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