1 /* Round to integer type. Common helper functions.
2 Copyright (C) 2016-2024 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/>. */
23 #include <math-barriers.h>
27 /* The including file should have defined UNSIGNED to 0 (signed return
28 type) or 1 (unsigned return type), INEXACT to 0 (no inexact
29 exceptions) or 1 (raise inexact exceptions) and RET_TYPE to the
30 return type (intmax_t or uintmax_t). */
32 /* Return the maximum unbiased exponent for an argument (negative if
33 NEGATIVE is set) that might be in range for a call to a fromfp
34 function with width WIDTH (greater than 0, and not exceeding that
35 of intmax_t). The truncated argument may still be out of range in
36 the case of negative arguments, and if not out of range it may
37 become out of range as a result of rounding. */
40 fromfp_max_exponent (bool negative
, int width
)
43 return negative
? -1 : width
- 1;
45 return negative
? width
- 1 : width
- 2;
48 /* Return the result of rounding an integer value X (passed as the
49 absolute value; NEGATIVE is true if the value is negative), where
50 HALF_BIT is true if the bit with value 0.5 is set and MORE_BITS is
51 true if any lower bits are set, in the rounding direction
55 fromfp_round (bool negative
, uintmax_t x
, bool half_bit
, bool more_bits
,
61 return x
+ (!negative
&& (half_bit
|| more_bits
));
64 return x
+ (negative
&& (half_bit
|| more_bits
));
66 case FP_INT_TOWARDZERO
:
68 /* Unknown rounding directions are defined to mean unspecified
69 rounding; treat this as truncation. */
72 case FP_INT_TONEARESTFROMZERO
:
75 case FP_INT_TONEAREST
:
76 return x
+ (half_bit
&& ((x
& 1) || more_bits
));
80 /* Integer rounding, of a value whose exponent EXPONENT did not exceed
81 the maximum exponent MAX_EXPONENT and so did not necessarily
82 overflow, has produced X (possibly wrapping to 0); the sign is
83 negative if NEGATIVE is true. Return whether this overflowed the
87 fromfp_overflowed (bool negative
, uintmax_t x
, int exponent
, int max_exponent
)
93 else if (max_exponent
== INTMAX_WIDTH
- 1)
94 return exponent
== INTMAX_WIDTH
- 1 && x
== 0;
96 return x
== (1ULL << (max_exponent
+ 1));
101 return exponent
== max_exponent
&& x
!= (1ULL << max_exponent
);
103 return x
== (1ULL << (max_exponent
+ 1));
107 /* Handle a domain error for a call to a fromfp function with an
108 argument which is negative if NEGATIVE is set, and specified width
109 (not exceeding that of intmax_t) WIDTH. The return value is
110 unspecified (with it being unclear if the result needs to fit
111 within WIDTH bits in this case); we choose to saturate to the given
112 number of bits (treating NaNs like any other value). */
115 fromfp_domain_error (bool negative
, unsigned int width
)
117 feraiseexcept (FE_INVALID
);
119 /* The return value is unspecified; we choose to saturate to the
120 given number of bits (treating NaNs like any other value). */
125 else if (width
== INTMAX_WIDTH
)
128 return (1ULL << width
) - 1;
135 return -(1ULL << (width
- 1));
137 return (1ULL << (width
- 1)) - 1;
141 /* Given X, the absolute value of a floating-point number (negative if
142 NEGATIVE is set) truncated towards zero, where HALF_BIT is true if
143 the bit with value 0.5 is set and MORE_BITS is true if any lower
144 bits are set, round it in the rounding direction ROUND, handle
145 errors and exceptions and return the appropriate return value for a
146 fromfp function. X originally had floating-point exponent
147 EXPONENT, which does not exceed MAX_EXPONENT, the return value from
148 fromfp_max_exponent with width WIDTH. */
151 fromfp_round_and_return (bool negative
, uintmax_t x
, bool half_bit
,
152 bool more_bits
, int round
, int exponent
,
153 int max_exponent
, unsigned int width
)
155 uintmax_t uret
= fromfp_round (negative
, x
, half_bit
, more_bits
, round
);
156 if (fromfp_overflowed (negative
, uret
, exponent
, max_exponent
))
157 return fromfp_domain_error (negative
, width
);
159 if (INEXACT
&& (half_bit
|| more_bits
))
161 /* There is no need for this to use the specific floating-point
162 type for which this header is included, and there is no need
163 for this header to know that type at all, so just use float
165 float force_inexact
= 1.0f
+ FLT_MIN
;
166 math_force_eval (force_inexact
);
169 /* A negative argument not rounding to zero will already have
170 produced a domain error. */
173 return negative
? -uret
: uret
;