/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ /* * hypotl() function for DJGPP. * * hypotl() computes sqrt(x^2 + y^2). The problem with the obvious * naive implementation is that it might fail for very large or * very small arguments. For instance, for large x or y the result * might overflow even if the value of the function should not, * because squaring a large number might trigger an overflow. For * very small numbers, their square might underflow and will be * silently replaced by zero; this won't cause an exception, but might * have an adverse effect on the accuracy of the result. * * This implementation tries to avoid the above pitfals, without * inflicting too much of a performance hit. * */ #include #include #include /* Approximate square roots of LDBL_MAX and LDBL_MIN. Numbers between these two shouldn't neither overflow nor underflow when squared. */ #define __SQRT_LDBL_MAX 1.0e+2466 #define __SQRT_LDBL_MIN 1.6e-2466 long double hypotl(long double x, long double y) { long double abig = x < 0 ? -x : x, asmall = y < 0 ? -y : y; long double ratio; /* Make abig = max(|x|, |y|), asmall = min(|x|, |y|). */ if (abig < asmall) { long double temp = abig; abig = asmall; asmall = temp; } /* Trivial case. */ if (asmall == 0.L) return abig; /* Scale the numbers as much as possible by using its ratio. For example, if both ABIG and ASMALL are VERY small, then X^2 + Y^2 might be VERY inaccurate due to loss of significant digits. Dividing ASMALL by ABIG scales them to a certain degree, so that accuracy is better. */ if ((ratio = asmall / abig) > __SQRT_LDBL_MIN) return abig * sqrt(1.0L + ratio*ratio); else { /* Slower but safer algorithm due to Moler and Morrison. Never produces any intermediate result greater than roughly the larger of X and Y. Should converge to machine-precision accuracy in 3 iterations. */ long double r = ratio*ratio, t, s, p = abig, q = asmall; do { t = 4.0L + r; if (t == 4.0L) break; s = r / t; p += 2.0L * s * p; q *= s; r = (q / p) * (q / p); } while (1); return p; } } #ifdef TEST #include int main(void) { printf("hypotl(3, 4) =\t\t\t %25.17Le\n", hypotl(3., 4.)); printf("hypotl(3*10^150, 4*10^150) =\t %30.21Lg\n", hypotl(3.e+150L, 4.e+150L)); printf("hypotl(3*10^306, 4*10^306) =\t %30.21Lg\n", hypotl(3.e+306L, 4.e+306L)); printf("hypotl(3*10^-320, 4*10^-320) =\t %30.21Lg\n", hypotl(3.e-320L, 4.e-320L)); printf("hypotl(0.7*DBL_MAX, 0.7*DBL_MAX) =%30.21Lg\n", hypotl(0.7L*DBL_MAX, 0.7L*DBL_MAX)); printf("hypotl(DBL_MAX, 1.0) =\t\t %30.21Lg\n", hypotl(DBL_MAX, 1.0L)); printf("hypotl(1.0, DBL_MAX) =\t\t %30.21Lg\n", hypotl(1.0L, DBL_MAX)); printf("hypotl(0.0, DBL_MAX) =\t\t %30.21Lg\n", hypotl(0.0L, DBL_MAX)); printf("hypotl(3*10^2463, 4*10^2463) =\t %30.21Lg\n", hypotl(3.e+2463L, 4.e+2463L)); printf("hypotl(3*10^2467, 4*10^2467) =\t %30.21Lg\n", hypotl(3.e+2467L, 4.e+2467L)); printf("hypotl(3*10^4930, 4*10^4930) =\t %30.21Lg\n", hypotl(3.e+4930L, 4.e+4930L)); printf("hypotl(3*10^-4930, 4*10^-4930) =\t %30.21Lg\n", hypotl(3.e-4930L, 4.e-4930L)); printf("hypotl(0.7*LDBL_MAX, 0.7*LDBL_MAX) =%30.21Lg\n", hypotl(0.7L*LDBL_MAX, 0.7L*LDBL_MAX)); printf("hypotl(LDBL_MAX, 1.0) =\t\t %30.21Lg\n", hypotl(LDBL_MAX, 1.0L)); printf("hypotl(1.0, LDBL_MAX) =\t\t %30.21Lg\n", hypotl(1.0L, LDBL_MAX)); printf("hypotl(0.0, LDBL_MAX) =\t\t %30.21Lg\n", hypotl(0.0L, LDBL_MAX)); return 0; } #endif