/************************************************************************ * * * N O T I C E * * * * Copyright Abandoned, 1987, Fred Fish * * * * This previously copyrighted work has been placed into the * * public domain by the author (Fred Fish) and may be freely used * * for any purpose, private or commercial. I would appreciate * * it, as a courtesy, if this notice is left in all copies and * * derivative works. Thank you, and enjoy... * * * * The author makes no warranty of any kind with respect to this * * product and explicitly disclaims any implied warranties of * * merchantability or fitness for any particular purpose. * * * ************************************************************************ */ /* * FUNCTION * * sqrt double precision square root * * KEY WORDS * * sqrt * machine independent routines * math libraries * * DESCRIPTION * * Returns double precision square root of double precision * floating point argument. * * USAGE * * double sqrt (x) * double x; * * REFERENCES * * Fortran IV-PLUS user's guide, Digital Equipment Corp. pp B-7. * * Computer Approximations, J.F. Hart et al, John Wiley & Sons, * 1968, pp. 89-96. * * RESTRICTIONS * * The relative error is 10**(-30.1) after three applications * of Heron's iteration for the square root. * * However, this assumes exact arithmetic in the iterations * and initial approximation. Additional errors may occur * due to truncation, rounding, or machine precision limits. * * PROGRAMMER * * Fred Fish * * INTERNALS * * Computes square root by: * * (1) Range reduction of argument to [0.5,1.0] * by application of identity: * * sqrt(x) = 2**(k/2) * sqrt(x * 2**(-k)) * * k is the exponent when x is written as * a mantissa times a power of 2 (m * 2**k). * It is assumed that the mantissa is * already normalized (0.5 =< m < 1.0). * * (2) An approximation to sqrt(m) is obtained * from: * * u = sqrt(m) = (P0 + P1*m) / (Q0 + Q1*m) * * P0 = 0.594604482 * P1 = 2.54164041 * Q0 = 2.13725758 * Q1 = 1.0 * * (coefficients from HART table #350 pg 193) * * (3) Three applications of Heron's iteration are * performed using: * * y[n+1] = 0.5 * (y[n] + (m/y[n])) * * where y[0] = u = approx sqrt(m) * * (4) If the value of k was odd then y is either * multiplied by the square root of two or * divided by the square root of two for k positive * or negative respectively. This rescales y * by multiplying by 2**frac(k/2). * * (5) Finally, y is rescaled by int(k/2) which * is equivalent to multiplication by 2**int(k/2). * * The result of steps 4 and 5 is that the value * of y between 0.5 and 1.0 has been rescaled by * 2**(k/2) which removes the original rescaling * done prior to finding the mantissa square root. * * NOTES * * The Convergent Technologies compiler optimizes division * by powers of two to "arithmetic shift right" instructions. * This is ok for positive integers but gives different * results than other C compilers for negative integers. * For example, (-1)/2 is -1 on the CT box, 0 on every other * machine I tried. * */ /* * MODIFICATIONS * * This routine modified to use polynomial, instead of rational, * approximation with coefficients * * P0 0.22906994529e+00 * P1 0.13006690496e+01 * P2 -0.90932104982e+00 * P3 0.50104207633e+00 * P4 -0.12146838249e+00 * * as given by Hart (op. cit.) in SQRT 0132. This approximation * gives around 5 digits correct. Two applications of Heron's * approximation will give more then practically achievable * 13-15 decimal digits. Multiplications by powers of 2 are * replaced by explicit calls to ldexp. * * Michal Jaegermann, 24 October 1990 */ #include #include #include "pml.h" #ifdef OLD #define P0 0.594604482 /* Approximation coeff */ #define P1 2.54164041 /* Approximation coeff */ #define Q0 2.13725758 /* Approximation coeff */ #define Q1 1.0 /* Approximation coeff */ #define ITERATIONS 3 /* Number of iterations */ #endif #define P0 0.22906994529e+00 /* Hart SQRT 0132 */ #define P1 0.13006690496e+01 #define P2 -0.90932104982e+00 #define P3 0.50104207633e+00 #define P4 -0.12146838249e+00 static char funcname[] = "sqrt"; double sqrt (x) double x; { #ifdef OLD auto int k; register int bugfix; register int kmod2; register int count; auto int exponent; #else #ifdef __MSHORT__ auto short k; #else auto int k; #endif #endif auto double m; auto double u; #ifdef OLD auto double y; #endif auto struct exception xcpt; extern double frexp (); extern double ldexp (); DBUG_ENTER ("sqrt"); DBUG_3 ("sqrtin", "arg %le", x); if (x == 0.0) { xcpt.retval = 0.0; } else if (x < 0.0) { xcpt.type = DOMAIN; xcpt.name = funcname; xcpt.arg1 = x; if (!matherr (&xcpt)) { fprintf (stderr, "%s: DOMAIN error\n", funcname); errno = EDOM; xcpt.retval = 0.0; } } else { m = frexp (x, &k); #ifdef OLD u = (P0 + (P1 * m)) / (Q0 + (Q1 * m)); for (count = 0, y = u; count < ITERATIONS; count++) { y = 0.5 * (y + (m / y)); } if ((kmod2 = (k % 2)) < 0) { y /= SQRT2; } else if (kmod2 > 0) { y *= SQRT2; } bugfix = 2; xcpt.retval = ldexp (y, k/bugfix); #else u = (((P4 * m + P3) * m + P2) * m + P1) * m + P0; u = ldexp((u + (m / u)), -1); /* Heron's iteration */ u += m / u; /* and a part of the second one */ if (k & 1) { u *= SQRT2; } /* * here we rely on the fact that -3/2 and (-3 >> 1) * do give different results */ xcpt.retval = ldexp (u, (k >> 1) - 1); #endif } DBUG_3 ("sqrtout", "result %le", xcpt.retval); DBUG_RETURN (xcpt.retval); }