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