1 //===-- Floating-point manipulation functions -------------------*- 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_SRC_SUPPORT_FPUTIL_MANIPULATION_FUNCTIONS_H
10 #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_MANIPULATION_FUNCTIONS_H
11
12 #include "FPBits.h"
13 #include "NearestIntegerOperations.h"
14 #include "NormalFloat.h"
15 #include "PlatformDefs.h"
16
17 #include "src/__support/CPP/Bit.h"
18 #include "src/__support/CPP/TypeTraits.h"
19
20 #include <limits.h>
21 #include <math.h>
22
23 namespace __llvm_libc {
24 namespace fputil {
25
26 template <typename T,
27 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
frexp(T x,int & exp)28 static inline T frexp(T x, int &exp) {
29 FPBits<T> bits(x);
30 if (bits.is_inf_or_nan())
31 return x;
32 if (bits.is_zero()) {
33 exp = 0;
34 return x;
35 }
36
37 NormalFloat<T> normal(bits);
38 exp = normal.exponent + 1;
39 normal.exponent = -1;
40 return normal;
41 }
42
43 template <typename T,
44 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
modf(T x,T & iptr)45 static inline T modf(T x, T &iptr) {
46 FPBits<T> bits(x);
47 if (bits.is_zero() || bits.is_nan()) {
48 iptr = x;
49 return x;
50 } else if (bits.is_inf()) {
51 iptr = x;
52 return bits.get_sign() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
53 } else {
54 iptr = trunc(x);
55 if (x == iptr) {
56 // If x is already an integer value, then return zero with the right
57 // sign.
58 return bits.get_sign() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
59 } else {
60 return x - iptr;
61 }
62 }
63 }
64
65 template <typename T,
66 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
copysign(T x,T y)67 static inline T copysign(T x, T y) {
68 FPBits<T> xbits(x);
69 xbits.set_sign(FPBits<T>(y).get_sign());
70 return T(xbits);
71 }
72
73 template <typename T,
74 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
ilogb(T x)75 static inline int ilogb(T x) {
76 // TODO: Raise appropriate floating point exceptions and set errno to the
77 // an appropriate error value wherever relevant.
78 FPBits<T> bits(x);
79 if (bits.is_zero()) {
80 return FP_ILOGB0;
81 } else if (bits.is_nan()) {
82 return FP_ILOGBNAN;
83 } else if (bits.is_inf()) {
84 return INT_MAX;
85 }
86
87 NormalFloat<T> normal(bits);
88 // The C standard does not specify the return value when an exponent is
89 // out of int range. However, XSI conformance required that INT_MAX or
90 // INT_MIN are returned.
91 // NOTE: It is highly unlikely that exponent will be out of int range as
92 // the exponent is only 15 bits wide even for the 128-bit floating point
93 // format.
94 if (normal.exponent > INT_MAX)
95 return INT_MAX;
96 else if (normal.exponent < INT_MIN)
97 return INT_MIN;
98 else
99 return normal.exponent;
100 }
101
102 template <typename T,
103 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
logb(T x)104 static inline T logb(T x) {
105 FPBits<T> bits(x);
106 if (bits.is_zero()) {
107 // TODO(Floating point exception): Raise div-by-zero exception.
108 // TODO(errno): POSIX requires setting errno to ERANGE.
109 return T(FPBits<T>::neg_inf());
110 } else if (bits.is_nan()) {
111 return x;
112 } else if (bits.is_inf()) {
113 // Return positive infinity.
114 return T(FPBits<T>::inf());
115 }
116
117 NormalFloat<T> normal(bits);
118 return normal.exponent;
119 }
120
121 template <typename T,
122 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
ldexp(T x,int exp)123 static inline T ldexp(T x, int exp) {
124 FPBits<T> bits(x);
125 if (bits.is_zero() || bits.is_inf_or_nan() || exp == 0)
126 return x;
127
128 // NormalFloat uses int32_t to store the true exponent value. We should ensure
129 // that adding |exp| to it does not lead to integer rollover. But, if |exp|
130 // value is larger the exponent range for type T, then we can return infinity
131 // early. Because the result of the ldexp operation can be a subnormal number,
132 // we need to accommodate the (mantissaWidht + 1) worth of shift in
133 // calculating the limit.
134 int exp_limit = FPBits<T>::MAX_EXPONENT + MantissaWidth<T>::VALUE + 1;
135 if (exp > exp_limit)
136 return bits.get_sign() ? T(FPBits<T>::neg_inf()) : T(FPBits<T>::inf());
137
138 // Similarly on the negative side we return zero early if |exp| is too small.
139 if (exp < -exp_limit)
140 return bits.get_sign() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
141
142 // For all other values, NormalFloat to T conversion handles it the right way.
143 NormalFloat<T> normal(bits);
144 normal.exponent += exp;
145 return normal;
146 }
147
148 template <typename T,
149 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
nextafter(T from,T to)150 static inline T nextafter(T from, T to) {
151 FPBits<T> from_bits(from);
152 if (from_bits.is_nan())
153 return from;
154
155 FPBits<T> to_bits(to);
156 if (to_bits.is_nan())
157 return to;
158
159 if (from == to)
160 return to;
161
162 using UIntType = typename FPBits<T>::UIntType;
163 UIntType int_val = from_bits.uintval();
164 UIntType sign_mask = (UIntType(1) << (sizeof(T) * 8 - 1));
165 if (from != T(0.0)) {
166 if ((from < to) == (from > T(0.0))) {
167 ++int_val;
168 } else {
169 --int_val;
170 }
171 } else {
172 int_val = (to_bits.uintval() & sign_mask) + UIntType(1);
173 }
174
175 return __llvm_libc::bit_cast<T>(int_val);
176 // TODO: Raise floating point exceptions as required by the standard.
177 }
178
179 } // namespace fputil
180 } // namespace __llvm_libc
181
182 #ifdef SPECIAL_X86_LONG_DOUBLE
183 #include "x86_64/NextAfterLongDouble.h"
184 #endif // SPECIAL_X86_LONG_DOUBLE
185
186 #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_MANIPULATION_FUNCTIONS_H
187