1 //===-- Nearest integer floating-point operations ---------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
10 #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
14 #include "rounding_mode.h"
16 #include "src/__support/CPP/type_traits.h"
17 #include "src/__support/common.h"
21 namespace __llvm_libc
{
24 template <typename T
, cpp::enable_if_t
<cpp::is_floating_point_v
<T
>, int> = 0>
25 LIBC_INLINE T
trunc(T x
) {
28 // If x is infinity or NaN, return it.
29 // If it is zero also we should return it as is, but the logic
30 // later in this function takes care of it. But not doing a zero
31 // check, we improve the run time of non-zero values.
32 if (bits
.is_inf_or_nan())
35 int exponent
= bits
.get_exponent();
37 // If the exponent is greater than the most negative mantissa
38 // exponent, then x is already an integer.
39 if (exponent
>= static_cast<int>(MantissaWidth
<T
>::VALUE
))
42 // If the exponent is such that abs(x) is less than 1, then return 0.
50 int trim_size
= MantissaWidth
<T
>::VALUE
- exponent
;
51 bits
.set_mantissa((bits
.get_mantissa() >> trim_size
) << trim_size
);
55 template <typename T
, cpp::enable_if_t
<cpp::is_floating_point_v
<T
>, int> = 0>
56 LIBC_INLINE T
ceil(T x
) {
59 // If x is infinity NaN or zero, return it.
60 if (bits
.is_inf_or_nan() || bits
.is_zero())
63 bool is_neg
= bits
.get_sign();
64 int exponent
= bits
.get_exponent();
66 // If the exponent is greater than the most negative mantissa
67 // exponent, then x is already an integer.
68 if (exponent
>= static_cast<int>(MantissaWidth
<T
>::VALUE
))
78 uint32_t trim_size
= MantissaWidth
<T
>::VALUE
- exponent
;
79 bits
.set_mantissa((bits
.get_mantissa() >> trim_size
) << trim_size
);
80 T trunc_value
= T(bits
);
82 // If x is already an integer, return it.
86 // If x is negative, the ceil operation is equivalent to the trunc operation.
90 return trunc_value
+ T(1.0);
93 template <typename T
, cpp::enable_if_t
<cpp::is_floating_point_v
<T
>, int> = 0>
94 LIBC_INLINE T
floor(T x
) {
96 if (bits
.get_sign()) {
103 template <typename T
, cpp::enable_if_t
<cpp::is_floating_point_v
<T
>, int> = 0>
104 LIBC_INLINE T
round(T x
) {
105 using UIntType
= typename FPBits
<T
>::UIntType
;
108 // If x is infinity NaN or zero, return it.
109 if (bits
.is_inf_or_nan() || bits
.is_zero())
112 bool is_neg
= bits
.get_sign();
113 int exponent
= bits
.get_exponent();
115 // If the exponent is greater than the most negative mantissa
116 // exponent, then x is already an integer.
117 if (exponent
>= static_cast<int>(MantissaWidth
<T
>::VALUE
))
120 if (exponent
== -1) {
121 // Absolute value of x is greater than equal to 0.5 but less than 1.
128 if (exponent
<= -2) {
129 // Absolute value of x is less than 0.5.
136 uint32_t trim_size
= MantissaWidth
<T
>::VALUE
- exponent
;
138 bool(bits
.get_mantissa() & (UIntType(1) << (trim_size
- 1)));
139 bits
.set_mantissa((bits
.get_mantissa() >> trim_size
) << trim_size
);
140 T trunc_value
= T(bits
);
142 // If x is already an integer, return it.
143 if (trunc_value
== x
)
147 // Franctional part is less than 0.5 so round value is the
148 // same as the trunc value.
151 return is_neg
? trunc_value
- T(1.0) : trunc_value
+ T(1.0);
155 template <typename T
, cpp::enable_if_t
<cpp::is_floating_point_v
<T
>, int> = 0>
156 LIBC_INLINE T
round_using_current_rounding_mode(T x
) {
157 using UIntType
= typename FPBits
<T
>::UIntType
;
160 // If x is infinity NaN or zero, return it.
161 if (bits
.is_inf_or_nan() || bits
.is_zero())
164 bool is_neg
= bits
.get_sign();
165 int exponent
= bits
.get_exponent();
166 int rounding_mode
= quick_get_round();
168 // If the exponent is greater than the most negative mantissa
169 // exponent, then x is already an integer.
170 if (exponent
>= static_cast<int>(MantissaWidth
<T
>::VALUE
))
173 if (exponent
<= -1) {
174 switch (rounding_mode
) {
176 return is_neg
? T(-1.0) : T(0.0);
178 return is_neg
? T(-0.0) : T(1.0);
180 return is_neg
? T(-0.0) : T(0.0);
182 if (exponent
<= -2 || bits
.get_mantissa() == 0)
183 return is_neg
? T(-0.0) : T(0.0); // abs(x) <= 0.5
185 return is_neg
? T(-1.0) : T(1.0); // abs(x) > 0.5
187 __builtin_unreachable();
191 uint32_t trim_size
= MantissaWidth
<T
>::VALUE
- exponent
;
192 FPBits
<T
> new_bits
= bits
;
193 new_bits
.set_mantissa((bits
.get_mantissa() >> trim_size
) << trim_size
);
194 T trunc_value
= T(new_bits
);
196 // If x is already an integer, return it.
197 if (trunc_value
== x
)
200 UIntType trim_value
= bits
.get_mantissa() & ((UIntType(1) << trim_size
) - 1);
201 UIntType half_value
= (UIntType(1) << (trim_size
- 1));
202 // If exponent is 0, trimSize will be equal to the mantissa width, and
203 // truncIsOdd` will not be correct. So, we handle it as a special case
205 UIntType trunc_is_odd
= new_bits
.get_mantissa() & (UIntType(1) << trim_size
);
207 switch (rounding_mode
) {
209 return is_neg
? trunc_value
- T(1.0) : trunc_value
;
211 return is_neg
? trunc_value
: trunc_value
+ T(1.0);
215 if (trim_value
> half_value
) {
216 return is_neg
? trunc_value
- T(1.0) : trunc_value
+ T(1.0);
217 } else if (trim_value
== half_value
) {
219 return is_neg
? T(-2.0) : T(2.0);
221 return is_neg
? trunc_value
- T(1.0) : trunc_value
+ T(1.0);
228 __builtin_unreachable();
234 template <typename F
, typename I
,
235 cpp::enable_if_t
<cpp::is_floating_point_v
<F
> && cpp::is_integral_v
<I
>,
237 LIBC_INLINE I
rounded_float_to_signed_integer(F x
) {
238 constexpr I INTEGER_MIN
= (I(1) << (sizeof(I
) * 8 - 1));
239 constexpr I INTEGER_MAX
= -(INTEGER_MIN
+ 1);
241 auto set_domain_error_and_raise_invalid
= []() {
242 set_errno_if_required(EDOM
);
243 raise_except_if_required(FE_INVALID
);
246 if (bits
.is_inf_or_nan()) {
247 set_domain_error_and_raise_invalid();
248 return bits
.get_sign() ? INTEGER_MIN
: INTEGER_MAX
;
251 int exponent
= bits
.get_exponent();
252 constexpr int EXPONENT_LIMIT
= sizeof(I
) * 8 - 1;
253 if (exponent
> EXPONENT_LIMIT
) {
254 set_domain_error_and_raise_invalid();
255 return bits
.get_sign() ? INTEGER_MIN
: INTEGER_MAX
;
256 } else if (exponent
== EXPONENT_LIMIT
) {
257 if (bits
.get_sign() == 0 || bits
.get_mantissa() != 0) {
258 set_domain_error_and_raise_invalid();
259 return bits
.get_sign() ? INTEGER_MIN
: INTEGER_MAX
;
261 // If the control reaches here, then it means that the rounded
262 // value is the most negative number for the signed integer type I.
265 // For all other cases, if `x` can fit in the integer type `I`,
266 // we just return `x`. static_cast will convert the floating
267 // point value to the exact integer value.
268 return static_cast<I
>(x
);
271 } // namespace internal
273 template <typename F
, typename I
,
274 cpp::enable_if_t
<cpp::is_floating_point_v
<F
> && cpp::is_integral_v
<I
>,
276 LIBC_INLINE I
round_to_signed_integer(F x
) {
277 return internal::rounded_float_to_signed_integer
<F
, I
>(round(x
));
280 template <typename F
, typename I
,
281 cpp::enable_if_t
<cpp::is_floating_point_v
<F
> && cpp::is_integral_v
<I
>,
283 LIBC_INLINE I
round_to_signed_integer_using_current_rounding_mode(F x
) {
284 return internal::rounded_float_to_signed_integer
<F
, I
>(
285 round_using_current_rounding_mode(x
));
288 } // namespace fputil
289 } // namespace __llvm_libc
291 #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_OPERATIONS_H