| /** |
| * This file has no copyright assigned and is placed in the Public Domain. |
| * This file is part of the mingw-w64 runtime package. |
| * No warranty is given; refer to the file DISCLAIMER.PD within this package. |
| */ |
| #include <math.h> |
| #include <float.h> |
| #include <errno.h> |
| |
| /* |
| This implementation is based largely on Cephes library |
| function cabsl (cmplxl.c), which bears the following notice: |
| |
| Cephes Math Library Release 2.1: January, 1989 |
| Copyright 1984, 1987, 1989 by Stephen L. Moshier |
| Direct inquiries to 30 Frost Street, Cambridge, MA 02140 |
| */ |
| |
| /* |
| Modified for use in libmingwex.a |
| 02 Sept 2002 Danny Smith <dannysmith@users.sourceforege.net> |
| Calls to ldexpl replaced by logbl and calls to frexpl replaced |
| by scalbnl to avoid duplicated range checks. |
| */ |
| |
| #define PRECL 32 |
| |
| long double |
| hypotl (long double x, long double y) |
| { |
| int exx; |
| int eyy; |
| int scale; |
| long double xx =fabsl(x); |
| long double yy =fabsl(y); |
| if (!isfinite(xx) || !isfinite(yy)) |
| { |
| /* Annex F.9.4.3, hypot returns +infinity if |
| either component is an infinity, even when the |
| other component is NaN. */ |
| return (isinf(xx) || isinf(yy)) ? INFINITY : NAN; |
| } |
| |
| if (xx == 0.0L) |
| return yy; |
| if (yy == 0.0L) |
| return xx; |
| |
| /* Get exponents */ |
| exx = logbl (xx); |
| eyy = logbl (yy); |
| |
| /* Check if large differences in scale */ |
| scale = exx - eyy; |
| if ( scale > PRECL) |
| return xx; |
| if ( scale < -PRECL) |
| return yy; |
| |
| /* Exponent of approximate geometric mean (x 2) */ |
| scale = (exx + eyy) >> 1; |
| |
| /* Rescale: Geometric mean is now about 2 */ |
| x = scalbnl(xx, -scale); |
| y = scalbnl(yy, -scale); |
| |
| xx = sqrtl(x * x + y * y); |
| |
| /* Check for overflow and underflow */ |
| exx = logbl(xx); |
| exx += scale; |
| if (exx > LDBL_MAX_EXP) |
| { |
| errno = ERANGE; |
| return INFINITY; |
| } |
| if (exx < LDBL_MIN_EXP) |
| return 0.0L; |
| |
| /* Undo scaling */ |
| return (scalbnl (xx, scale)); |
| } |