• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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