]>
git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/ieee754/flt-32/e_fmodf.c
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>
21 #include "math_config.h"
23 /* With x = mx * 2^ex and y = my * 2^ey (mx, my, ex, ey being integers), the
24 simplest implementation is:
26 mx * 2^ex == 2 * mx * 2^(ex - 1)
37 With the mathematical equivalence of:
39 r == x % y == (x % (N * y)) % y
41 And with mx/my being mantissa of double floating point number (which uses
42 less bits than the storage type), on each step the argument reduction can
43 be improved by 8 (which is the size of uint32_t minus MANTISSA_WIDTH plus
46 mx * 2^ex == 2^8 * mx * 2^(ex - 8)
58 __ieee754_fmodf (float x
, float y
)
60 uint32_t hx
= asuint (x
);
61 uint32_t hy
= asuint (y
);
63 uint32_t sx
= hx
& SIGN_MASK
;
64 /* Get |x| and |y|. */
69 - If x or y is a Nan, NaN is returned.
70 - If x is an inifinity, a NaN is returned.
71 - If y is zero, Nan is returned.
72 - If x is +0/-0, and y is not zero, +0/-0 is returned. */
73 if (__glibc_unlikely (hy
== 0 || hx
>= EXPONENT_MASK
|| hy
> EXPONENT_MASK
))
74 return (x
* y
) / (x
* y
);
76 if (__glibc_unlikely (hx
<= hy
))
83 int ex
= hx
>> MANTISSA_WIDTH
;
84 int ey
= hy
>> MANTISSA_WIDTH
;
86 /* Common case where exponents are close: ey >= -103 and |x/y| < 2^8, */
87 if (__glibc_likely (ey
> MANTISSA_WIDTH
&& ex
- ey
<= EXPONENT_WIDTH
))
89 uint64_t mx
= (hx
& MANTISSA_MASK
) | (MANTISSA_MASK
+ 1);
90 uint64_t my
= (hy
& MANTISSA_MASK
) | (MANTISSA_MASK
+ 1);
92 uint32_t d
= (ex
== ey
) ? (mx
- my
) : (mx
<< (ex
- ey
)) % my
;
93 return make_float (d
, ey
- 1, sx
);
96 /* Special case, both x and y are subnormal. */
97 if (__glibc_unlikely (ex
== 0 && ey
== 0))
98 return asfloat (sx
| hx
% hy
);
100 /* Convert |x| and |y| to 'mx + 2^ex' and 'my + 2^ey'. Assume that hx is
101 not subnormal by conditions above. */
102 uint32_t mx
= get_mantissa (hx
) | (MANTISSA_MASK
+ 1);
105 uint32_t my
= get_mantissa (hy
) | (MANTISSA_MASK
+ 1);
106 int lead_zeros_my
= EXPONENT_WIDTH
;
107 if (__glibc_likely (ey
> 0))
112 lead_zeros_my
= __builtin_clz (my
);
115 int tail_zeros_my
= __builtin_ctz (my
);
116 int sides_zeroes
= lead_zeros_my
+ tail_zeros_my
;
117 int exp_diff
= ex
- ey
;
119 int right_shift
= exp_diff
< tail_zeros_my
? exp_diff
: tail_zeros_my
;
121 exp_diff
-= right_shift
;
124 int left_shift
= exp_diff
< EXPONENT_WIDTH
? exp_diff
: EXPONENT_WIDTH
;
126 exp_diff
-= left_shift
;
130 if (__glibc_unlikely (mx
== 0))
134 return make_float (mx
, ey
, sx
);
136 /* Assume modulo/divide operation is slow, so use multiplication with invert
138 uint32_t inv_hy
= UINT32_MAX
/ my
;
139 while (exp_diff
> sides_zeroes
) {
140 exp_diff
-= sides_zeroes
;
141 uint32_t hd
= (mx
* inv_hy
) >> (BIT_WIDTH
- sides_zeroes
);
144 while (__glibc_unlikely (mx
> my
))
147 uint32_t hd
= (mx
* inv_hy
) >> (BIT_WIDTH
- exp_diff
);
150 while (__glibc_unlikely (mx
> my
))
153 return make_float (mx
, ey
, sx
);
155 libm_alias_finite (__ieee754_fmodf
, __fmodf
)