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_UTILS_FPUTIL_MANIPULATION_FUNCTIONS_H
10 #define LLVM_LIBC_UTILS_FPUTIL_MANIPULATION_FUNCTIONS_H
11
12 #include "FPBits.h"
13 #include "NearestIntegerOperations.h"
14 #include "NormalFloat.h"
15
16 #include "include/math.h"
17 #include "utils/CPP/TypeTraits.h"
18
19 #include <limits.h>
20
21 namespace __llvm_libc {
22 namespace fputil {
23
24 template <typename T,
25 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
frexp(T x,int & exp)26 static inline T frexp(T x, int &exp) {
27 FPBits<T> bits(x);
28 if (bits.isInfOrNaN())
29 return x;
30 if (bits.isZero()) {
31 exp = 0;
32 return x;
33 }
34
35 NormalFloat<T> normal(bits);
36 exp = normal.exponent + 1;
37 normal.exponent = -1;
38 return normal;
39 }
40
41 template <typename T,
42 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
modf(T x,T & iptr)43 static inline T modf(T x, T &iptr) {
44 FPBits<T> bits(x);
45 if (bits.isZero() || bits.isNaN()) {
46 iptr = x;
47 return x;
48 } else if (bits.isInf()) {
49 iptr = x;
50 return bits.sign ? FPBits<T>::negZero() : FPBits<T>::zero();
51 } else {
52 iptr = trunc(x);
53 if (x == iptr) {
54 // If x is already an integer value, then return zero with the right
55 // sign.
56 return bits.sign ? FPBits<T>::negZero() : FPBits<T>::zero();
57 } else {
58 return x - iptr;
59 }
60 }
61 }
62
63 template <typename T,
64 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
copysign(T x,T y)65 static inline T copysign(T x, T y) {
66 FPBits<T> xbits(x);
67 xbits.sign = FPBits<T>(y).sign;
68 return xbits;
69 }
70
71 template <typename T,
72 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
ilogb(T x)73 static inline int ilogb(T x) {
74 // TODO: Raise appropriate floating point exceptions and set errno to the
75 // an appropriate error value wherever relevant.
76 FPBits<T> bits(x);
77 if (bits.isZero()) {
78 return FP_ILOGB0;
79 } else if (bits.isNaN()) {
80 return FP_ILOGBNAN;
81 } else if (bits.isInf()) {
82 return INT_MAX;
83 }
84
85 NormalFloat<T> normal(bits);
86 // The C standard does not specify the return value when an exponent is
87 // out of int range. However, XSI conformance required that INT_MAX or
88 // INT_MIN are returned.
89 // NOTE: It is highly unlikely that exponent will be out of int range as
90 // the exponent is only 15 bits wide even for the 128-bit floating point
91 // format.
92 if (normal.exponent > INT_MAX)
93 return INT_MAX;
94 else if (normal.exponent < INT_MIN)
95 return INT_MIN;
96 else
97 return normal.exponent;
98 }
99
100 template <typename T,
101 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
logb(T x)102 static inline T logb(T x) {
103 FPBits<T> bits(x);
104 if (bits.isZero()) {
105 // TODO(Floating point exception): Raise div-by-zero exception.
106 // TODO(errno): POSIX requires setting errno to ERANGE.
107 return FPBits<T>::negInf();
108 } else if (bits.isNaN()) {
109 return x;
110 } else if (bits.isInf()) {
111 // Return positive infinity.
112 return FPBits<T>::inf();
113 }
114
115 NormalFloat<T> normal(bits);
116 return normal.exponent;
117 }
118
119 template <typename T,
120 cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
ldexp(T x,int exp)121 static inline T ldexp(T x, int exp) {
122 FPBits<T> bits(x);
123 if (bits.isZero() || bits.isInfOrNaN() || exp == 0)
124 return x;
125
126 // NormalFloat uses int32_t to store the true exponent value. We should ensure
127 // that adding |exp| to it does not lead to integer rollover. But, if |exp|
128 // value is larger the exponent range for type T, then we can return infinity
129 // early. Because the result of the ldexp operation can be a subnormal number,
130 // we need to accommodate the (mantissaWidht + 1) worth of shift in
131 // calculating the limit.
132 int expLimit = FPBits<T>::maxExponent + MantissaWidth<T>::value + 1;
133 if (exp > expLimit)
134 return bits.sign ? FPBits<T>::negInf() : FPBits<T>::inf();
135
136 // Similarly on the negative side we return zero early if |exp| is too small.
137 if (exp < -expLimit)
138 return bits.sign ? FPBits<T>::negZero() : FPBits<T>::zero();
139
140 // For all other values, NormalFloat to T conversion handles it the right way.
141 NormalFloat<T> normal(bits);
142 normal.exponent += exp;
143 return normal;
144 }
145
146 } // namespace fputil
147 } // namespace __llvm_libc
148
149 #endif // LLVM_LIBC_UTILS_FPUTIL_MANIPULATION_FUNCTIONS_H
150