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