• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Nearest integer floating-point operations ---------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
10 #define LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
11 
12 #include "FPBits.h"
13 
14 #include "utils/CPP/TypeTraits.h"
15 
16 namespace __llvm_libc {
17 namespace fputil {
18 
19 template <typename T,
20           cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
trunc(T x)21 static inline T trunc(T x) {
22   FPBits<T> bits(x);
23 
24   // If x is infinity or NaN, return it.
25   // If it is zero also we should return it as is, but the logic
26   // later in this function takes care of it. But not doing a zero
27   // check, we improve the run time of non-zero values.
28   if (bits.isInfOrNaN())
29     return x;
30 
31   int exponent = bits.getExponent();
32 
33   // If the exponent is greater than the most negative mantissa
34   // exponent, then x is already an integer.
35   if (exponent >= static_cast<int>(MantissaWidth<T>::value))
36     return x;
37 
38   // If the exponent is such that abs(x) is less than 1, then return 0.
39   if (exponent <= -1) {
40     if (bits.sign)
41       return T(-0.0);
42     else
43       return T(0.0);
44   }
45 
46   int trimSize = MantissaWidth<T>::value - exponent;
47   bits.mantissa = (bits.mantissa >> trimSize) << trimSize;
48   return bits;
49 }
50 
51 template <typename T,
52           cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
ceil(T x)53 static inline T ceil(T x) {
54   FPBits<T> bits(x);
55 
56   // If x is infinity NaN or zero, return it.
57   if (bits.isInfOrNaN() || bits.isZero())
58     return x;
59 
60   bool isNeg = bits.sign;
61   int exponent = bits.getExponent();
62 
63   // If the exponent is greater than the most negative mantissa
64   // exponent, then x is already an integer.
65   if (exponent >= static_cast<int>(MantissaWidth<T>::value))
66     return x;
67 
68   if (exponent <= -1) {
69     if (isNeg)
70       return T(-0.0);
71     else
72       return T(1.0);
73   }
74 
75   uint32_t trimSize = MantissaWidth<T>::value - exponent;
76   bits.mantissa = (bits.mantissa >> trimSize) << trimSize;
77   T truncValue = T(bits);
78 
79   // If x is already an integer, return it.
80   if (truncValue == x)
81     return x;
82 
83   // If x is negative, the ceil operation is equivalent to the trunc operation.
84   if (isNeg)
85     return truncValue;
86 
87   return truncValue + T(1.0);
88 }
89 
90 template <typename T,
91           cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
floor(T x)92 static inline T floor(T x) {
93   FPBits<T> bits(x);
94   if (bits.sign) {
95     return -ceil(-x);
96   } else {
97     return trunc(x);
98   }
99 }
100 
101 template <typename T,
102           cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
round(T x)103 static inline T round(T x) {
104   using UIntType = typename FPBits<T>::UIntType;
105   FPBits<T> bits(x);
106 
107   // If x is infinity NaN or zero, return it.
108   if (bits.isInfOrNaN() || bits.isZero())
109     return x;
110 
111   bool isNeg = bits.sign;
112   int exponent = bits.getExponent();
113 
114   // If the exponent is greater than the most negative mantissa
115   // exponent, then x is already an integer.
116   if (exponent >= static_cast<int>(MantissaWidth<T>::value))
117     return x;
118 
119   if (exponent == -1) {
120     // Absolute value of x is greater than equal to 0.5 but less than 1.
121     if (isNeg)
122       return T(-1.0);
123     else
124       return T(1.0);
125   }
126 
127   if (exponent <= -2) {
128     // Absolute value of x is less than 0.5.
129     if (isNeg)
130       return T(-0.0);
131     else
132       return T(0.0);
133   }
134 
135   uint32_t trimSize = MantissaWidth<T>::value - exponent;
136   bool halfBitSet = bits.mantissa & (UIntType(1) << (trimSize - 1));
137   bits.mantissa = (bits.mantissa >> trimSize) << trimSize;
138   T truncValue = T(bits);
139 
140   // If x is already an integer, return it.
141   if (truncValue == x)
142     return x;
143 
144   if (!halfBitSet) {
145     // Franctional part is less than 0.5 so round value is the
146     // same as the trunc value.
147     return truncValue;
148   } else {
149     return isNeg ? truncValue - T(1.0) : truncValue + T(1.0);
150   }
151 }
152 
153 } // namespace fputil
154 } // namespace __llvm_libc
155 
156 #endif // LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
157