1 //===-- Floating-point manipulation functions -------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_MANIPULATIONFUNCTIONS_H
10 #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_MANIPULATIONFUNCTIONS_H
13 #include "NearestIntegerOperations.h"
14 #include "NormalFloat.h"
16 #include "dyadic_float.h"
17 #include "rounding_mode.h"
19 #include "hdr/math_macros.h"
20 #include "src/__support/CPP/bit.h"
21 #include "src/__support/CPP/limits.h" // INT_MAX, INT_MIN
22 #include "src/__support/CPP/type_traits.h"
23 #include "src/__support/FPUtil/FEnvImpl.h"
24 #include "src/__support/macros/attributes.h"
25 #include "src/__support/macros/config.h"
26 #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
28 namespace LIBC_NAMESPACE_DECL
{
31 template <typename T
, cpp::enable_if_t
<cpp::is_floating_point_v
<T
>, int> = 0>
32 LIBC_INLINE T
frexp(T x
, int &exp
) {
34 if (bits
.is_inf_or_nan()) {
35 #ifdef LIBC_FREXP_INF_NAN_EXPONENT
36 // The value written back to the second parameter when calling
37 // frexp/frexpf/frexpl` with `+/-Inf`/`NaN` is unspecified in the standard.
38 // Set the exp value for Inf/NaN inputs explicitly to
39 // LIBC_FREXP_INF_NAN_EXPONENT if it is defined.
40 exp
= LIBC_FREXP_INF_NAN_EXPONENT
;
41 #endif // LIBC_FREXP_INF_NAN_EXPONENT
49 NormalFloat
<T
> normal(bits
);
50 exp
= normal
.exponent
+ 1;
55 template <typename T
, cpp::enable_if_t
<cpp::is_floating_point_v
<T
>, int> = 0>
56 LIBC_INLINE T
modf(T x
, T
&iptr
) {
58 if (bits
.is_zero() || bits
.is_nan()) {
61 } else if (bits
.is_inf()) {
63 return FPBits
<T
>::zero(bits
.sign()).get_val();
67 // If x is already an integer value, then return zero with the right
69 return FPBits
<T
>::zero(bits
.sign()).get_val();
76 template <typename T
, cpp::enable_if_t
<cpp::is_floating_point_v
<T
>, int> = 0>
77 LIBC_INLINE T
copysign(T x
, T y
) {
79 xbits
.set_sign(FPBits
<T
>(y
).sign());
80 return xbits
.get_val();
83 template <typename T
> struct IntLogbConstants
;
85 template <> struct IntLogbConstants
<int> {
86 LIBC_INLINE_VAR
static constexpr int FP_LOGB0
= FP_ILOGB0
;
87 LIBC_INLINE_VAR
static constexpr int FP_LOGBNAN
= FP_ILOGBNAN
;
88 LIBC_INLINE_VAR
static constexpr int T_MAX
= INT_MAX
;
89 LIBC_INLINE_VAR
static constexpr int T_MIN
= INT_MIN
;
92 template <> struct IntLogbConstants
<long> {
93 LIBC_INLINE_VAR
static constexpr long FP_LOGB0
= FP_ILOGB0
;
94 LIBC_INLINE_VAR
static constexpr long FP_LOGBNAN
= FP_ILOGBNAN
;
95 LIBC_INLINE_VAR
static constexpr long T_MAX
= LONG_MAX
;
96 LIBC_INLINE_VAR
static constexpr long T_MIN
= LONG_MIN
;
99 template <typename T
, typename U
>
100 LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_floating_point_v
<U
>, T
>
103 if (LIBC_UNLIKELY(bits
.is_zero() || bits
.is_inf_or_nan())) {
104 set_errno_if_required(EDOM
);
105 raise_except_if_required(FE_INVALID
);
108 return IntLogbConstants
<T
>::FP_LOGB0
;
110 return IntLogbConstants
<T
>::FP_LOGBNAN
;
112 return IntLogbConstants
<T
>::T_MAX
;
115 DyadicFloat
<FPBits
<U
>::STORAGE_LEN
> normal(bits
.get_val());
116 int exponent
= normal
.get_unbiased_exponent();
117 // The C standard does not specify the return value when an exponent is
118 // out of int range. However, XSI conformance required that INT_MAX or
119 // INT_MIN are returned.
120 // NOTE: It is highly unlikely that exponent will be out of int range as
121 // the exponent is only 15 bits wide even for the 128-bit floating point
123 if (LIBC_UNLIKELY(exponent
> IntLogbConstants
<T
>::T_MAX
||
124 exponent
< IntLogbConstants
<T
>::T_MIN
)) {
125 set_errno_if_required(ERANGE
);
126 raise_except_if_required(FE_INVALID
);
127 return exponent
> 0 ? IntLogbConstants
<T
>::T_MAX
128 : IntLogbConstants
<T
>::T_MIN
;
131 return static_cast<T
>(exponent
);
134 template <typename T
, cpp::enable_if_t
<cpp::is_floating_point_v
<T
>, int> = 0>
135 LIBC_INLINE
constexpr T
logb(T x
) {
137 if (LIBC_UNLIKELY(bits
.is_zero() || bits
.is_inf_or_nan())) {
141 raise_except_if_required(FE_DIVBYZERO
);
143 if (bits
.is_zero()) {
144 set_errno_if_required(ERANGE
);
145 return FPBits
<T
>::inf(Sign::NEG
).get_val();
148 return FPBits
<T
>::inf().get_val();
151 DyadicFloat
<FPBits
<T
>::STORAGE_LEN
> normal(bits
.get_val());
152 return static_cast<T
>(normal
.get_unbiased_exponent());
155 template <typename T
, typename U
>
156 LIBC_INLINE
constexpr cpp::enable_if_t
<
157 cpp::is_floating_point_v
<T
> && cpp::is_integral_v
<U
>, T
>
160 if (LIBC_UNLIKELY((exp
== 0) || bits
.is_zero() || bits
.is_inf_or_nan()))
163 // NormalFloat uses int32_t to store the true exponent value. We should ensure
164 // that adding |exp| to it does not lead to integer rollover. But, if |exp|
165 // value is larger the exponent range for type T, then we can return infinity
166 // early. Because the result of the ldexp operation can be a subnormal number,
167 // we need to accommodate the (mantissaWidth + 1) worth of shift in
168 // calculating the limit.
169 constexpr int EXP_LIMIT
=
170 FPBits
<T
>::MAX_BIASED_EXPONENT
+ FPBits
<T
>::FRACTION_LEN
+ 1;
171 // Make sure that we can safely cast exp to int when not returning early.
172 static_assert(EXP_LIMIT
<= INT_MAX
&& -EXP_LIMIT
>= INT_MIN
);
173 if (LIBC_UNLIKELY(exp
> EXP_LIMIT
)) {
174 int rounding_mode
= quick_get_round();
175 Sign sign
= bits
.sign();
177 if ((sign
== Sign::POS
&& rounding_mode
== FE_DOWNWARD
) ||
178 (sign
== Sign::NEG
&& rounding_mode
== FE_UPWARD
) ||
179 (rounding_mode
== FE_TOWARDZERO
))
180 return FPBits
<T
>::max_normal(sign
).get_val();
182 set_errno_if_required(ERANGE
);
183 raise_except_if_required(FE_OVERFLOW
);
184 return FPBits
<T
>::inf(sign
).get_val();
187 // Similarly on the negative side we return zero early if |exp| is too small.
188 if (LIBC_UNLIKELY(exp
< -EXP_LIMIT
)) {
189 int rounding_mode
= quick_get_round();
190 Sign sign
= bits
.sign();
192 if ((sign
== Sign::POS
&& rounding_mode
== FE_UPWARD
) ||
193 (sign
== Sign::NEG
&& rounding_mode
== FE_DOWNWARD
))
194 return FPBits
<T
>::min_subnormal(sign
).get_val();
196 set_errno_if_required(ERANGE
);
197 raise_except_if_required(FE_UNDERFLOW
);
198 return FPBits
<T
>::zero(sign
).get_val();
201 // For all other values, NormalFloat to T conversion handles it the right way.
202 DyadicFloat
<FPBits
<T
>::STORAGE_LEN
> normal(bits
.get_val());
203 normal
.exponent
+= static_cast<int>(exp
);
204 // TODO: Add tests for exceptions.
205 return normal
.template as
<T
, /*ShouldRaiseExceptions=*/true>();
208 template <typename T
, typename U
,
209 cpp::enable_if_t
<cpp::is_floating_point_v
<T
> &&
210 cpp::is_floating_point_v
<U
> &&
211 (sizeof(T
) <= sizeof(U
)),
213 LIBC_INLINE T
nextafter(T from
, U to
) {
214 FPBits
<T
> from_bits(from
);
215 if (from_bits
.is_nan())
218 FPBits
<U
> to_bits(to
);
219 if (to_bits
.is_nan())
222 // NOTE: This would work only if `U` has a greater or equal precision than
223 // `T`. Otherwise `from` could loose its precision and the following statement
224 // could incorrectly evaluate to `true`.
225 if (cast
<U
>(from
) == to
)
228 using StorageType
= typename FPBits
<T
>::StorageType
;
230 if ((cast
<U
>(from
) < to
) == (from
> T(0))) {
231 from_bits
= FPBits
<T
>(StorageType(from_bits
.uintval() + 1));
233 from_bits
= FPBits
<T
>(StorageType(from_bits
.uintval() - 1));
236 from_bits
= FPBits
<T
>::min_subnormal(to_bits
.sign());
239 if (from_bits
.is_subnormal())
240 raise_except_if_required(FE_UNDERFLOW
| FE_INEXACT
);
241 else if (from_bits
.is_inf())
242 raise_except_if_required(FE_OVERFLOW
| FE_INEXACT
);
244 return from_bits
.get_val();
247 template <bool IsDown
, typename T
,
248 cpp::enable_if_t
<cpp::is_floating_point_v
<T
>, int> = 0>
249 LIBC_INLINE
constexpr T
nextupdown(T x
) {
250 constexpr Sign sign
= IsDown
? Sign::NEG
: Sign::POS
;
253 if (xbits
.is_nan() || xbits
== FPBits
<T
>::max_normal(sign
) ||
254 xbits
== FPBits
<T
>::inf(sign
))
257 using StorageType
= typename FPBits
<T
>::StorageType
;
259 if (xbits
.sign() == sign
) {
260 xbits
= FPBits
<T
>(StorageType(xbits
.uintval() + 1));
262 xbits
= FPBits
<T
>(StorageType(xbits
.uintval() - 1));
265 xbits
= FPBits
<T
>::min_subnormal(sign
);
268 return xbits
.get_val();
271 } // namespace fputil
272 } // namespace LIBC_NAMESPACE_DECL
274 #ifdef LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
275 #include "x86_64/NextAfterLongDouble.h"
276 #include "x86_64/NextUpDownLongDouble.h"
277 #endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
279 #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_MANIPULATIONFUNCTIONS_H