OLD | NEW |
1 #include <math.h> | 1 #include <math.h> |
2 #include <stdint.h> | 2 #include <stdint.h> |
3 #include <float.h> | 3 #include <float.h> |
4 | 4 |
5 #if FLT_EVAL_METHOD > 1U && LDBL_MANT_DIG == 64 | 5 #if FLT_EVAL_METHOD > 1U && LDBL_MANT_DIG == 64 |
6 #define SPLIT (0x1p32 + 1) | 6 #define SPLIT (0x1p32 + 1) |
7 #else | 7 #else |
8 #define SPLIT (0x1p27 + 1) | 8 #define SPLIT (0x1p27 + 1) |
9 #endif | 9 #endif |
10 | 10 |
11 static void sq(double_t *hi, double_t *lo, double x) | 11 static void sq(double_t* hi, double_t* lo, double x) { |
12 { | 12 double_t xh, xl, xc; |
13 » double_t xh, xl, xc; | |
14 | 13 |
15 » xc = (double_t)x*SPLIT; | 14 xc = (double_t)x * SPLIT; |
16 » xh = x - xc + xc; | 15 xh = x - xc + xc; |
17 » xl = x - xh; | 16 xl = x - xh; |
18 » *hi = (double_t)x*x; | 17 *hi = (double_t)x * x; |
19 » *lo = xh*xh - *hi + 2*xh*xl + xl*xl; | 18 *lo = xh * xh - *hi + 2 * xh * xl + xl * xl; |
20 } | 19 } |
21 | 20 |
22 double hypot(double x, double y) | 21 double hypot(double x, double y) { |
23 { | 22 union { |
24 » union {double f; uint64_t i;} ux = {x}, uy = {y}, ut; | 23 double f; |
25 » int ex, ey; | 24 uint64_t i; |
26 » double_t hx, lx, hy, ly, z; | 25 } ux = {x}, uy = {y}, ut; |
| 26 int ex, ey; |
| 27 double_t hx, lx, hy, ly, z; |
27 | 28 |
28 » /* arrange |x| >= |y| */ | 29 /* arrange |x| >= |y| */ |
29 » ux.i &= -1ULL>>1; | 30 ux.i &= -1ULL >> 1; |
30 » uy.i &= -1ULL>>1; | 31 uy.i &= -1ULL >> 1; |
31 » if (ux.i < uy.i) { | 32 if (ux.i < uy.i) { |
32 » » ut = ux; | 33 ut = ux; |
33 » » ux = uy; | 34 ux = uy; |
34 » » uy = ut; | 35 uy = ut; |
35 » } | 36 } |
36 | 37 |
37 » /* special cases */ | 38 /* special cases */ |
38 » ex = ux.i>>52; | 39 ex = ux.i >> 52; |
39 » ey = uy.i>>52; | 40 ey = uy.i >> 52; |
40 » x = ux.f; | 41 x = ux.f; |
41 » y = uy.f; | 42 y = uy.f; |
42 » /* note: hypot(inf,nan) == inf */ | 43 /* note: hypot(inf,nan) == inf */ |
43 » if (ey == 0x7ff) | 44 if (ey == 0x7ff) |
44 » » return y; | 45 return y; |
45 » if (ex == 0x7ff || uy.i == 0) | 46 if (ex == 0x7ff || uy.i == 0) |
46 » » return x; | 47 return x; |
47 » /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ | 48 /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ |
48 » /* 64 difference is enough for ld80 double_t */ | 49 /* 64 difference is enough for ld80 double_t */ |
49 » if (ex - ey > 64) | 50 if (ex - ey > 64) |
50 » » return x + y; | 51 return x + y; |
51 | 52 |
52 » /* precise sqrt argument in nearest rounding mode without overflow */ | 53 /* precise sqrt argument in nearest rounding mode without overflow */ |
53 » /* xh*xh must not overflow and xl*xl must not underflow in sq */ | 54 /* xh*xh must not overflow and xl*xl must not underflow in sq */ |
54 » z = 1; | 55 z = 1; |
55 » if (ex > 0x3ff+510) { | 56 if (ex > 0x3ff + 510) { |
56 » » z = 0x1p700; | 57 z = 0x1p700; |
57 » » x *= 0x1p-700; | 58 x *= 0x1p-700; |
58 » » y *= 0x1p-700; | 59 y *= 0x1p-700; |
59 » } else if (ey < 0x3ff-450) { | 60 } else if (ey < 0x3ff - 450) { |
60 » » z = 0x1p-700; | 61 z = 0x1p-700; |
61 » » x *= 0x1p700; | 62 x *= 0x1p700; |
62 » » y *= 0x1p700; | 63 y *= 0x1p700; |
63 » } | 64 } |
64 » sq(&hx, &lx, x); | 65 sq(&hx, &lx, x); |
65 » sq(&hy, &ly, y); | 66 sq(&hy, &ly, y); |
66 » return z*sqrt(ly+lx+hy+hx); | 67 return z * sqrt(ly + lx + hy + hx); |
67 } | 68 } |
OLD | NEW |