xref: /reactos/sdk/lib/crt/math/sqrt.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * COPYRIGHT:       BSD - See COPYING.ARM in the top level directory
3*c2c66affSColin Finck  * PROJECT:         ReactOS CRT library
4*c2c66affSColin Finck  * PURPOSE:         Portable implementation of sqrt
5*c2c66affSColin Finck  * PROGRAMMER:      Timo Kreuzer (timo.kreuzer@reactos.org)
6*c2c66affSColin Finck  */
7*c2c66affSColin Finck 
8*c2c66affSColin Finck #include <math.h>
9*c2c66affSColin Finck #include <assert.h>
10*c2c66affSColin Finck 
11*c2c66affSColin Finck double
12*c2c66affSColin Finck __cdecl
sqrt(double x)13*c2c66affSColin Finck sqrt(
14*c2c66affSColin Finck     double x)
15*c2c66affSColin Finck {
16*c2c66affSColin Finck     const double threehalfs = 1.5;
17*c2c66affSColin Finck     const double x2 = x * 0.5;
18*c2c66affSColin Finck     long long bits;
19*c2c66affSColin Finck     double inv, y;
20*c2c66affSColin Finck 
21*c2c66affSColin Finck     /* Handle special cases */
22*c2c66affSColin Finck     if (x == 0.0)
23*c2c66affSColin Finck     {
24*c2c66affSColin Finck         return x;
25*c2c66affSColin Finck     }
26*c2c66affSColin Finck     else if (x < 0.0)
27*c2c66affSColin Finck     {
28*c2c66affSColin Finck         return -NAN;
29*c2c66affSColin Finck     }
30*c2c66affSColin Finck 
31*c2c66affSColin Finck     /* Convert into a 64  bit integer */
32*c2c66affSColin Finck     bits = *(long long *)&x;
33*c2c66affSColin Finck 
34*c2c66affSColin Finck     /* Check for !finite(x) */
35*c2c66affSColin Finck     if ((bits & 0x7ff7ffffffffffffLL) == 0x7ff0000000000000LL)
36*c2c66affSColin Finck     {
37*c2c66affSColin Finck         return x;
38*c2c66affSColin Finck     }
39*c2c66affSColin Finck 
40*c2c66affSColin Finck     /* Step 1: quick approximation of 1/sqrt(x) with bit magic
41*c2c66affSColin Finck        See http://en.wikipedia.org/wiki/Fast_inverse_square_root */
42*c2c66affSColin Finck     bits = 0x5fe6eb50c7b537a9ll - (bits >> 1);
43*c2c66affSColin Finck     inv = *(double*)&bits;
44*c2c66affSColin Finck 
45*c2c66affSColin Finck     /* Step 2: 3 Newton iterations to approximate 1 / sqrt(x) */
46*c2c66affSColin Finck     inv = inv * (threehalfs - (x2 * inv * inv));
47*c2c66affSColin Finck     inv = inv * (threehalfs - (x2 * inv * inv));
48*c2c66affSColin Finck     inv = inv * (threehalfs - (x2 * inv * inv));
49*c2c66affSColin Finck 
50*c2c66affSColin Finck     /* Step 3: 1 additional Heron iteration has shown to maximize the precision.
51*c2c66affSColin Finck        Normally the formula would be: y = (y + (x / y)) * 0.5;
52*c2c66affSColin Finck        Instead we use the inverse sqrt directly */
53*c2c66affSColin Finck     y = ((1 / inv) + (x * inv)) * 0.5;
54*c2c66affSColin Finck 
55*c2c66affSColin Finck     //assert(y == (double)((y + (x / y)) * 0.5));
56*c2c66affSColin Finck     /* GCC BUG: While the C-Standard requires that an explicit cast to
57*c2c66affSColin Finck        double converts the result of a computation to the appropriate
58*c2c66affSColin Finck        64 bit value, our GCC ignores this and uses an 80 bit FPU register
59*c2c66affSColin Finck        in an intermediate value, so we need to make sure it is stored in
60*c2c66affSColin Finck        a memory location before comparison */
61*c2c66affSColin Finck //#if DBG
62*c2c66affSColin Finck //    {
63*c2c66affSColin Finck //        volatile double y1 = y, y2;
64*c2c66affSColin Finck //        y2 = (y + (x / y)) * 0.5;
65*c2c66affSColin Finck //        assert(y1 == y2);
66*c2c66affSColin Finck //    }
67*c2c66affSColin Finck //#endif
68*c2c66affSColin Finck 
69*c2c66affSColin Finck     return y;
70*c2c66affSColin Finck }
71