1
0

hypot.c 1.3 KB

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