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> 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> 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> 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> 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> 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> 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> 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