exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / remainder.c
blob37a707b169daf3e53aab77eb9d4a75cc8ff095e4
1 /* Remainder.
2 Copyright (C) 2012-2024 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation, either version 3 of the
7 License, or (at your option) any later version.
9 This file is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 #if ! (defined USE_LONG_DOUBLE || defined USE_FLOAT)
18 # include <config.h>
19 #endif
21 /* Specification. */
22 #include <math.h>
24 #ifdef USE_LONG_DOUBLE
25 # define REMAINDER remainderl
26 # define DOUBLE long double
27 # define L_(literal) literal##L
28 # define FABS fabsl
29 # define FMOD fmodl
30 # define ISNAN isnanl
31 #elif ! defined USE_FLOAT
32 # define REMAINDER remainder
33 # define DOUBLE double
34 # define L_(literal) literal
35 # define FABS fabs
36 # define FMOD fmod
37 # define ISNAN isnand
38 #else /* defined USE_FLOAT */
39 # define REMAINDER remainderf
40 # define DOUBLE float
41 # define L_(literal) literal##f
42 # define FABS fabsf
43 # define FMOD fmodf
44 # define ISNAN isnanf
45 #endif
47 #undef NAN
48 #if defined _MSC_VER
49 static DOUBLE zero;
50 # define NAN (zero / zero)
51 #else
52 # define NAN (L_(0.0) / L_(0.0))
53 #endif
55 DOUBLE
56 REMAINDER (DOUBLE x, DOUBLE y)
58 if (isfinite (x) && isfinite (y) && y != L_(0.0))
60 if (x == L_(0.0))
61 /* Return x, regardless of the sign of y. */
62 return x;
65 int negate = ((!signbit (x)) ^ (!signbit (y)));
66 DOUBLE r;
68 /* Take the absolute value of x and y. */
69 x = FABS (x);
70 y = FABS (y);
72 /* Trivial case that requires no computation. */
73 if (x <= L_(0.5) * y)
74 return (negate ? - x : x);
76 /* With a fixed y, the function x -> remainder(x,y) has a period 2*y.
77 Therefore we can reduce the argument x modulo 2*y. And it's no
78 problem if 2*y overflows, since fmod(x,Inf) = x. */
79 x = FMOD (x, L_(2.0) * y);
81 /* Consider the 3 cases:
82 0 <= x <= 0.5 * y
83 0.5 * y < x < 1.5 * y
84 1.5 * y <= x <= 2.0 * y */
85 if (x <= L_(0.5) * y)
86 r = x;
87 else
89 r = x - y;
90 if (r > L_(0.5) * y)
91 r = x - L_(2.0) * y;
93 return (negate ? - r : r);
96 else
98 if (ISNAN (x) || ISNAN (y))
99 return x + y; /* NaN */
100 else if (isinf (y))
101 return x;
102 else
103 /* x infinite or y zero */
104 return NAN;