1 /* Floating-point remainder function.
2 Copyright (C) 2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <libm-alias-finite.h>
20 #include <libm-alias-float.h>
21 #include <math-svid-compat.h>
23 #include "math_config.h"
25 /* With x = mx * 2^ex and y = my * 2^ey (mx, my, ex, ey being integers), the
26 simplest implementation is:
28 mx * 2^ex == 2 * mx * 2^(ex - 1)
39 With the mathematical equivalence of:
41 r == x % y == (x % (N * y)) % y
43 And with mx/my being mantissa of a single floating point number (which uses
44 less bits than the storage type), on each step the argument reduction can
45 be improved by 8 (which is the size of uint32_t minus MANTISSA_WIDTH plus
46 the implicit one bit):
48 mx * 2^ex == 2^8 * mx * 2^(ex - 8)
60 - If x or y is a NaN, a NaN is returned.
61 - If x is an infinity, or y is zero, a NaN is returned and EDOM is set.
62 - If x is +0/-0, and y is not zero, +0/-0 is returned. */
65 __fmodf (float x
, float y
)
67 uint32_t hx
= asuint (x
);
68 uint32_t hy
= asuint (y
);
70 uint32_t sx
= hx
& SIGN_MASK
;
71 /* Get |x| and |y|. */
75 if (__glibc_likely (hx
< hy
))
77 /* If y is a NaN, return a NaN. */
78 if (__glibc_unlikely (hy
> EXPONENT_MASK
))
83 int ex
= hx
>> MANTISSA_WIDTH
;
84 int ey
= hy
>> MANTISSA_WIDTH
;
85 int exp_diff
= ex
- ey
;
87 /* Common case where exponents are close: |x/y| < 2^9, x not inf/NaN
88 and |x%y| not denormal. */
89 if (__glibc_likely (ey
< (EXPONENT_MASK
>> MANTISSA_WIDTH
) - EXPONENT_WIDTH
90 && ey
> MANTISSA_WIDTH
91 && exp_diff
<= EXPONENT_WIDTH
))
93 uint32_t mx
= (hx
<< EXPONENT_WIDTH
) | SIGN_MASK
;
94 uint32_t my
= (hy
<< EXPONENT_WIDTH
) | SIGN_MASK
;
96 mx
%= (my
>> exp_diff
);
98 if (__glibc_unlikely (mx
== 0))
100 int shift
= __builtin_clz (mx
);
103 mx
= sx
| (mx
>> EXPONENT_WIDTH
);
104 return asfloat (mx
+ ((uint32_t)ex
<< MANTISSA_WIDTH
));
107 if (__glibc_unlikely (hy
== 0 || hx
>= EXPONENT_MASK
))
109 /* If x is a NaN, return a NaN. */
110 if (hx
> EXPONENT_MASK
)
113 /* If x is an infinity or y is zero, return a NaN and set EDOM. */
114 return __math_edomf ((x
* y
) / (x
* y
));
117 /* Special case, both x and y are denormal. */
118 if (__glibc_unlikely (ex
== 0))
119 return asfloat (sx
| hx
% hy
);
121 /* Extract normalized mantissas - hx is not denormal and hy != 0. */
122 uint32_t mx
= get_mantissa (hx
) | (MANTISSA_MASK
+ 1);
123 uint32_t my
= get_mantissa (hy
) | (MANTISSA_MASK
+ 1);
124 int lead_zeros_my
= EXPONENT_WIDTH
;
127 /* Special case for denormal y. */
128 if (__glibc_unlikely (ey
< 0))
133 lead_zeros_my
= __builtin_clz (my
);
136 int tail_zeros_my
= __builtin_ctz (my
);
137 int sides_zeroes
= lead_zeros_my
+ tail_zeros_my
;
139 int right_shift
= exp_diff
< tail_zeros_my
? exp_diff
: tail_zeros_my
;
141 exp_diff
-= right_shift
;
144 int left_shift
= exp_diff
< EXPONENT_WIDTH
? exp_diff
: EXPONENT_WIDTH
;
146 exp_diff
-= left_shift
;
150 if (__glibc_unlikely (mx
== 0))
154 return make_float (mx
, ey
, sx
);
156 /* Multiplication with the inverse is faster than repeated modulo. */
157 uint32_t inv_hy
= UINT32_MAX
/ my
;
158 while (exp_diff
> sides_zeroes
) {
159 exp_diff
-= sides_zeroes
;
160 uint32_t hd
= (mx
* inv_hy
) >> (BIT_WIDTH
- sides_zeroes
);
163 while (__glibc_unlikely (mx
> my
))
166 uint32_t hd
= (mx
* inv_hy
) >> (BIT_WIDTH
- exp_diff
);
169 while (__glibc_unlikely (mx
> my
))
172 return make_float (mx
, ey
, sx
);
174 strong_alias (__fmodf
, __ieee754_fmodf
)
176 versioned_symbol (libm
, __fmodf
, fmodf
, GLIBC_2_38
);
177 libm_alias_float_other (__fmod
, fmod
)
179 libm_alias_float (__fmod
, fmod
)
181 libm_alias_finite (__ieee754_fmodf
, __fmodf
)