1c120edc7SMichael Jones //===-- Nearest integer floating-point operations ---------------*- C++ -*-===//
2c120edc7SMichael Jones //
3c120edc7SMichael Jones // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c120edc7SMichael Jones // See https://llvm.org/LICENSE.txt for license information.
5c120edc7SMichael Jones // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c120edc7SMichael Jones //
7c120edc7SMichael Jones //===----------------------------------------------------------------------===//
8c120edc7SMichael Jones
9c120edc7SMichael Jones #ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
10c120edc7SMichael Jones #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
11c120edc7SMichael Jones
1276ec69a9STue Ly #include "FEnvImpl.h"
13c120edc7SMichael Jones #include "FPBits.h"
14c120edc7SMichael Jones
15f362aea4SSiva Chandra Reddy #include "src/__support/CPP/TypeTraits.h"
16c120edc7SMichael Jones
17c120edc7SMichael Jones #include <errno.h>
18*0f031daeSTue Ly #include <math.h>
19c120edc7SMichael Jones
20c120edc7SMichael Jones namespace __llvm_libc {
21c120edc7SMichael Jones namespace fputil {
22c120edc7SMichael Jones
23c120edc7SMichael Jones template <typename T,
24c120edc7SMichael Jones cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
trunc(T x)25c120edc7SMichael Jones static inline T trunc(T x) {
26c120edc7SMichael Jones FPBits<T> bits(x);
27c120edc7SMichael Jones
28c120edc7SMichael Jones // If x is infinity or NaN, return it.
29c120edc7SMichael Jones // If it is zero also we should return it as is, but the logic
30c120edc7SMichael Jones // later in this function takes care of it. But not doing a zero
31c120edc7SMichael Jones // check, we improve the run time of non-zero values.
321c92911eSMichael Jones if (bits.is_inf_or_nan())
33c120edc7SMichael Jones return x;
34c120edc7SMichael Jones
351c92911eSMichael Jones int exponent = bits.get_exponent();
36c120edc7SMichael Jones
37c120edc7SMichael Jones // If the exponent is greater than the most negative mantissa
38c120edc7SMichael Jones // exponent, then x is already an integer.
391c92911eSMichael Jones if (exponent >= static_cast<int>(MantissaWidth<T>::VALUE))
40c120edc7SMichael Jones return x;
41c120edc7SMichael Jones
42c120edc7SMichael Jones // If the exponent is such that abs(x) is less than 1, then return 0.
43c120edc7SMichael Jones if (exponent <= -1) {
441c92911eSMichael Jones if (bits.get_sign())
45c120edc7SMichael Jones return T(-0.0);
46c120edc7SMichael Jones else
47c120edc7SMichael Jones return T(0.0);
48c120edc7SMichael Jones }
49c120edc7SMichael Jones
501c92911eSMichael Jones int trim_size = MantissaWidth<T>::VALUE - exponent;
511c92911eSMichael Jones bits.set_mantissa((bits.get_mantissa() >> trim_size) << trim_size);
52c120edc7SMichael Jones return T(bits);
53c120edc7SMichael Jones }
54c120edc7SMichael Jones
55c120edc7SMichael Jones template <typename T,
56c120edc7SMichael Jones cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
ceil(T x)57c120edc7SMichael Jones static inline T ceil(T x) {
58c120edc7SMichael Jones FPBits<T> bits(x);
59c120edc7SMichael Jones
60c120edc7SMichael Jones // If x is infinity NaN or zero, return it.
611c92911eSMichael Jones if (bits.is_inf_or_nan() || bits.is_zero())
62c120edc7SMichael Jones return x;
63c120edc7SMichael Jones
641c92911eSMichael Jones bool is_neg = bits.get_sign();
651c92911eSMichael Jones int exponent = bits.get_exponent();
66c120edc7SMichael Jones
67c120edc7SMichael Jones // If the exponent is greater than the most negative mantissa
68c120edc7SMichael Jones // exponent, then x is already an integer.
691c92911eSMichael Jones if (exponent >= static_cast<int>(MantissaWidth<T>::VALUE))
70c120edc7SMichael Jones return x;
71c120edc7SMichael Jones
72c120edc7SMichael Jones if (exponent <= -1) {
731c92911eSMichael Jones if (is_neg)
74c120edc7SMichael Jones return T(-0.0);
75c120edc7SMichael Jones else
76c120edc7SMichael Jones return T(1.0);
77c120edc7SMichael Jones }
78c120edc7SMichael Jones
791c92911eSMichael Jones uint32_t trim_size = MantissaWidth<T>::VALUE - exponent;
801c92911eSMichael Jones bits.set_mantissa((bits.get_mantissa() >> trim_size) << trim_size);
811c92911eSMichael Jones T trunc_value = T(bits);
82c120edc7SMichael Jones
83c120edc7SMichael Jones // If x is already an integer, return it.
841c92911eSMichael Jones if (trunc_value == x)
85c120edc7SMichael Jones return x;
86c120edc7SMichael Jones
87c120edc7SMichael Jones // If x is negative, the ceil operation is equivalent to the trunc operation.
881c92911eSMichael Jones if (is_neg)
891c92911eSMichael Jones return trunc_value;
90c120edc7SMichael Jones
911c92911eSMichael Jones return trunc_value + T(1.0);
92c120edc7SMichael Jones }
93c120edc7SMichael Jones
94c120edc7SMichael Jones template <typename T,
95c120edc7SMichael Jones cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
floor(T x)96c120edc7SMichael Jones static inline T floor(T x) {
97c120edc7SMichael Jones FPBits<T> bits(x);
981c92911eSMichael Jones if (bits.get_sign()) {
99c120edc7SMichael Jones return -ceil(-x);
100c120edc7SMichael Jones } else {
101c120edc7SMichael Jones return trunc(x);
102c120edc7SMichael Jones }
103c120edc7SMichael Jones }
104c120edc7SMichael Jones
105c120edc7SMichael Jones template <typename T,
106c120edc7SMichael Jones cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
round(T x)107c120edc7SMichael Jones static inline T round(T x) {
108c120edc7SMichael Jones using UIntType = typename FPBits<T>::UIntType;
109c120edc7SMichael Jones FPBits<T> bits(x);
110c120edc7SMichael Jones
111c120edc7SMichael Jones // If x is infinity NaN or zero, return it.
1121c92911eSMichael Jones if (bits.is_inf_or_nan() || bits.is_zero())
113c120edc7SMichael Jones return x;
114c120edc7SMichael Jones
1151c92911eSMichael Jones bool is_neg = bits.get_sign();
1161c92911eSMichael Jones int exponent = bits.get_exponent();
117c120edc7SMichael Jones
118c120edc7SMichael Jones // If the exponent is greater than the most negative mantissa
119c120edc7SMichael Jones // exponent, then x is already an integer.
1201c92911eSMichael Jones if (exponent >= static_cast<int>(MantissaWidth<T>::VALUE))
121c120edc7SMichael Jones return x;
122c120edc7SMichael Jones
123c120edc7SMichael Jones if (exponent == -1) {
124c120edc7SMichael Jones // Absolute value of x is greater than equal to 0.5 but less than 1.
1251c92911eSMichael Jones if (is_neg)
126c120edc7SMichael Jones return T(-1.0);
127c120edc7SMichael Jones else
128c120edc7SMichael Jones return T(1.0);
129c120edc7SMichael Jones }
130c120edc7SMichael Jones
131c120edc7SMichael Jones if (exponent <= -2) {
132c120edc7SMichael Jones // Absolute value of x is less than 0.5.
1331c92911eSMichael Jones if (is_neg)
134c120edc7SMichael Jones return T(-0.0);
135c120edc7SMichael Jones else
136c120edc7SMichael Jones return T(0.0);
137c120edc7SMichael Jones }
138c120edc7SMichael Jones
1391c92911eSMichael Jones uint32_t trim_size = MantissaWidth<T>::VALUE - exponent;
1401c92911eSMichael Jones bool half_bit_set = bits.get_mantissa() & (UIntType(1) << (trim_size - 1));
1411c92911eSMichael Jones bits.set_mantissa((bits.get_mantissa() >> trim_size) << trim_size);
1421c92911eSMichael Jones T trunc_value = T(bits);
143c120edc7SMichael Jones
144c120edc7SMichael Jones // If x is already an integer, return it.
1451c92911eSMichael Jones if (trunc_value == x)
146c120edc7SMichael Jones return x;
147c120edc7SMichael Jones
1481c92911eSMichael Jones if (!half_bit_set) {
149c120edc7SMichael Jones // Franctional part is less than 0.5 so round value is the
150c120edc7SMichael Jones // same as the trunc value.
1511c92911eSMichael Jones return trunc_value;
152c120edc7SMichael Jones } else {
1531c92911eSMichael Jones return is_neg ? trunc_value - T(1.0) : trunc_value + T(1.0);
154c120edc7SMichael Jones }
155c120edc7SMichael Jones }
156c120edc7SMichael Jones
157c120edc7SMichael Jones template <typename T,
158c120edc7SMichael Jones cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
round_using_current_rounding_mode(T x)1591c92911eSMichael Jones static inline T round_using_current_rounding_mode(T x) {
160c120edc7SMichael Jones using UIntType = typename FPBits<T>::UIntType;
161c120edc7SMichael Jones FPBits<T> bits(x);
162c120edc7SMichael Jones
163c120edc7SMichael Jones // If x is infinity NaN or zero, return it.
1641c92911eSMichael Jones if (bits.is_inf_or_nan() || bits.is_zero())
165c120edc7SMichael Jones return x;
166c120edc7SMichael Jones
1671c92911eSMichael Jones bool is_neg = bits.get_sign();
1681c92911eSMichael Jones int exponent = bits.get_exponent();
1691c92911eSMichael Jones int rounding_mode = get_round();
170c120edc7SMichael Jones
171c120edc7SMichael Jones // If the exponent is greater than the most negative mantissa
172c120edc7SMichael Jones // exponent, then x is already an integer.
1731c92911eSMichael Jones if (exponent >= static_cast<int>(MantissaWidth<T>::VALUE))
174c120edc7SMichael Jones return x;
175c120edc7SMichael Jones
176c120edc7SMichael Jones if (exponent <= -1) {
1771c92911eSMichael Jones switch (rounding_mode) {
178c120edc7SMichael Jones case FE_DOWNWARD:
1791c92911eSMichael Jones return is_neg ? T(-1.0) : T(0.0);
180c120edc7SMichael Jones case FE_UPWARD:
1811c92911eSMichael Jones return is_neg ? T(-0.0) : T(1.0);
182c120edc7SMichael Jones case FE_TOWARDZERO:
1831c92911eSMichael Jones return is_neg ? T(-0.0) : T(0.0);
184c120edc7SMichael Jones case FE_TONEAREST:
1851c92911eSMichael Jones if (exponent <= -2 || bits.get_mantissa() == 0)
1861c92911eSMichael Jones return is_neg ? T(-0.0) : T(0.0); // abs(x) <= 0.5
187c120edc7SMichael Jones else
1881c92911eSMichael Jones return is_neg ? T(-1.0) : T(1.0); // abs(x) > 0.5
189c120edc7SMichael Jones default:
190c120edc7SMichael Jones __builtin_unreachable();
191c120edc7SMichael Jones }
192c120edc7SMichael Jones }
193c120edc7SMichael Jones
1941c92911eSMichael Jones uint32_t trim_size = MantissaWidth<T>::VALUE - exponent;
1951c92911eSMichael Jones FPBits<T> new_bits = bits;
1961c92911eSMichael Jones new_bits.set_mantissa((bits.get_mantissa() >> trim_size) << trim_size);
1971c92911eSMichael Jones T trunc_value = T(new_bits);
198c120edc7SMichael Jones
199c120edc7SMichael Jones // If x is already an integer, return it.
2001c92911eSMichael Jones if (trunc_value == x)
201c120edc7SMichael Jones return x;
202c120edc7SMichael Jones
2031c92911eSMichael Jones UIntType trim_value = bits.get_mantissa() & ((UIntType(1) << trim_size) - 1);
2041c92911eSMichael Jones UIntType half_value = (UIntType(1) << (trim_size - 1));
205c120edc7SMichael Jones // If exponent is 0, trimSize will be equal to the mantissa width, and
206c120edc7SMichael Jones // truncIsOdd` will not be correct. So, we handle it as a special case
207c120edc7SMichael Jones // below.
2081c92911eSMichael Jones UIntType trunc_is_odd = new_bits.get_mantissa() & (UIntType(1) << trim_size);
209c120edc7SMichael Jones
2101c92911eSMichael Jones switch (rounding_mode) {
211c120edc7SMichael Jones case FE_DOWNWARD:
2121c92911eSMichael Jones return is_neg ? trunc_value - T(1.0) : trunc_value;
213c120edc7SMichael Jones case FE_UPWARD:
2141c92911eSMichael Jones return is_neg ? trunc_value : trunc_value + T(1.0);
215c120edc7SMichael Jones case FE_TOWARDZERO:
2161c92911eSMichael Jones return trunc_value;
217c120edc7SMichael Jones case FE_TONEAREST:
2181c92911eSMichael Jones if (trim_value > half_value) {
2191c92911eSMichael Jones return is_neg ? trunc_value - T(1.0) : trunc_value + T(1.0);
2201c92911eSMichael Jones } else if (trim_value == half_value) {
221c120edc7SMichael Jones if (exponent == 0)
2221c92911eSMichael Jones return is_neg ? T(-2.0) : T(2.0);
2231c92911eSMichael Jones if (trunc_is_odd)
2241c92911eSMichael Jones return is_neg ? trunc_value - T(1.0) : trunc_value + T(1.0);
225c120edc7SMichael Jones else
2261c92911eSMichael Jones return trunc_value;
227c120edc7SMichael Jones } else {
2281c92911eSMichael Jones return trunc_value;
229c120edc7SMichael Jones }
230c120edc7SMichael Jones default:
231c120edc7SMichael Jones __builtin_unreachable();
232c120edc7SMichael Jones }
233c120edc7SMichael Jones }
234c120edc7SMichael Jones
235c120edc7SMichael Jones namespace internal {
236c120edc7SMichael Jones
237c120edc7SMichael Jones template <typename F, typename I,
238c120edc7SMichael Jones cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
239c120edc7SMichael Jones cpp::IsIntegral<I>::Value,
240c120edc7SMichael Jones int> = 0>
rounded_float_to_signed_integer(F x)2411c92911eSMichael Jones static inline I rounded_float_to_signed_integer(F x) {
2421c92911eSMichael Jones constexpr I INTEGER_MIN = (I(1) << (sizeof(I) * 8 - 1));
2431c92911eSMichael Jones constexpr I INTEGER_MAX = -(INTEGER_MIN + 1);
244c120edc7SMichael Jones FPBits<F> bits(x);
2451c92911eSMichael Jones auto set_domain_error_and_raise_invalid = []() {
246*0f031daeSTue Ly if (math_errhandling & MATH_ERRNO)
247155f5a6dSMichael Jones errno = EDOM;
248*0f031daeSTue Ly if (math_errhandling & MATH_ERREXCEPT)
2491c92911eSMichael Jones raise_except(FE_INVALID);
250c120edc7SMichael Jones };
251c120edc7SMichael Jones
2521c92911eSMichael Jones if (bits.is_inf_or_nan()) {
2531c92911eSMichael Jones set_domain_error_and_raise_invalid();
2541c92911eSMichael Jones return bits.get_sign() ? INTEGER_MIN : INTEGER_MAX;
255c120edc7SMichael Jones }
256c120edc7SMichael Jones
2571c92911eSMichael Jones int exponent = bits.get_exponent();
2581c92911eSMichael Jones constexpr int EXPONENT_LIMIT = sizeof(I) * 8 - 1;
2591c92911eSMichael Jones if (exponent > EXPONENT_LIMIT) {
2601c92911eSMichael Jones set_domain_error_and_raise_invalid();
2611c92911eSMichael Jones return bits.get_sign() ? INTEGER_MIN : INTEGER_MAX;
2621c92911eSMichael Jones } else if (exponent == EXPONENT_LIMIT) {
2631c92911eSMichael Jones if (bits.get_sign() == 0 || bits.get_mantissa() != 0) {
2641c92911eSMichael Jones set_domain_error_and_raise_invalid();
2651c92911eSMichael Jones return bits.get_sign() ? INTEGER_MIN : INTEGER_MAX;
266c120edc7SMichael Jones }
267c120edc7SMichael Jones // If the control reaches here, then it means that the rounded
268c120edc7SMichael Jones // value is the most negative number for the signed integer type I.
269c120edc7SMichael Jones }
270c120edc7SMichael Jones
271c120edc7SMichael Jones // For all other cases, if `x` can fit in the integer type `I`,
272c120edc7SMichael Jones // we just return `x`. Implicit conversion will convert the
273c120edc7SMichael Jones // floating point value to the exact integer value.
274c120edc7SMichael Jones return x;
275c120edc7SMichael Jones }
276c120edc7SMichael Jones
277c120edc7SMichael Jones } // namespace internal
278c120edc7SMichael Jones
279c120edc7SMichael Jones template <typename F, typename I,
280c120edc7SMichael Jones cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
281c120edc7SMichael Jones cpp::IsIntegral<I>::Value,
282c120edc7SMichael Jones int> = 0>
round_to_signed_integer(F x)2831c92911eSMichael Jones static inline I round_to_signed_integer(F x) {
2841c92911eSMichael Jones return internal::rounded_float_to_signed_integer<F, I>(round(x));
285c120edc7SMichael Jones }
286c120edc7SMichael Jones
287c120edc7SMichael Jones template <typename F, typename I,
288c120edc7SMichael Jones cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
289c120edc7SMichael Jones cpp::IsIntegral<I>::Value,
290c120edc7SMichael Jones int> = 0>
round_to_signed_integer_using_current_rounding_mode(F x)2911c92911eSMichael Jones static inline I round_to_signed_integer_using_current_rounding_mode(F x) {
2921c92911eSMichael Jones return internal::rounded_float_to_signed_integer<F, I>(
2931c92911eSMichael Jones round_using_current_rounding_mode(x));
294c120edc7SMichael Jones }
295c120edc7SMichael Jones
296c120edc7SMichael Jones } // namespace fputil
297c120edc7SMichael Jones } // namespace __llvm_libc
298c120edc7SMichael Jones
299c120edc7SMichael Jones #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
300