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