Back to index

glibc  2.9
e_sqrtf.c
Go to the documentation of this file.
00001 /* Single-precision floating point square root.
00002    Copyright (C) 1997, 2003, 2004, 2008 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <math.h>
00021 #include <math_private.h>
00022 #include <fenv_libc.h>
00023 #include <inttypes.h>
00024 
00025 #include <sysdep.h>
00026 #include <ldsodefs.h>
00027 
00028 static const float almost_half = 0.50000006;     /* 0.5 + 2^-24 */
00029 static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
00030 static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
00031 static const float two48 = 281474976710656.0;
00032 static const float twom24 = 5.9604644775390625e-8;
00033 extern const float __t_sqrt[1024];
00034 
00035 /* The method is based on a description in
00036    Computation of elementary functions on the IBM RISC System/6000 processor,
00037    P. W. Markstein, IBM J. Res. Develop, 34(1) 1990.
00038    Basically, it consists of two interleaved Newton-Rhapson approximations,
00039    one to find the actual square root, and one to find its reciprocal
00040    without the expense of a division operation.   The tricky bit here
00041    is the use of the POWER/PowerPC multiply-add operation to get the
00042    required accuracy with high speed.
00043 
00044    The argument reduction works by a combination of table lookup to
00045    obtain the initial guesses, and some careful modification of the
00046    generated guesses (which mostly runs on the integer unit, while the
00047    Newton-Rhapson is running on the FPU).  */
00048 
00049 #ifdef __STDC__
00050 float
00051 __slow_ieee754_sqrtf (float x)
00052 #else
00053 float
00054 __slow_ieee754_sqrtf (x)
00055      float x;
00056 #endif
00057 {
00058   const float inf = a_inf.value;
00059 
00060   if (x > 0)
00061     {
00062       if (x != inf)
00063        {
00064          /* Variables named starting with 's' exist in the
00065             argument-reduced space, so that 2 > sx >= 0.5,
00066             1.41... > sg >= 0.70.., 0.70.. >= sy > 0.35... .
00067             Variables named ending with 'i' are integer versions of
00068             floating-point values.  */
00069          float sx;          /* The value of which we're trying to find the square
00070                                root.  */
00071          float sg, g;              /* Guess of the square root of x.  */
00072          float sd, d;              /* Difference between the square of the guess and x.  */
00073          float sy;          /* Estimate of 1/2g (overestimated by 1ulp).  */
00074          float sy2;         /* 2*sy */
00075          float e;           /* Difference between y*g and 1/2 (note that e==se).  */
00076          float shx;         /* == sx * fsg */
00077          float fsg;         /* sg*fsg == g.  */
00078          fenv_t fe;         /* Saved floating-point environment (stores rounding
00079                                mode and whether the inexact exception is
00080                                enabled).  */
00081          uint32_t xi, sxi, fsgi;
00082          const float *t_sqrt;
00083 
00084          GET_FLOAT_WORD (xi, x);
00085          fe = fegetenv_register ();
00086          relax_fenv_state ();
00087          sxi = (xi & 0x3fffffff) | 0x3f000000;
00088          SET_FLOAT_WORD (sx, sxi);
00089          t_sqrt = __t_sqrt + (xi >> (23 - 8 - 1) & 0x3fe);
00090          sg = t_sqrt[0];
00091          sy = t_sqrt[1];
00092 
00093          /* Here we have three Newton-Rhapson iterations each of a
00094             division and a square root and the remainder of the
00095             argument reduction, all interleaved.   */
00096          sd = -(sg * sg - sx);
00097          fsgi = (xi + 0x40000000) >> 1 & 0x7f800000;
00098          sy2 = sy + sy;
00099          sg = sy * sd + sg; /* 16-bit approximation to sqrt(sx). */
00100          e = -(sy * sg - almost_half);
00101          SET_FLOAT_WORD (fsg, fsgi);
00102          sd = -(sg * sg - sx);
00103          sy = sy + e * sy2;
00104          if ((xi & 0x7f800000) == 0)
00105            goto denorm;
00106          shx = sx * fsg;
00107          sg = sg + sy * sd; /* 32-bit approximation to sqrt(sx),
00108                                but perhaps rounded incorrectly.  */
00109          sy2 = sy + sy;
00110          g = sg * fsg;
00111          e = -(sy * sg - almost_half);
00112          d = -(g * sg - shx);
00113          sy = sy + e * sy2;
00114          fesetenv_register (fe);
00115          return g + sy * d;
00116        denorm:
00117          /* For denormalised numbers, we normalise, calculate the
00118             square root, and return an adjusted result.  */
00119          fesetenv_register (fe);
00120          return __slow_ieee754_sqrtf (x * two48) * twom24;
00121        }
00122     }
00123   else if (x < 0)
00124     {
00125       /* For some reason, some PowerPC32 processors don't implement
00126          FE_INVALID_SQRT.  */
00127 #ifdef FE_INVALID_SQRT
00128       feraiseexcept (FE_INVALID_SQRT);
00129 
00130       fenv_union_t u = { .fenv = fegetenv_register () };
00131       if ((u.l[1] & FE_INVALID) == 0)
00132 #endif
00133        feraiseexcept (FE_INVALID);
00134       x = a_nan.value;
00135     }
00136   return f_washf (x);
00137 }
00138 
00139 
00140 #ifdef __STDC__
00141 float
00142 __ieee754_sqrtf (float x)
00143 #else
00144 float
00145 __ieee754_sqrtf (x)
00146      float x;
00147 #endif
00148 {
00149   double z;
00150 
00151   /* If the CPU is 64-bit we can use the optional FP instructions.  */
00152   if (__CPU_HAS_FSQRT)
00153     {
00154       /* Volatile is required to prevent the compiler from moving the
00155          fsqrt instruction above the branch.  */
00156       __asm __volatile ("   fsqrts %0,%1\n"
00157                             :"=f" (z):"f" (x));
00158     }
00159   else
00160     z = __slow_ieee754_sqrtf (x);
00161 
00162   return z;
00163 }