• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdint.h>
2 #include <math.h>
3 #include "libm.h"
4 #include "sqrt_data.h"
5 
6 #define FENV_SUPPORT 1
7 
8 /* returns a*b*2^-32 - e, with error 0 <= e < 1.  */
mul32(uint32_t a,uint32_t b)9 static inline uint32_t mul32(uint32_t a, uint32_t b)
10 {
11 	return (uint64_t)a*b >> 32;
12 }
13 
14 /* returns a*b*2^-64 - e, with error 0 <= e < 3.  */
mul64(uint64_t a,uint64_t b)15 static inline uint64_t mul64(uint64_t a, uint64_t b)
16 {
17 	uint64_t ahi = a>>32;
18 	uint64_t alo = a&0xffffffff;
19 	uint64_t bhi = b>>32;
20 	uint64_t blo = b&0xffffffff;
21 	return ahi*bhi + (ahi*blo >> 32) + (alo*bhi >> 32);
22 }
23 
sqrt(double x)24 double sqrt(double x)
25 {
26 	uint64_t ix, top, m;
27 
28 	/* special case handling.  */
29 	ix = asuint64(x);
30 	top = ix >> 52;
31 	if (predict_false(top - 0x001 >= 0x7ff - 0x001)) {
32 		/* x < 0x1p-1022 or inf or nan.  */
33 		if (ix * 2 == 0)
34 			return x;
35 		if (ix == 0x7ff0000000000000)
36 			return x;
37 		if (ix > 0x7ff0000000000000)
38 			return __math_invalid(x);
39 		/* x is subnormal, normalize it.  */
40 		ix = asuint64(x * 0x1p52);
41 		top = ix >> 52;
42 		top -= 52;
43 	}
44 
45 	/* argument reduction:
46 	   x = 4^e m; with integer e, and m in [1, 4)
47 	   m: fixed point representation [2.62]
48 	   2^e is the exponent part of the result.  */
49 	int even = top & 1;
50 	m = (ix << 11) | 0x8000000000000000;
51 	if (even) m >>= 1;
52 	top = (top + 0x3ff) >> 1;
53 
54 	/* approximate r ~ 1/sqrt(m) and s ~ sqrt(m) when m in [1,4)
55 
56 	   initial estimate:
57 	   7bit table lookup (1bit exponent and 6bit significand).
58 
59 	   iterative approximation:
60 	   using 2 goldschmidt iterations with 32bit int arithmetics
61 	   and a final iteration with 64bit int arithmetics.
62 
63 	   details:
64 
65 	   the relative error (e = r0 sqrt(m)-1) of a linear estimate
66 	   (r0 = a m + b) is |e| < 0.085955 ~ 0x1.6p-4 at best,
67 	   a table lookup is faster and needs one less iteration
68 	   6 bit lookup table (128b) gives |e| < 0x1.f9p-8
69 	   7 bit lookup table (256b) gives |e| < 0x1.fdp-9
70 	   for single and double prec 6bit is enough but for quad
71 	   prec 7bit is needed (or modified iterations). to avoid
72 	   one more iteration >=13bit table would be needed (16k).
73 
74 	   a newton-raphson iteration for r is
75 	     w = r*r
76 	     u = 3 - m*w
77 	     r = r*u/2
78 	   can use a goldschmidt iteration for s at the end or
79 	     s = m*r
80 
81 	   first goldschmidt iteration is
82 	     s = m*r
83 	     u = 3 - s*r
84 	     r = r*u/2
85 	     s = s*u/2
86 	   next goldschmidt iteration is
87 	     u = 3 - s*r
88 	     r = r*u/2
89 	     s = s*u/2
90 	   and at the end r is not computed only s.
91 
92 	   they use the same amount of operations and converge at the
93 	   same quadratic rate, i.e. if
94 	     r1 sqrt(m) - 1 = e, then
95 	     r2 sqrt(m) - 1 = -3/2 e^2 - 1/2 e^3
96 	   the advantage of goldschmidt is that the mul for s and r
97 	   are independent (computed in parallel), however it is not
98 	   "self synchronizing": it only uses the input m in the
99 	   first iteration so rounding errors accumulate. at the end
100 	   or when switching to larger precision arithmetics rounding
101 	   errors dominate so the first iteration should be used.
102 
103 	   the fixed point representations are
104 	     m: 2.30 r: 0.32, s: 2.30, d: 2.30, u: 2.30, three: 2.30
105 	   and after switching to 64 bit
106 	     m: 2.62 r: 0.64, s: 2.62, d: 2.62, u: 2.62, three: 2.62  */
107 
108 	static const uint64_t three = 0xc0000000;
109 	uint64_t r, s, d, u, i;
110 
111 	i = (ix >> 46) % 128;
112 	r = (uint32_t)__rsqrt_tab[i] << 16;
113 	/* |r sqrt(m) - 1| < 0x1.fdp-9 */
114 	s = mul32(m>>32, r);
115 	/* |s/sqrt(m) - 1| < 0x1.fdp-9 */
116 	d = mul32(s, r);
117 	u = three - d;
118 	r = mul32(r, u) << 1;
119 	/* |r sqrt(m) - 1| < 0x1.7bp-16 */
120 	s = mul32(s, u) << 1;
121 	/* |s/sqrt(m) - 1| < 0x1.7bp-16 */
122 	d = mul32(s, r);
123 	u = three - d;
124 	r = mul32(r, u) << 1;
125 	/* |r sqrt(m) - 1| < 0x1.3704p-29 (measured worst-case) */
126 	r = r << 32;
127 	s = mul64(m, r);
128 	d = mul64(s, r);
129 	u = (three<<32) - d;
130 	s = mul64(s, u);  /* repr: 3.61 */
131 	/* -0x1p-57 < s - sqrt(m) < 0x1.8001p-61 */
132 	s = (s - 2) >> 9; /* repr: 12.52 */
133 	/* -0x1.09p-52 < s - sqrt(m) < -0x1.fffcp-63 */
134 
135 	/* s < sqrt(m) < s + 0x1.09p-52,
136 	   compute nearest rounded result:
137 	   the nearest result to 52 bits is either s or s+0x1p-52,
138 	   we can decide by comparing (2^52 s + 0.5)^2 to 2^104 m.  */
139 	uint64_t d0, d1, d2;
140 	double y, t;
141 	d0 = (m << 42) - s*s;
142 	d1 = s - d0;
143 	d2 = d1 + s + 1;
144 	s += d1 >> 63;
145 	s &= 0x000fffffffffffff;
146 	s |= top << 52;
147 	y = asdouble(s);
148 	if (FENV_SUPPORT) {
149 		/* handle rounding modes and inexact exception:
150 		   only (s+1)^2 == 2^42 m case is exact otherwise
151 		   add a tiny value to cause the fenv effects.  */
152 		uint64_t tiny = predict_false(d2==0) ? 0 : 0x0010000000000000;
153 		tiny |= (d1^d2) & 0x8000000000000000;
154 		t = asdouble(tiny);
155 		y = eval_as_double(y + t);
156 	}
157 	return y;
158 }
159