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