mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 13:50:11 +00:00
[libc] Remove unnecessary FPBits
functions and properties (#79113)
This patch reduces the surface of `FPBits`.
This commit is contained in:
parent
9629c73aeb
commit
3bc86bf3bf
@ -28,7 +28,7 @@ using LIBC_NAMESPACE::fputil::FPBits;
|
||||
// exponent. Subnormals have a lower effective precision since they don't
|
||||
// necessarily use all of the bits of the mantissa.
|
||||
template <typename F> inline constexpr int effective_precision(int exponent) {
|
||||
const int full_precision = FPBits<F>::MANTISSA_PRECISION;
|
||||
const int full_precision = FPBits<F>::FRACTION_LEN + 1;
|
||||
|
||||
// This is intended to be 0 when the exponent is the lowest normal and
|
||||
// increase as the exponent's magnitude increases.
|
||||
|
@ -31,7 +31,7 @@ LIBC_INLINE T remquo(T x, T y, int &q) {
|
||||
if (ybits.is_nan())
|
||||
return y;
|
||||
if (xbits.is_inf() || ybits.is_zero())
|
||||
return FPBits<T>::build_quiet_nan(1);
|
||||
return FPBits<T>::build_quiet_nan(fputil::Sign::POS, 1).get_val();
|
||||
|
||||
if (xbits.is_zero()) {
|
||||
q = 0;
|
||||
|
@ -390,7 +390,7 @@ public:
|
||||
return exp_bits() == encode(BiasedExp::BITS_ALL_ZEROES());
|
||||
}
|
||||
LIBC_INLINE constexpr bool is_normal() const {
|
||||
return is_finite() && !UP::is_subnormal();
|
||||
return is_finite() && !is_subnormal();
|
||||
}
|
||||
// Returns the mantissa with the implicit bit set iff the current
|
||||
// value is a valid normal number.
|
||||
@ -556,6 +556,14 @@ public:
|
||||
using UP::FRACTION_MASK;
|
||||
using UP::SIGN_MASK;
|
||||
|
||||
// Comparison
|
||||
LIBC_INLINE constexpr friend bool operator==(FPRep a, FPRep b) {
|
||||
return a.uintval() == b.uintval();
|
||||
}
|
||||
LIBC_INLINE constexpr friend bool operator!=(FPRep a, FPRep b) {
|
||||
return a.uintval() != b.uintval();
|
||||
}
|
||||
|
||||
// Representation
|
||||
LIBC_INLINE constexpr StorageType uintval() const { return bits & FP_MASK; }
|
||||
LIBC_INLINE constexpr void set_uintval(StorageType value) {
|
||||
@ -698,16 +706,6 @@ struct FPBits final : public internal::FPRep<get_fp_type<T>(), FPBits<T>> {
|
||||
using UP::bits;
|
||||
|
||||
// Constants.
|
||||
LIBC_INLINE_VAR static constexpr uint32_t MANTISSA_PRECISION =
|
||||
UP::FRACTION_LEN + 1;
|
||||
LIBC_INLINE_VAR static constexpr StorageType MIN_NORMAL =
|
||||
UP::min_normal(Sign::POS).uintval();
|
||||
LIBC_INLINE_VAR static constexpr StorageType MAX_NORMAL =
|
||||
UP::max_normal(Sign::POS).uintval();
|
||||
LIBC_INLINE_VAR static constexpr StorageType MIN_SUBNORMAL =
|
||||
UP::min_subnormal(Sign::POS).uintval();
|
||||
LIBC_INLINE_VAR static constexpr StorageType MAX_SUBNORMAL =
|
||||
UP::max_subnormal(Sign::POS).uintval();
|
||||
LIBC_INLINE_VAR static constexpr int MAX_BIASED_EXPONENT =
|
||||
(1 << UP::EXP_LEN) - 1;
|
||||
|
||||
@ -731,37 +729,6 @@ struct FPBits final : public internal::FPRep<get_fp_type<T>(), FPBits<T>> {
|
||||
|
||||
LIBC_INLINE constexpr explicit operator T() const { return get_val(); }
|
||||
|
||||
// Methods below this are used by tests.
|
||||
// TODO: inline and remove.
|
||||
LIBC_INLINE static constexpr T one(Sign sign = Sign::POS) {
|
||||
return T(UP::one(sign));
|
||||
}
|
||||
LIBC_INLINE static constexpr T zero(Sign sign = Sign::POS) {
|
||||
return T(UP::zero(sign));
|
||||
}
|
||||
LIBC_INLINE static constexpr T inf(Sign sign = Sign::POS) {
|
||||
return T(UP::inf(sign));
|
||||
}
|
||||
LIBC_INLINE static constexpr T min_normal() {
|
||||
return T(UP::min_normal(Sign::POS));
|
||||
}
|
||||
LIBC_INLINE static constexpr T max_normal() {
|
||||
return T(UP::max_normal(Sign::POS));
|
||||
}
|
||||
LIBC_INLINE static constexpr T min_denormal() {
|
||||
return T(UP::min_subnormal(Sign::POS));
|
||||
}
|
||||
LIBC_INLINE static constexpr T max_denormal() {
|
||||
return T(UP::max_subnormal(Sign::POS));
|
||||
}
|
||||
LIBC_INLINE static constexpr T build_nan(StorageType v) {
|
||||
return T(UP::build_nan(Sign::POS, v));
|
||||
}
|
||||
LIBC_INLINE static constexpr T build_quiet_nan(StorageType v,
|
||||
Sign sign = Sign::POS) {
|
||||
return T(UP::build_quiet_nan(sign, v));
|
||||
}
|
||||
|
||||
// TODO: Use an uint32_t for 'biased_exp'.
|
||||
LIBC_INLINE static constexpr FPBits<T>
|
||||
create_value(Sign sign, StorageType biased_exp, StorageType mantissa) {
|
||||
|
@ -197,7 +197,7 @@ LIBC_INLINE T hypot(T x, T y) {
|
||||
if (int round_mode = quick_get_round();
|
||||
round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
|
||||
return T(FPBits_t::inf());
|
||||
return T(FPBits_t(FPBits_t::MAX_NORMAL));
|
||||
return T(FPBits_t::max_normal());
|
||||
}
|
||||
} else {
|
||||
// For denormal result, we simply move the leading bit of the result to
|
||||
@ -254,7 +254,7 @@ LIBC_INLINE T hypot(T x, T y) {
|
||||
if (out_exp >= FPBits_t::MAX_BIASED_EXPONENT) {
|
||||
if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
|
||||
return T(FPBits_t::inf());
|
||||
return T(FPBits_t(FPBits_t::MAX_NORMAL));
|
||||
return T(FPBits_t::max_normal());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ LIBC_INLINE T logb(T x) {
|
||||
return x;
|
||||
} else if (bits.is_inf()) {
|
||||
// Return positive infinity.
|
||||
return T(FPBits<T>::inf(Sign::POS));
|
||||
return T(FPBits<T>::inf());
|
||||
}
|
||||
|
||||
NormalFloat<T> normal(bits);
|
||||
@ -127,7 +127,7 @@ LIBC_INLINE T ldexp(T x, int exp) {
|
||||
// that adding |exp| to it does not lead to integer rollover. But, if |exp|
|
||||
// value is larger the exponent range for type T, then we can return infinity
|
||||
// early. Because the result of the ldexp operation can be a subnormal number,
|
||||
// we need to accommodate the (mantissaWidht + 1) worth of shift in
|
||||
// we need to accommodate the (mantissaWidth + 1) worth of shift in
|
||||
// calculating the limit.
|
||||
int exp_limit = FPBits<T>::MAX_BIASED_EXPONENT + FPBits<T>::FRACTION_LEN + 1;
|
||||
if (exp > exp_limit)
|
||||
@ -164,26 +164,22 @@ LIBC_INLINE T nextafter(T from, U to) {
|
||||
return static_cast<T>(to);
|
||||
|
||||
using StorageType = typename FPBits<T>::StorageType;
|
||||
StorageType int_val = from_bits.uintval();
|
||||
if (from != FPBits<T>::zero()) {
|
||||
if ((static_cast<U>(from) < to) == (from > FPBits<T>::zero())) {
|
||||
++int_val;
|
||||
if (from != T(0)) {
|
||||
if ((static_cast<U>(from) < to) == (from > T(0))) {
|
||||
from_bits = FPBits<T>(StorageType(from_bits.uintval() + 1));
|
||||
} else {
|
||||
--int_val;
|
||||
from_bits = FPBits<T>(StorageType(from_bits.uintval() - 1));
|
||||
}
|
||||
} else {
|
||||
int_val = FPBits<T>::MIN_SUBNORMAL;
|
||||
if (to_bits.is_neg())
|
||||
int_val |= FPBits<T>::SIGN_MASK;
|
||||
from_bits = FPBits<T>::min_subnormal(to_bits.sign());
|
||||
}
|
||||
|
||||
StorageType exponent_bits = int_val & FPBits<T>::EXP_MASK;
|
||||
if (exponent_bits == StorageType(0))
|
||||
if (from_bits.is_subnormal())
|
||||
raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
|
||||
else if (exponent_bits == FPBits<T>::EXP_MASK)
|
||||
else if (from_bits.is_inf())
|
||||
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
|
||||
|
||||
return cpp::bit_cast<T>(int_val);
|
||||
return from_bits.get_val();
|
||||
}
|
||||
|
||||
} // namespace fputil
|
||||
|
@ -215,7 +215,7 @@ template <> LIBC_INLINE NormalFloat<long double>::operator long double() const {
|
||||
// Max exponent is of the form 0xFF...E. That is why -2 and not -1.
|
||||
constexpr int MAX_EXPONENT_VALUE = (1 << LDBits::EXP_LEN) - 2;
|
||||
if (biased_exponent > MAX_EXPONENT_VALUE) {
|
||||
return LDBits::inf(sign);
|
||||
return LDBits::inf(sign).get_val();
|
||||
}
|
||||
|
||||
FPBits<long double> result(0.0l);
|
||||
|
@ -93,7 +93,7 @@ template <size_t Bits> struct DyadicFloat {
|
||||
return 0.0;
|
||||
|
||||
// Assume that it is normalized, and output is also normal.
|
||||
constexpr uint32_t PRECISION = FPBits<T>::MANTISSA_PRECISION;
|
||||
constexpr uint32_t PRECISION = FPBits<T>::FRACTION_LEN + 1;
|
||||
using output_bits_t = typename FPBits<T>::StorageType;
|
||||
|
||||
int exp_hi = exponent + static_cast<int>((Bits - 1) + FPBits<T>::EXP_BIAS);
|
||||
|
@ -102,15 +102,13 @@ template <typename T, size_t N> struct ExceptValues {
|
||||
// Helper functions to set results for exceptional cases.
|
||||
template <typename T> LIBC_INLINE T round_result_slightly_down(T value_rn) {
|
||||
volatile T tmp = value_rn;
|
||||
const T MIN_NORMAL = FPBits<T>::min_normal();
|
||||
tmp = tmp - MIN_NORMAL;
|
||||
tmp -= FPBits<T>::min_normal().get_val();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <typename T> LIBC_INLINE T round_result_slightly_up(T value_rn) {
|
||||
volatile T tmp = value_rn;
|
||||
const T MIN_NORMAL = FPBits<T>::min_normal();
|
||||
tmp = tmp + MIN_NORMAL;
|
||||
tmp += FPBits<T>::min_normal().get_val();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@ -130,9 +130,9 @@ template <> LIBC_INLINE double fma<double>(double x, double y, double z) {
|
||||
return x * y + z;
|
||||
|
||||
// Extract mantissa and append hidden leading bits.
|
||||
UInt128 x_mant = x_bits.get_mantissa() | FPBits::MIN_NORMAL;
|
||||
UInt128 y_mant = y_bits.get_mantissa() | FPBits::MIN_NORMAL;
|
||||
UInt128 z_mant = z_bits.get_mantissa() | FPBits::MIN_NORMAL;
|
||||
UInt128 x_mant = x_bits.get_explicit_mantissa();
|
||||
UInt128 y_mant = y_bits.get_explicit_mantissa();
|
||||
UInt128 z_mant = z_bits.get_explicit_mantissa();
|
||||
|
||||
// If the exponent of the product x*y > the exponent of z, then no extra
|
||||
// precision beside the entire product x*y is needed. On the other hand, when
|
||||
@ -255,9 +255,7 @@ template <> LIBC_INLINE double fma<double>(double x, double y, double z) {
|
||||
if ((round_mode == FE_TOWARDZERO) ||
|
||||
(round_mode == FE_UPWARD && prod_sign.is_neg()) ||
|
||||
(round_mode == FE_DOWNWARD && prod_sign.is_pos())) {
|
||||
result = FPBits::MAX_NORMAL;
|
||||
return prod_sign.is_neg() ? -cpp::bit_cast<double>(result)
|
||||
: cpp::bit_cast<double>(result);
|
||||
return FPBits::max_normal(prod_sign).get_val();
|
||||
}
|
||||
return static_cast<double>(FPBits::inf(prod_sign));
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ template <typename T> struct FModExceptionalInputHandler {
|
||||
|
||||
LIBC_INLINE static bool pre_check(T x, T y, T &out) {
|
||||
using FPB = fputil::FPBits<T>;
|
||||
const T quiet_nan = FPB::build_quiet_nan(0);
|
||||
const T quiet_nan = FPB::build_quiet_nan().get_val();
|
||||
FPB sx(x), sy(y);
|
||||
if (LIBC_LIKELY(!sy.is_zero() && !sy.is_inf_or_nan() &&
|
||||
!sx.is_inf_or_nan())) {
|
||||
|
@ -71,15 +71,19 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
|
||||
return x86::sqrt(x);
|
||||
} else {
|
||||
// IEEE floating points formats.
|
||||
using StorageType = typename FPBits<T>::StorageType;
|
||||
constexpr StorageType ONE = StorageType(1) << FPBits<T>::FRACTION_LEN;
|
||||
using Sign = fputil::Sign;
|
||||
using FPBits_t = typename fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits_t::StorageType;
|
||||
constexpr StorageType ONE = StorageType(1) << FPBits_t::FRACTION_LEN;
|
||||
constexpr auto FLT_NAN =
|
||||
FPBits_t::build_quiet_nan(Sign::POS, ONE >> 1).get_val();
|
||||
|
||||
FPBits<T> bits(x);
|
||||
FPBits_t bits(x);
|
||||
|
||||
if (bits.is_inf_or_nan()) {
|
||||
if (bits.is_neg() && (bits.get_mantissa() == 0)) {
|
||||
// sqrt(-Inf) = NaN
|
||||
return FPBits<T>::build_quiet_nan(ONE >> 1);
|
||||
return FLT_NAN;
|
||||
} else {
|
||||
// sqrt(NaN) = NaN
|
||||
// sqrt(+Inf) = +Inf
|
||||
@ -91,7 +95,7 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
|
||||
return x;
|
||||
} else if (bits.is_neg()) {
|
||||
// sqrt( negative numbers ) = NaN
|
||||
return FPBits<T>::build_quiet_nan(ONE >> 1);
|
||||
return FLT_NAN;
|
||||
} else {
|
||||
int x_exp = bits.get_exponent();
|
||||
StorageType x_mant = bits.get_mantissa();
|
||||
@ -145,10 +149,10 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
|
||||
}
|
||||
|
||||
// Remove hidden bit and append the exponent field.
|
||||
x_exp = ((x_exp >> 1) + FPBits<T>::EXP_BIAS);
|
||||
x_exp = ((x_exp >> 1) + FPBits_t::EXP_BIAS);
|
||||
|
||||
y = (y - ONE) |
|
||||
(static_cast<StorageType>(x_exp) << FPBits<T>::FRACTION_LEN);
|
||||
(static_cast<StorageType>(x_exp) << FPBits_t::FRACTION_LEN);
|
||||
|
||||
switch (quick_get_round()) {
|
||||
case FE_TONEAREST:
|
||||
|
@ -38,14 +38,16 @@ LIBC_INLINE long double sqrt(long double x);
|
||||
LIBC_INLINE long double sqrt(long double x) {
|
||||
using LDBits = FPBits<long double>;
|
||||
using StorageType = typename LDBits::StorageType;
|
||||
using Sign = fputil::Sign;
|
||||
constexpr StorageType ONE = StorageType(1) << int(LDBits::FRACTION_LEN);
|
||||
constexpr auto LDNAN = LDBits::build_quiet_nan(Sign::POS, ONE >> 1).get_val();
|
||||
|
||||
FPBits<long double> bits(x);
|
||||
LDBits bits(x);
|
||||
|
||||
if (bits.is_inf_or_nan()) {
|
||||
if (bits.is_neg() && (bits.get_mantissa() == 0)) {
|
||||
// sqrt(-Inf) = NaN
|
||||
return LDBits::build_quiet_nan(ONE >> 1);
|
||||
return LDNAN;
|
||||
} else {
|
||||
// sqrt(NaN) = NaN
|
||||
// sqrt(+Inf) = +Inf
|
||||
@ -57,7 +59,7 @@ LIBC_INLINE long double sqrt(long double x) {
|
||||
return x;
|
||||
} else if (bits.is_neg()) {
|
||||
// sqrt( negative numbers ) = NaN
|
||||
return LDBits::build_quiet_nan(ONE >> 1);
|
||||
return LDNAN;
|
||||
} else {
|
||||
int x_exp = bits.get_explicit_exponent();
|
||||
StorageType x_mant = bits.get_mantissa();
|
||||
|
@ -43,16 +43,18 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
|
||||
}
|
||||
|
||||
using StorageType = FPBits::StorageType;
|
||||
constexpr StorageType SIGN_VAL = (StorageType(1) << 79);
|
||||
|
||||
constexpr StorageType FRACTION_MASK = FPBits::FRACTION_MASK;
|
||||
StorageType int_val = from_bits.uintval();
|
||||
if (from < 0.0l) {
|
||||
if (from > to) {
|
||||
if (int_val == (SIGN_VAL + FPBits::MAX_SUBNORMAL)) {
|
||||
// StorageType int_val = from_bits.uintval();
|
||||
if (from == 0.0l) { // +0.0 / -0.0
|
||||
from_bits = FPBits::min_subnormal(from > to ? Sign::NEG : Sign::POS);
|
||||
} else if (from < 0.0l) {
|
||||
if (to < from) { // toward -inf
|
||||
if (from_bits == FPBits::max_subnormal(Sign::NEG)) {
|
||||
// We deal with normal/subnormal boundary separately to avoid
|
||||
// dealing with the implicit bit.
|
||||
int_val = SIGN_VAL + FPBits::MIN_NORMAL;
|
||||
} else if ((int_val & FRACTION_MASK) == FRACTION_MASK) {
|
||||
from_bits = FPBits::min_normal(Sign::NEG);
|
||||
} else if (from_bits.get_mantissa() == FRACTION_MASK) {
|
||||
from_bits.set_mantissa(0);
|
||||
// Incrementing exponent might overflow the value to infinity,
|
||||
// which is what is expected. Since NaNs are handling separately,
|
||||
@ -62,45 +64,40 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
|
||||
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
|
||||
return from_bits.get_val();
|
||||
} else {
|
||||
++int_val;
|
||||
from_bits = FPBits(StorageType(from_bits.uintval() + 1));
|
||||
}
|
||||
} else {
|
||||
if (int_val == (SIGN_VAL + FPBits::MIN_NORMAL)) {
|
||||
} else { // toward +inf
|
||||
if (from_bits == FPBits::min_normal(Sign::NEG)) {
|
||||
// We deal with normal/subnormal boundary separately to avoid
|
||||
// dealing with the implicit bit.
|
||||
int_val = SIGN_VAL + FPBits::MAX_SUBNORMAL;
|
||||
} else if ((int_val & FRACTION_MASK) == 0) {
|
||||
from_bits = FPBits::max_subnormal(Sign::NEG);
|
||||
} else if (from_bits.get_mantissa() == 0) {
|
||||
from_bits.set_mantissa(FRACTION_MASK);
|
||||
// from == 0 is handled separately so decrementing the exponent will not
|
||||
// lead to underflow.
|
||||
from_bits.set_biased_exponent(from_bits.get_biased_exponent() - 1);
|
||||
return from_bits.get_val();
|
||||
} else {
|
||||
--int_val;
|
||||
from_bits = FPBits(StorageType(from_bits.uintval() - 1));
|
||||
}
|
||||
}
|
||||
} else if (from == 0.0l) {
|
||||
if (from > to)
|
||||
int_val = SIGN_VAL + 1;
|
||||
else
|
||||
int_val = 1;
|
||||
} else {
|
||||
if (from > to) {
|
||||
if (int_val == FPBits::MIN_NORMAL) {
|
||||
int_val = FPBits::MAX_SUBNORMAL;
|
||||
} else if ((int_val & FRACTION_MASK) == 0) {
|
||||
if (to < from) { // toward -inf
|
||||
if (from_bits == FPBits::min_normal(Sign::POS)) {
|
||||
from_bits = FPBits::max_subnormal(Sign::POS);
|
||||
} else if (from_bits.get_mantissa() == 0) {
|
||||
from_bits.set_mantissa(FRACTION_MASK);
|
||||
// from == 0 is handled separately so decrementing the exponent will not
|
||||
// lead to underflow.
|
||||
from_bits.set_biased_exponent(from_bits.get_biased_exponent() - 1);
|
||||
return from_bits.get_val();
|
||||
} else {
|
||||
--int_val;
|
||||
from_bits = FPBits(StorageType(from_bits.uintval() - 1));
|
||||
}
|
||||
} else {
|
||||
if (int_val == FPBits::MAX_SUBNORMAL) {
|
||||
int_val = FPBits::MIN_NORMAL;
|
||||
} else if ((int_val & FRACTION_MASK) == FRACTION_MASK) {
|
||||
} else { // toward +inf
|
||||
if (from_bits == FPBits::max_subnormal(Sign::POS)) {
|
||||
from_bits = FPBits::min_normal(Sign::POS);
|
||||
} else if (from_bits.get_mantissa() == FRACTION_MASK) {
|
||||
from_bits.set_mantissa(0);
|
||||
// Incrementing exponent might overflow the value to infinity,
|
||||
// which is what is expected. Since NaNs are handling separately,
|
||||
@ -110,16 +107,15 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
|
||||
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
|
||||
return from_bits.get_val();
|
||||
} else {
|
||||
++int_val;
|
||||
from_bits = FPBits(StorageType(from_bits.uintval() + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StorageType implicit_bit = int_val & (StorageType(1) << FPBits::FRACTION_LEN);
|
||||
if (implicit_bit == StorageType(0))
|
||||
if (!from_bits.get_implicit_bit())
|
||||
raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
|
||||
|
||||
return cpp::bit_cast<long double>(int_val);
|
||||
return from_bits.get_val();
|
||||
}
|
||||
|
||||
} // namespace fputil
|
||||
|
@ -25,7 +25,6 @@
|
||||
#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) \
|
||||
LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) \
|
||||
__##name##_impl__ __asm__(#name); \
|
||||
decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]]; \
|
||||
type __##name##_impl__ arglist
|
||||
#else
|
||||
#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) type name arglist
|
||||
|
@ -1167,7 +1167,7 @@ LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) {
|
||||
index = left_paren;
|
||||
}
|
||||
}
|
||||
result = FPBits(result.build_quiet_nan(nan_mantissa, result.sign()));
|
||||
result = FPBits(result.build_quiet_nan(result.sign(), nan_mantissa));
|
||||
}
|
||||
} else if (tolower(src[index]) == 'i') { // INF
|
||||
if (tolower(src[index + 1]) == inf_string[1] &&
|
||||
@ -1215,7 +1215,7 @@ template <class T> LIBC_INLINE StrToNumResult<T> strtonan(const char *arg) {
|
||||
nan_mantissa = static_cast<StorageType>(nan_mantissa_result);
|
||||
}
|
||||
|
||||
result = FPBits(result.build_quiet_nan(nan_mantissa));
|
||||
result = FPBits::build_quiet_nan(fputil::Sign::POS, nan_mantissa);
|
||||
return {T(result), 0, error};
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ LLVM_LIBC_FUNCTION(float, acosf, (float x)) {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
}
|
||||
return x + FPBits::build_quiet_nan(0);
|
||||
return x + FPBits::build_quiet_nan().get_val();
|
||||
}
|
||||
|
||||
// When 0.5 < |x| < 1, we perform range reduction as follow:
|
||||
|
@ -29,7 +29,7 @@ LLVM_LIBC_FUNCTION(float, acoshf, (float x)) {
|
||||
// x < 1.
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
return FPBits_t::build_quiet_nan(0);
|
||||
return FPBits_t::build_quiet_nan().get_val();
|
||||
}
|
||||
|
||||
if (LIBC_UNLIKELY(x_u >= 0x4f8ffb03)) {
|
||||
|
@ -109,7 +109,7 @@ LLVM_LIBC_FUNCTION(float, asinf, (float x)) {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
}
|
||||
return x + FPBits::build_nan(FPBits::FRACTION_MASK);
|
||||
return x + FPBits::build_nan(Sign::POS, FPBits::FRACTION_MASK).get_val();
|
||||
}
|
||||
|
||||
// Check for exceptional values
|
||||
|
@ -29,11 +29,11 @@ LLVM_LIBC_FUNCTION(float, atanhf, (float x)) {
|
||||
if (x_abs == 0x3F80'0000U) {
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_DIVBYZERO);
|
||||
return FPBits::inf(sign);
|
||||
return FPBits::inf(sign).get_val();
|
||||
} else {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
return FPBits::build_quiet_nan(0);
|
||||
return FPBits::build_quiet_nan().get_val();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ LLVM_LIBC_FUNCTION(float, cosf, (float x)) {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
}
|
||||
return x + FPBits::build_quiet_nan(0);
|
||||
return x + FPBits::build_quiet_nan().get_val();
|
||||
}
|
||||
|
||||
// Combine the results with the sine of sum formula:
|
||||
|
@ -32,16 +32,16 @@ LLVM_LIBC_FUNCTION(float, coshf, (float x)) {
|
||||
}
|
||||
|
||||
if (xbits.is_inf_or_nan())
|
||||
return x + FPBits::inf();
|
||||
return x + FPBits::inf().get_val();
|
||||
|
||||
int rounding = fputil::quick_get_round();
|
||||
if (LIBC_UNLIKELY(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO))
|
||||
return FPBits::max_normal();
|
||||
return FPBits::max_normal().get_val();
|
||||
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_OVERFLOW);
|
||||
|
||||
return x + FPBits::inf();
|
||||
return x + FPBits::inf().get_val();
|
||||
}
|
||||
|
||||
// TODO: We should be able to reduce the latency and reciprocal throughput
|
||||
|
@ -205,7 +205,7 @@ double set_exceptional(double x) {
|
||||
return x;
|
||||
|
||||
if (fputil::quick_get_round() == FE_UPWARD)
|
||||
return FPBits::min_denormal();
|
||||
return FPBits::min_subnormal().get_val();
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_UNDERFLOW);
|
||||
return 0.0;
|
||||
@ -216,7 +216,7 @@ double set_exceptional(double x) {
|
||||
if (x_u < 0x7ff0'0000'0000'0000ULL) {
|
||||
int rounding = fputil::quick_get_round();
|
||||
if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
|
||||
return FPBits::max_normal();
|
||||
return FPBits::max_normal().get_val();
|
||||
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_OVERFLOW);
|
||||
|
@ -248,7 +248,7 @@ double set_exceptional(double x) {
|
||||
return x;
|
||||
|
||||
if (fputil::quick_get_round() == FE_UPWARD)
|
||||
return FPBits::min_denormal();
|
||||
return FPBits::min_subnormal().get_val();
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_UNDERFLOW);
|
||||
return 0.0;
|
||||
@ -262,7 +262,7 @@ double set_exceptional(double x) {
|
||||
if (x_u < 0x7ff0'0000'0000'0000ULL) {
|
||||
int rounding = fputil::quick_get_round();
|
||||
if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
|
||||
return FPBits::max_normal();
|
||||
return FPBits::max_normal().get_val();
|
||||
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_OVERFLOW);
|
||||
|
@ -42,7 +42,7 @@ LIBC_INLINE float exp10f(float x) {
|
||||
if (xbits.is_nan())
|
||||
return x;
|
||||
if (fputil::fenv_is_round_up())
|
||||
return FPBits::min_denormal();
|
||||
return FPBits::min_subnormal().get_val();
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_UNDERFLOW);
|
||||
return 0.0f;
|
||||
@ -53,13 +53,13 @@ LIBC_INLINE float exp10f(float x) {
|
||||
if (x_u < 0x7f80'0000U) {
|
||||
int rounding = fputil::quick_get_round();
|
||||
if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
|
||||
return FPBits::max_normal();
|
||||
return FPBits::max_normal().get_val();
|
||||
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_OVERFLOW);
|
||||
}
|
||||
// x is +inf or nan
|
||||
return x + FPBits::inf();
|
||||
return x + FPBits::inf().get_val();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,7 @@ double set_exceptional(double x) {
|
||||
return x;
|
||||
|
||||
if (fputil::quick_get_round() == FE_UPWARD)
|
||||
return FPBits::min_denormal();
|
||||
return FPBits::min_subnormal().get_val();
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_UNDERFLOW);
|
||||
return 0.0;
|
||||
@ -237,7 +237,7 @@ double set_exceptional(double x) {
|
||||
if (x_u < 0x7ff0'0000'0000'0000ULL) {
|
||||
int rounding = fputil::quick_get_round();
|
||||
if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
|
||||
return FPBits::max_normal();
|
||||
return FPBits::max_normal().get_val();
|
||||
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_OVERFLOW);
|
||||
|
@ -76,13 +76,13 @@ LIBC_INLINE float exp2f(float x) {
|
||||
if (x_u < 0x7f80'0000U) {
|
||||
int rounding = fputil::quick_get_round();
|
||||
if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
|
||||
return FPBits::max_normal();
|
||||
return FPBits::max_normal().get_val();
|
||||
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_OVERFLOW);
|
||||
}
|
||||
// x is +inf or nan
|
||||
return x + FPBits::inf();
|
||||
return x + FPBits::inf().get_val();
|
||||
}
|
||||
// x <= -150
|
||||
if (x_u >= 0xc316'0000U) {
|
||||
@ -93,7 +93,7 @@ LIBC_INLINE float exp2f(float x) {
|
||||
if (xbits.is_nan())
|
||||
return x;
|
||||
if (fputil::fenv_is_round_up())
|
||||
return FPBits::min_denormal();
|
||||
return FPBits::min_subnormal().get_val();
|
||||
if (x != 0.0f) {
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_UNDERFLOW);
|
||||
|
@ -50,7 +50,7 @@ LLVM_LIBC_FUNCTION(float, expf, (float x)) {
|
||||
if (xbits.is_nan())
|
||||
return x;
|
||||
if (fputil::fenv_is_round_up())
|
||||
return FPBits::min_denormal();
|
||||
return FPBits::min_subnormal().get_val();
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_UNDERFLOW);
|
||||
return 0.0f;
|
||||
@ -61,7 +61,7 @@ LLVM_LIBC_FUNCTION(float, expf, (float x)) {
|
||||
if (xbits.uintval() < 0x7f80'0000U) {
|
||||
int rounding = fputil::quick_get_round();
|
||||
if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
|
||||
return FPBits::max_normal();
|
||||
return FPBits::max_normal().get_val();
|
||||
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_OVERFLOW);
|
||||
|
@ -267,13 +267,13 @@ double set_exceptional(double x) {
|
||||
if (x_u < 0x7ff0'0000'0000'0000ULL) {
|
||||
int rounding = fputil::quick_get_round();
|
||||
if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
|
||||
return FPBits::max_normal();
|
||||
return FPBits::max_normal().get_val();
|
||||
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_OVERFLOW);
|
||||
}
|
||||
// x is +inf or nan
|
||||
return x + static_cast<double>(FPBits::inf());
|
||||
return x + FPBits::inf().get_val();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -68,12 +68,12 @@ LLVM_LIBC_FUNCTION(float, expm1f, (float x)) {
|
||||
if (xbits.uintval() < 0x7f80'0000U) {
|
||||
int rounding = fputil::quick_get_round();
|
||||
if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
|
||||
return FPBits::max_normal();
|
||||
return FPBits::max_normal().get_val();
|
||||
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_OVERFLOW);
|
||||
}
|
||||
return x + static_cast<float>(FPBits::inf());
|
||||
return x + FPBits::inf().get_val();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -732,28 +732,29 @@ double log_accurate(int e_x, int index, double m_x) {
|
||||
|
||||
LLVM_LIBC_FUNCTION(double, log, (double x)) {
|
||||
using FPBits_t = typename fputil::FPBits<double>;
|
||||
using Sign = fputil::Sign;
|
||||
FPBits_t xbits(x);
|
||||
uint64_t x_u = xbits.uintval();
|
||||
|
||||
int x_e = -FPBits_t::EXP_BIAS;
|
||||
|
||||
if (LIBC_UNLIKELY(x_u == 0x3FF0'0000'0000'0000ULL)) {
|
||||
if (LIBC_UNLIKELY(xbits == FPBits_t::one())) {
|
||||
// log(1.0) = +0.0
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::MIN_NORMAL ||
|
||||
xbits.uintval() > FPBits_t::MAX_NORMAL)) {
|
||||
if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() ||
|
||||
xbits.uintval() > FPBits_t::max_normal().uintval())) {
|
||||
if (xbits.is_zero()) {
|
||||
// return -Inf and raise FE_DIVBYZERO.
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_DIVBYZERO);
|
||||
return static_cast<double>(FPBits_t::inf(fputil::Sign::NEG));
|
||||
return FPBits_t::inf(Sign::NEG).get_val();
|
||||
}
|
||||
if (xbits.is_neg() && !xbits.is_nan()) {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
return FPBits_t::build_quiet_nan(0);
|
||||
return FPBits_t::build_quiet_nan().get_val();
|
||||
}
|
||||
if (xbits.is_inf_or_nan()) {
|
||||
return x;
|
||||
|
@ -733,28 +733,29 @@ double log10_accurate(int e_x, int index, double m_x) {
|
||||
|
||||
LLVM_LIBC_FUNCTION(double, log10, (double x)) {
|
||||
using FPBits_t = typename fputil::FPBits<double>;
|
||||
using Sign = fputil::Sign;
|
||||
FPBits_t xbits(x);
|
||||
uint64_t x_u = xbits.uintval();
|
||||
|
||||
int x_e = -FPBits_t::EXP_BIAS;
|
||||
|
||||
if (LIBC_UNLIKELY(x_u == 0x3FF0'0000'0000'0000ULL)) {
|
||||
if (LIBC_UNLIKELY(xbits == FPBits_t::one())) {
|
||||
// log10(1.0) = +0.0
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::MIN_NORMAL ||
|
||||
xbits.uintval() > FPBits_t::MAX_NORMAL)) {
|
||||
if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() ||
|
||||
xbits.uintval() > FPBits_t::max_normal().uintval())) {
|
||||
if (xbits.is_zero()) {
|
||||
// return -Inf and raise FE_DIVBYZERO.
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_DIVBYZERO);
|
||||
return static_cast<double>(FPBits_t::inf(fputil::Sign::NEG));
|
||||
return FPBits_t::inf(Sign::NEG).get_val();
|
||||
}
|
||||
if (xbits.is_neg() && !xbits.is_nan()) {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
return FPBits_t::build_quiet_nan(0);
|
||||
return FPBits_t::build_quiet_nan().get_val();
|
||||
}
|
||||
if (xbits.is_inf_or_nan()) {
|
||||
return x;
|
||||
|
@ -106,6 +106,7 @@ LLVM_LIBC_FUNCTION(float, log10f, (float x)) {
|
||||
constexpr double LOG10_2 = 0x1.34413509f79ffp-2;
|
||||
|
||||
using FPBits = typename fputil::FPBits<float>;
|
||||
using Sign = fputil::Sign;
|
||||
FPBits xbits(x);
|
||||
uint32_t x_u = xbits.uintval();
|
||||
|
||||
@ -160,18 +161,19 @@ LLVM_LIBC_FUNCTION(float, log10f, (float x)) {
|
||||
|
||||
int m = -FPBits::EXP_BIAS;
|
||||
|
||||
if (LIBC_UNLIKELY(x_u < FPBits::MIN_NORMAL || x_u > FPBits::MAX_NORMAL)) {
|
||||
if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval() ||
|
||||
x_u > FPBits::max_normal().uintval())) {
|
||||
if (xbits.is_zero()) {
|
||||
// Return -inf and raise FE_DIVBYZERO
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_DIVBYZERO);
|
||||
return static_cast<float>(FPBits::inf(fputil::Sign::NEG));
|
||||
return FPBits::inf(Sign::NEG).get_val();
|
||||
}
|
||||
if (xbits.is_neg() && !xbits.is_nan()) {
|
||||
// Return NaN and raise FE_INVALID
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
return FPBits::build_quiet_nan(0);
|
||||
return FPBits::build_quiet_nan().get_val();
|
||||
}
|
||||
if (xbits.is_inf_or_nan()) {
|
||||
return x;
|
||||
|
@ -873,6 +873,7 @@ LIBC_INLINE double log1p_accurate(int e_x, int index,
|
||||
|
||||
LLVM_LIBC_FUNCTION(double, log1p, (double x)) {
|
||||
using FPBits_t = typename fputil::FPBits<double>;
|
||||
using Sign = fputil::Sign;
|
||||
constexpr int EXP_BIAS = FPBits_t::EXP_BIAS;
|
||||
constexpr int FRACTION_LEN = FPBits_t::FRACTION_LEN;
|
||||
constexpr uint64_t FRACTION_MASK = FPBits_t::FRACTION_MASK;
|
||||
@ -887,19 +888,19 @@ LLVM_LIBC_FUNCTION(double, log1p, (double x)) {
|
||||
// |x| >= 1
|
||||
if (LIBC_UNLIKELY(x_u >= 0x4650'0000'0000'0000ULL)) {
|
||||
// x >= 2^102 or x is negative, inf, or NaN
|
||||
if (LIBC_UNLIKELY(x_u > FPBits_t::MAX_NORMAL)) {
|
||||
if (LIBC_UNLIKELY(x_u > FPBits_t::max_normal().uintval())) {
|
||||
// x <= -1.0 or x is Inf or NaN
|
||||
if (x_u == 0xbff0'0000'0000'0000ULL) {
|
||||
// x = -1.0
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_DIVBYZERO);
|
||||
return static_cast<double>(FPBits_t::inf(fputil::Sign::NEG));
|
||||
return FPBits_t::inf(Sign::NEG).get_val();
|
||||
}
|
||||
if (xbits.is_neg() && !xbits.is_nan()) {
|
||||
// x < -1.0
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
return FPBits_t::build_quiet_nan(0);
|
||||
return FPBits_t::build_quiet_nan().get_val();
|
||||
}
|
||||
// x is +Inf or NaN
|
||||
return x;
|
||||
|
@ -43,11 +43,11 @@ LIBC_INLINE float log(double x) {
|
||||
|
||||
uint64_t x_u = xbits.uintval();
|
||||
|
||||
if (LIBC_UNLIKELY(x_u > FPBits::MAX_NORMAL)) {
|
||||
if (LIBC_UNLIKELY(x_u > FPBits::max_normal().uintval())) {
|
||||
if (xbits.is_neg() && !xbits.is_nan()) {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
return fputil::FPBits<float>::build_quiet_nan(0);
|
||||
return fputil::FPBits<float>::build_quiet_nan().get_val();
|
||||
}
|
||||
return static_cast<float>(x);
|
||||
}
|
||||
|
@ -854,28 +854,29 @@ double log2_accurate(int e_x, int index, double m_x) {
|
||||
|
||||
LLVM_LIBC_FUNCTION(double, log2, (double x)) {
|
||||
using FPBits_t = typename fputil::FPBits<double>;
|
||||
using Sign = fputil::Sign;
|
||||
FPBits_t xbits(x);
|
||||
uint64_t x_u = xbits.uintval();
|
||||
|
||||
int x_e = -FPBits_t::EXP_BIAS;
|
||||
|
||||
if (LIBC_UNLIKELY(x_u == 0x3FF0'0000'0000'0000ULL)) {
|
||||
if (LIBC_UNLIKELY(xbits == FPBits_t::one())) {
|
||||
// log2(1.0) = +0.0
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::MIN_NORMAL ||
|
||||
xbits.uintval() > FPBits_t::MAX_NORMAL)) {
|
||||
if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() ||
|
||||
xbits.uintval() > FPBits_t::max_normal().uintval())) {
|
||||
if (xbits.is_zero()) {
|
||||
// return -Inf and raise FE_DIVBYZERO.
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_DIVBYZERO);
|
||||
return static_cast<double>(FPBits_t::inf(fputil::Sign::NEG));
|
||||
return FPBits_t::inf(Sign::NEG).get_val();
|
||||
}
|
||||
if (xbits.is_neg() && !xbits.is_nan()) {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
return FPBits_t::build_quiet_nan(0);
|
||||
return FPBits_t::build_quiet_nan().get_val();
|
||||
}
|
||||
if (xbits.is_inf_or_nan()) {
|
||||
return x;
|
||||
|
@ -55,6 +55,7 @@ namespace LIBC_NAMESPACE {
|
||||
|
||||
LLVM_LIBC_FUNCTION(float, log2f, (float x)) {
|
||||
using FPBits = typename fputil::FPBits<float>;
|
||||
using Sign = fputil::Sign;
|
||||
FPBits xbits(x);
|
||||
uint32_t x_u = xbits.uintval();
|
||||
|
||||
@ -68,16 +69,17 @@ LLVM_LIBC_FUNCTION(float, log2f, (float x)) {
|
||||
return 0.0f;
|
||||
|
||||
// Exceptional inputs.
|
||||
if (LIBC_UNLIKELY(x_u < FPBits::MIN_NORMAL || x_u > FPBits::MAX_NORMAL)) {
|
||||
if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval() ||
|
||||
x_u > FPBits::max_normal().uintval())) {
|
||||
if (xbits.is_zero()) {
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_DIVBYZERO);
|
||||
return static_cast<float>(FPBits::inf(fputil::Sign::NEG));
|
||||
return FPBits::inf(Sign::NEG).get_val();
|
||||
}
|
||||
if (xbits.is_neg() && !xbits.is_nan()) {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except(FE_INVALID);
|
||||
return FPBits::build_quiet_nan(0);
|
||||
return FPBits::build_quiet_nan().get_val();
|
||||
}
|
||||
if (xbits.is_inf_or_nan()) {
|
||||
return x;
|
||||
|
@ -54,6 +54,7 @@ namespace LIBC_NAMESPACE {
|
||||
LLVM_LIBC_FUNCTION(float, logf, (float x)) {
|
||||
constexpr double LOG_2 = 0x1.62e42fefa39efp-1;
|
||||
using FPBits = typename fputil::FPBits<float>;
|
||||
using Sign = fputil::Sign;
|
||||
FPBits xbits(x);
|
||||
uint32_t x_u = xbits.uintval();
|
||||
|
||||
@ -79,7 +80,7 @@ LLVM_LIBC_FUNCTION(float, logf, (float x)) {
|
||||
#endif // LIBC_TARGET_CPU_HAS_FMA
|
||||
}
|
||||
// Subnormal inputs.
|
||||
if (LIBC_UNLIKELY(x_u < FPBits::MIN_NORMAL)) {
|
||||
if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval())) {
|
||||
if (x_u == 0) {
|
||||
// Return -inf and raise FE_DIVBYZERO
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
@ -112,18 +113,18 @@ LLVM_LIBC_FUNCTION(float, logf, (float x)) {
|
||||
#endif // LIBC_TARGET_CPU_HAS_FMA
|
||||
}
|
||||
// Exceptional inputs.
|
||||
if (LIBC_UNLIKELY(x_u > FPBits::MAX_NORMAL)) {
|
||||
if (LIBC_UNLIKELY(x_u > FPBits::max_normal().uintval())) {
|
||||
if (x_u == 0x8000'0000U) {
|
||||
// Return -inf and raise FE_DIVBYZERO
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_DIVBYZERO);
|
||||
return static_cast<float>(FPBits::inf(fputil::Sign::NEG));
|
||||
return FPBits::inf(Sign::NEG).get_val();
|
||||
}
|
||||
if (xbits.is_neg() && !xbits.is_nan()) {
|
||||
// Return NaN and raise FE_INVALID
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
return FPBits::build_quiet_nan(0);
|
||||
return FPBits::build_quiet_nan().get_val();
|
||||
}
|
||||
// x is +inf or nan
|
||||
return x;
|
||||
|
@ -547,14 +547,15 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
|
||||
// pow(+-0, -Inf) = +inf and raise FE_DIVBYZERO
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_DIVBYZERO);
|
||||
return FloatBits::inf();
|
||||
return FloatBits::inf().get_val();
|
||||
}
|
||||
// pow (|x| < 1, -inf) = +inf
|
||||
// pow (|x| < 1, +inf) = 0.0f
|
||||
// pow (|x| > 1, -inf) = 0.0f
|
||||
// pow (|x| > 1, +inf) = +inf
|
||||
return ((x_abs < 0x3f80'0000) == (y_u == 0xff80'0000)) ? FloatBits::inf()
|
||||
: 0.0f;
|
||||
return ((x_abs < 0x3f80'0000) == (y_u == 0xff80'0000))
|
||||
? FloatBits::inf().get_val()
|
||||
: 0.0f;
|
||||
}
|
||||
default:
|
||||
// Speed up for common exponents
|
||||
@ -617,7 +618,7 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
|
||||
// pow(0, negative number) = inf
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_DIVBYZERO);
|
||||
return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS);
|
||||
return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS).get_val();
|
||||
}
|
||||
// pow(0, positive number) = 0
|
||||
return out_is_neg ? -0.0f : 0.0f;
|
||||
@ -628,7 +629,7 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
|
||||
if (y_u >= FloatBits::SIGN_MASK) {
|
||||
return out_is_neg ? -0.0f : 0.0f;
|
||||
}
|
||||
return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS);
|
||||
return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS).get_val();
|
||||
}
|
||||
}
|
||||
|
||||
@ -656,7 +657,7 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
|
||||
// pow( negative, non-integer ) = NaN
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
return FloatBits::build_quiet_nan(0);
|
||||
return FloatBits::build_quiet_nan().get_val();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +148,9 @@ LLVM_LIBC_FUNCTION(void, sincosf, (float x, float *sinp, float *cosp)) {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
}
|
||||
*sinp = x + FPBits::build_nan(FPBits::FRACTION_MASK);
|
||||
*sinp =
|
||||
x +
|
||||
FPBits::build_nan(fputil::Sign::POS, FPBits::FRACTION_MASK).get_val();
|
||||
*cosp = *sinp;
|
||||
return;
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ LLVM_LIBC_FUNCTION(float, sinf, (float x)) {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
}
|
||||
return x + FPBits::build_quiet_nan(0);
|
||||
return x + FPBits::build_quiet_nan().get_val();
|
||||
}
|
||||
|
||||
// Combine the results with the sine of sum formula:
|
||||
|
@ -56,16 +56,16 @@ LLVM_LIBC_FUNCTION(float, sinhf, (float x)) {
|
||||
int rounding = fputil::quick_get_round();
|
||||
if (xbits.is_neg()) {
|
||||
if (LIBC_UNLIKELY(rounding == FE_UPWARD || rounding == FE_TOWARDZERO))
|
||||
return -FPBits::max_normal();
|
||||
return -FPBits::max_normal().get_val();
|
||||
} else {
|
||||
if (LIBC_UNLIKELY(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO))
|
||||
return FPBits::max_normal();
|
||||
return FPBits::max_normal().get_val();
|
||||
}
|
||||
|
||||
fputil::set_errno_if_required(ERANGE);
|
||||
fputil::raise_except_if_required(FE_OVERFLOW);
|
||||
|
||||
return x + FPBits::inf(xbits.sign());
|
||||
return x + FPBits::inf(xbits.sign()).get_val();
|
||||
}
|
||||
|
||||
// sinh(x) = (e^x - e^(-x)) / 2.
|
||||
|
@ -114,7 +114,7 @@ LLVM_LIBC_FUNCTION(float, tanf, (float x)) {
|
||||
fputil::set_errno_if_required(EDOM);
|
||||
fputil::raise_except_if_required(FE_INVALID);
|
||||
}
|
||||
return x + FPBits::build_quiet_nan(0);
|
||||
return x + FPBits::build_quiet_nan().get_val();
|
||||
}
|
||||
// Other large exceptional values
|
||||
if (auto r = TANF_EXCEPTS.lookup_odd(x_abs, x_sign);
|
||||
|
@ -66,16 +66,16 @@ template <typename T> struct FPTest : public Test {
|
||||
using Sign = LIBC_NAMESPACE::fputil::Sign;
|
||||
static constexpr StorageType STORAGE_MAX =
|
||||
LIBC_NAMESPACE::cpp::numeric_limits<StorageType>::max();
|
||||
static constexpr T zero = FPBits::zero(Sign::POS);
|
||||
static constexpr T neg_zero = FPBits::zero(Sign::NEG);
|
||||
static constexpr T aNaN = FPBits::build_quiet_nan(1);
|
||||
static constexpr T sNaN = FPBits::build_nan(1);
|
||||
static constexpr T inf = FPBits::inf(Sign::POS);
|
||||
static constexpr T neg_inf = FPBits::inf(Sign::NEG);
|
||||
static constexpr T min_normal = FPBits::min_normal();
|
||||
static constexpr T max_normal = FPBits::max_normal();
|
||||
static constexpr T min_denormal = FPBits::min_denormal();
|
||||
static constexpr T max_denormal = FPBits::max_denormal();
|
||||
static constexpr T zero = T(FPBits::zero(Sign::POS));
|
||||
static constexpr T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
static constexpr T aNaN = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
static constexpr T sNaN = T(FPBits::build_nan(Sign::POS, 1));
|
||||
static constexpr T inf = T(FPBits::inf(Sign::POS));
|
||||
static constexpr T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
static constexpr T min_normal = T(FPBits::min_normal());
|
||||
static constexpr T max_normal = T(FPBits::max_normal());
|
||||
static constexpr T min_denormal = T(FPBits::min_subnormal());
|
||||
static constexpr T max_denormal = T(FPBits::max_subnormal());
|
||||
|
||||
static constexpr int N_ROUNDING_MODES = 4;
|
||||
static constexpr fputil::testing::RoundingMode ROUNDING_MODES[4] = {
|
||||
@ -95,16 +95,16 @@ template <typename T> struct FPTest : public Test {
|
||||
using Sign = LIBC_NAMESPACE::fputil::Sign; \
|
||||
static constexpr StorageType STORAGE_MAX = \
|
||||
LIBC_NAMESPACE::cpp::numeric_limits<StorageType>::max(); \
|
||||
const T zero = FPBits::zero(Sign::POS); \
|
||||
const T neg_zero = FPBits::zero(Sign::NEG); \
|
||||
const T aNaN = FPBits::build_quiet_nan(1); \
|
||||
const T sNaN = FPBits::build_nan(1); \
|
||||
const T inf = FPBits::inf(Sign::POS); \
|
||||
const T neg_inf = FPBits::inf(Sign::NEG); \
|
||||
const T min_normal = FPBits::min_normal(); \
|
||||
const T max_normal = FPBits::max_normal(); \
|
||||
const T min_denormal = FPBits::min_denormal(); \
|
||||
const T max_denormal = FPBits::max_denormal();
|
||||
const T zero = T(FPBits::zero(Sign::POS)); \
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG)); \
|
||||
const T aNaN = T(FPBits::build_quiet_nan(Sign::POS, 1)); \
|
||||
const T sNaN = T(FPBits::build_nan(Sign::POS, 1)); \
|
||||
const T inf = T(FPBits::inf(Sign::POS)); \
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG)); \
|
||||
const T min_normal = T(FPBits::min_normal()); \
|
||||
const T max_normal = T(FPBits::max_normal()); \
|
||||
const T min_denormal = T(FPBits::min_subnormal()); \
|
||||
const T max_denormal = T(FPBits::max_subnormal());
|
||||
|
||||
#define EXPECT_FP_EQ(expected, actual) \
|
||||
EXPECT_THAT(actual, LIBC_NAMESPACE::testing::getMatcher< \
|
||||
|
@ -232,13 +232,11 @@ TEST(LlvmLibcFPBitsTest, FPType_X86_Binary80_IsNan) {
|
||||
TEST(LlvmLibcFPBitsTest, FloatType) {
|
||||
using FloatBits = FPBits<float>;
|
||||
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(FloatBits(FloatBits::inf(Sign::POS))).c_str(),
|
||||
"(+Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(FloatBits(FloatBits::inf(Sign::NEG))).c_str(),
|
||||
"(-Infinity)");
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(FloatBits(FloatBits::build_nan(1))).c_str(),
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(FloatBits::inf(Sign::POS)).c_str(),
|
||||
"(+Infinity)");
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(FloatBits::inf(Sign::NEG)).c_str(),
|
||||
"(-Infinity)");
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(FloatBits::build_nan(Sign::POS, 1)).c_str(),
|
||||
"(NaN)");
|
||||
|
||||
FloatBits zero(0.0f);
|
||||
@ -289,22 +287,19 @@ TEST(LlvmLibcFPBitsTest, FloatType) {
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(negnum).c_str(),
|
||||
"0xBF900000 = (S: 1, E: 0x007F, M: 0x00100000)");
|
||||
|
||||
FloatBits quiet_nan = FloatBits(FloatBits::build_quiet_nan(1));
|
||||
FloatBits quiet_nan = FloatBits::build_quiet_nan(Sign::POS, 1);
|
||||
EXPECT_EQ(quiet_nan.is_quiet_nan(), true);
|
||||
}
|
||||
|
||||
TEST(LlvmLibcFPBitsTest, DoubleType) {
|
||||
using DoubleBits = FPBits<double>;
|
||||
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(DoubleBits(DoubleBits::inf(Sign::POS))).c_str(),
|
||||
"(+Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(DoubleBits(DoubleBits::inf(Sign::NEG))).c_str(),
|
||||
"(-Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(DoubleBits(DoubleBits::build_nan(1))).c_str(),
|
||||
"(NaN)");
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(DoubleBits::inf(Sign::POS)).c_str(),
|
||||
"(+Infinity)");
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(DoubleBits::inf(Sign::NEG)).c_str(),
|
||||
"(-Infinity)");
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(DoubleBits::build_nan(Sign::POS, 1)).c_str(),
|
||||
"(NaN)");
|
||||
|
||||
DoubleBits zero(0.0);
|
||||
EXPECT_TRUE(zero.is_pos());
|
||||
@ -354,7 +349,7 @@ TEST(LlvmLibcFPBitsTest, DoubleType) {
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(negnum).c_str(),
|
||||
"0xBFF2000000000000 = (S: 1, E: 0x03FF, M: 0x0002000000000000)");
|
||||
|
||||
DoubleBits quiet_nan = DoubleBits(DoubleBits::build_quiet_nan(1));
|
||||
DoubleBits quiet_nan = DoubleBits::build_quiet_nan(Sign::POS, 1);
|
||||
EXPECT_EQ(quiet_nan.is_quiet_nan(), true);
|
||||
}
|
||||
|
||||
@ -365,16 +360,12 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
|
||||
if constexpr (sizeof(long double) == sizeof(double))
|
||||
return; // The tests for the "double" type cover for this case.
|
||||
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(LongDoubleBits::inf(Sign::POS)).c_str(),
|
||||
"(+Infinity)");
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(LongDoubleBits::inf(Sign::NEG)).c_str(),
|
||||
"(-Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::inf(Sign::POS)))
|
||||
.c_str(),
|
||||
"(+Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::inf(Sign::NEG)))
|
||||
.c_str(),
|
||||
"(-Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::build_nan(1))).c_str(),
|
||||
LIBC_NAMESPACE::str(LongDoubleBits::build_nan(Sign::POS, 1)).c_str(),
|
||||
"(NaN)");
|
||||
|
||||
LongDoubleBits zero(0.0l);
|
||||
@ -440,7 +431,7 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
|
||||
"0x000000000000BFFF9000000000000000 = "
|
||||
"(S: 1, E: 0x3FFF, I: 1, M: 0x00000000000000001000000000000000)");
|
||||
|
||||
LongDoubleBits quiet_nan = LongDoubleBits(LongDoubleBits::build_quiet_nan(1));
|
||||
LongDoubleBits quiet_nan = LongDoubleBits::build_quiet_nan(Sign::POS, 1);
|
||||
EXPECT_EQ(quiet_nan.is_quiet_nan(), true);
|
||||
}
|
||||
#else
|
||||
@ -450,16 +441,12 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
|
||||
#else
|
||||
using LongDoubleBits = FPBits<long double>;
|
||||
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(LongDoubleBits::inf(Sign::POS)).c_str(),
|
||||
"(+Infinity)");
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(LongDoubleBits::inf(Sign::NEG)).c_str(),
|
||||
"(-Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::inf(Sign::POS)))
|
||||
.c_str(),
|
||||
"(+Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::inf(Sign::NEG)))
|
||||
.c_str(),
|
||||
"(-Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::build_nan(1))).c_str(),
|
||||
LIBC_NAMESPACE::str(LongDoubleBits::build_nan(Sign::POS, 1)).c_str(),
|
||||
"(NaN)");
|
||||
|
||||
LongDoubleBits zero(0.0l);
|
||||
@ -519,7 +506,7 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
|
||||
"0xBFFF2000000000000000000000000000 = "
|
||||
"(S: 1, E: 0x3FFF, M: 0x00002000000000000000000000000000)");
|
||||
|
||||
LongDoubleBits quiet_nan = LongDoubleBits(LongDoubleBits::build_quiet_nan(1));
|
||||
LongDoubleBits quiet_nan = LongDoubleBits::build_quiet_nan(1);
|
||||
EXPECT_EQ(quiet_nan.is_quiet_nan(), true);
|
||||
#endif
|
||||
}
|
||||
@ -529,17 +516,15 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
|
||||
TEST(LlvmLibcFPBitsTest, Float128Type) {
|
||||
using Float128Bits = FPBits<float128>;
|
||||
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(Float128Bits::inf(Sign::POS)).c_str(),
|
||||
"(+Infinity)");
|
||||
EXPECT_STREQ(LIBC_NAMESPACE::str(Float128Bits::inf(Sign::NEG)).c_str(),
|
||||
"(-Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(Float128Bits(Float128Bits::inf(Sign::POS))).c_str(),
|
||||
"(+Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(Float128Bits(Float128Bits::inf(Sign::NEG))).c_str(),
|
||||
"(-Infinity)");
|
||||
EXPECT_STREQ(
|
||||
LIBC_NAMESPACE::str(Float128Bits(Float128Bits::build_nan(1))).c_str(),
|
||||
LIBC_NAMESPACE::str(Float128Bits::build_nan(Sign::POS, 1)).c_str(),
|
||||
"(NaN)");
|
||||
|
||||
Float128Bits zero(Float128Bits::zero());
|
||||
Float128Bits zero = Float128Bits::zero(Sign::POS);
|
||||
EXPECT_TRUE(zero.is_pos());
|
||||
EXPECT_EQ(zero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
|
||||
EXPECT_EQ(zero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
|
||||
@ -549,7 +534,7 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
|
||||
"0x00000000000000000000000000000000 = "
|
||||
"(S: 0, E: 0x0000, M: 0x00000000000000000000000000000000)");
|
||||
|
||||
Float128Bits negzero(Float128Bits::zero(Sign::NEG));
|
||||
Float128Bits negzero = Float128Bits::zero(Sign::NEG);
|
||||
EXPECT_TRUE(negzero.is_neg());
|
||||
EXPECT_EQ(negzero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
|
||||
EXPECT_EQ(negzero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
|
||||
@ -596,7 +581,7 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
|
||||
"0xBFFF2000000000000000000000000000 = "
|
||||
"(S: 1, E: 0x3FFF, M: 0x00002000000000000000000000000000)");
|
||||
|
||||
Float128Bits quiet_nan = Float128Bits(Float128Bits::build_quiet_nan(1));
|
||||
Float128Bits quiet_nan = Float128Bits::build_quiet_nan(Sign::POS, 1);
|
||||
EXPECT_EQ(quiet_nan.is_quiet_nan(), true);
|
||||
}
|
||||
#endif // LIBC_COMPILER_HAS_FLOAT128
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
void test_na_n_arg(FuncPtr func) {
|
||||
EXPECT_FP_EQ(nan, func(nan, inf));
|
||||
|
@ -25,11 +25,21 @@ private:
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
using Sign = LIBC_NAMESPACE::fputil::Sign;
|
||||
|
||||
const T min_subnormal = T(FPBits::min_subnormal(Sign::POS));
|
||||
const T min_normal = T(FPBits::min_normal(Sign::POS));
|
||||
const T max_normal = T(FPBits::max_normal(Sign::POS));
|
||||
const T inf = T(FPBits::inf(Sign::POS));
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval();
|
||||
static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval();
|
||||
static constexpr StorageType MAX_SUBNORMAL =
|
||||
FPBits::max_subnormal().uintval();
|
||||
static constexpr StorageType MIN_SUBNORMAL =
|
||||
FPBits::min_subnormal().uintval();
|
||||
|
||||
StorageType get_random_bit_pattern() {
|
||||
StorageType bits{0};
|
||||
@ -52,14 +62,13 @@ public:
|
||||
EXPECT_FP_EQ(func(inf, neg_inf, nan), nan);
|
||||
|
||||
// Test underflow rounding up.
|
||||
EXPECT_FP_EQ(func(T(0.5), FPBits::min_denormal(), FPBits::min_denormal()),
|
||||
EXPECT_FP_EQ(func(T(0.5), min_subnormal, min_subnormal),
|
||||
T(FPBits(StorageType(2))));
|
||||
// Test underflow rounding down.
|
||||
T v = T(FPBits(FPBits::MIN_NORMAL + StorageType(1)));
|
||||
EXPECT_FP_EQ(
|
||||
func(T(1) / T(FPBits::MIN_NORMAL << 1), v, FPBits::min_normal()), v);
|
||||
T v = T(FPBits(MIN_NORMAL + StorageType(1)));
|
||||
EXPECT_FP_EQ(func(T(1) / T(MIN_NORMAL << 1), v, min_normal), v);
|
||||
// Test overflow.
|
||||
T z = FPBits::max_normal();
|
||||
T z = max_normal;
|
||||
EXPECT_FP_EQ(func(T(1.75), z, -z), T(0.75) * z);
|
||||
// Exact cancellation.
|
||||
EXPECT_FP_EQ(func(T(3.0), T(5.0), -T(15.0)), T(0.0));
|
||||
@ -68,11 +77,9 @@ public:
|
||||
|
||||
void test_subnormal_range(Func func) {
|
||||
constexpr StorageType COUNT = 100'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_SUBNORMAL - FPBits::MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType v = FPBits::MIN_SUBNORMAL, w = FPBits::MAX_SUBNORMAL;
|
||||
v <= FPBits::MAX_SUBNORMAL && w >= FPBits::MIN_SUBNORMAL;
|
||||
v += STEP, w -= STEP) {
|
||||
constexpr StorageType STEP = (MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType v = MIN_SUBNORMAL, w = MAX_SUBNORMAL;
|
||||
v <= MAX_SUBNORMAL && w >= MIN_SUBNORMAL; v += STEP, w -= STEP) {
|
||||
T x = T(FPBits(get_random_bit_pattern())), y = T(FPBits(v)),
|
||||
z = T(FPBits(w));
|
||||
mpfr::TernaryInput<T> input{x, y, z};
|
||||
@ -83,11 +90,9 @@ public:
|
||||
|
||||
void test_normal_range(Func func) {
|
||||
constexpr StorageType COUNT = 100'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_NORMAL - FPBits::MIN_NORMAL) / COUNT;
|
||||
for (StorageType v = FPBits::MIN_NORMAL, w = FPBits::MAX_NORMAL;
|
||||
v <= FPBits::MAX_NORMAL && w >= FPBits::MIN_NORMAL;
|
||||
v += STEP, w -= STEP) {
|
||||
constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT;
|
||||
for (StorageType v = MIN_NORMAL, w = MAX_NORMAL;
|
||||
v <= MAX_NORMAL && w >= MIN_NORMAL; v += STEP, w -= STEP) {
|
||||
T x = T(FPBits(v)), y = T(FPBits(w)),
|
||||
z = T(FPBits(get_random_bit_pattern()));
|
||||
mpfr::TernaryInput<T> input{x, y, z};
|
||||
|
@ -25,15 +25,22 @@ private:
|
||||
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
|
||||
using Sign = LIBC_NAMESPACE::fputil::Sign;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
const T nan = FPBits::build_quiet_nan(1);
|
||||
const T inf = FPBits::inf();
|
||||
const T neg_inf = FPBits::inf(Sign::NEG);
|
||||
const T zero = FPBits::zero();
|
||||
const T neg_zero = FPBits::zero(Sign::NEG);
|
||||
const T max_normal = FPBits::max_normal();
|
||||
const T min_normal = FPBits::min_normal();
|
||||
const T max_subnormal = FPBits::max_denormal();
|
||||
const T min_subnormal = FPBits::min_denormal();
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
const T inf = T(FPBits::inf());
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero());
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T max_normal = T(FPBits::max_normal());
|
||||
const T min_normal = T(FPBits::min_normal());
|
||||
const T max_subnormal = T(FPBits::max_subnormal());
|
||||
const T min_subnormal = T(FPBits::min_subnormal());
|
||||
|
||||
static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval();
|
||||
static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval();
|
||||
static constexpr StorageType MAX_SUBNORMAL =
|
||||
FPBits::max_subnormal().uintval();
|
||||
static constexpr StorageType MIN_SUBNORMAL =
|
||||
FPBits::min_subnormal().uintval();
|
||||
|
||||
public:
|
||||
void test_special_numbers(Func func) {
|
||||
@ -62,12 +69,11 @@ public:
|
||||
void test_subnormal_range(Func func) {
|
||||
constexpr StorageType COUNT = 10'001;
|
||||
for (unsigned scale = 0; scale < 4; ++scale) {
|
||||
StorageType max_value = FPBits::MAX_SUBNORMAL << scale;
|
||||
StorageType step = (max_value - FPBits::MIN_SUBNORMAL) / COUNT;
|
||||
StorageType max_value = MAX_SUBNORMAL << scale;
|
||||
StorageType step = (max_value - MIN_SUBNORMAL) / COUNT;
|
||||
for (int signs = 0; signs < 4; ++signs) {
|
||||
for (StorageType v = FPBits::MIN_SUBNORMAL, w = max_value;
|
||||
v <= max_value && w >= FPBits::MIN_SUBNORMAL;
|
||||
v += step, w -= step) {
|
||||
for (StorageType v = MIN_SUBNORMAL, w = max_value;
|
||||
v <= max_value && w >= MIN_SUBNORMAL; v += step, w -= step) {
|
||||
T x = T(FPBits(v)), y = T(FPBits(w));
|
||||
if (signs % 2 == 1) {
|
||||
x = -x;
|
||||
@ -86,13 +92,10 @@ public:
|
||||
|
||||
void test_normal_range(Func func) {
|
||||
constexpr StorageType COUNT = 10'001;
|
||||
constexpr StorageType STEP =
|
||||
(StorageType(FPBits::MAX_NORMAL) - StorageType(FPBits::MIN_NORMAL)) /
|
||||
COUNT;
|
||||
constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT;
|
||||
for (int signs = 0; signs < 4; ++signs) {
|
||||
for (StorageType v = FPBits::MIN_NORMAL, w = FPBits::MAX_NORMAL;
|
||||
v <= FPBits::MAX_NORMAL && w >= FPBits::MIN_NORMAL;
|
||||
v += STEP, w -= STEP) {
|
||||
for (StorageType v = MIN_NORMAL, w = MAX_NORMAL;
|
||||
v <= MAX_NORMAL && w >= MIN_NORMAL; v += STEP, w -= STEP) {
|
||||
T x = T(FPBits(v)), y = T(FPBits(w));
|
||||
if (signs % 2 == 1) {
|
||||
x = -x;
|
||||
|
@ -26,10 +26,10 @@ public:
|
||||
void test_special_numbers(typename ILogbFunc<T>::Func func) {
|
||||
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
|
||||
using Sign = LIBC_NAMESPACE::fputil::Sign;
|
||||
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero())));
|
||||
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero(Sign::POS))));
|
||||
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero(Sign::NEG))));
|
||||
EXPECT_EQ(FP_ILOGBNAN, func(T(FPBits::build_quiet_nan(1))));
|
||||
EXPECT_EQ(INT_MAX, func(T(FPBits::inf())));
|
||||
EXPECT_EQ(FP_ILOGBNAN, func(T(FPBits::build_quiet_nan(Sign::POS, 1))));
|
||||
EXPECT_EQ(INT_MAX, func(T(FPBits::inf(Sign::POS))));
|
||||
EXPECT_EQ(INT_MAX, func(T(FPBits::inf(Sign::NEG))));
|
||||
}
|
||||
|
||||
@ -76,11 +76,11 @@ public:
|
||||
void test_subnormal_range(typename ILogbFunc<T>::Func func) {
|
||||
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
constexpr StorageType MIN_SUBNORMAL = FPBits::min_subnormal().uintval();
|
||||
constexpr StorageType MAX_SUBNORMAL = FPBits::max_subnormal().uintval();
|
||||
constexpr StorageType COUNT = 10'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_SUBNORMAL - FPBits::MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType v = FPBits::MIN_SUBNORMAL; v <= FPBits::MAX_SUBNORMAL;
|
||||
v += STEP) {
|
||||
constexpr StorageType STEP = (MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType v = MIN_SUBNORMAL; v <= MAX_SUBNORMAL; v += STEP) {
|
||||
T x = T(FPBits(v));
|
||||
if (isnan(x) || isinf(x) || x == 0.0)
|
||||
continue;
|
||||
@ -95,11 +95,11 @@ public:
|
||||
void test_normal_range(typename ILogbFunc<T>::Func func) {
|
||||
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval();
|
||||
constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval();
|
||||
constexpr StorageType COUNT = 10'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_NORMAL - FPBits::MIN_NORMAL) / COUNT;
|
||||
for (StorageType v = FPBits::MIN_NORMAL; v <= FPBits::MAX_NORMAL;
|
||||
v += STEP) {
|
||||
constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT;
|
||||
for (StorageType v = MIN_NORMAL; v <= MAX_NORMAL; v += STEP) {
|
||||
T x = T(FPBits(v));
|
||||
if (isnan(x) || isinf(x) || x == 0.0)
|
||||
continue;
|
||||
|
@ -29,7 +29,7 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::Test {
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
// A normalized mantissa to be used with tests.
|
||||
static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x1234;
|
||||
|
@ -27,12 +27,12 @@ class NextAfterTestTemplate : public LIBC_NAMESPACE::testing::Test {
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
const StorageType min_subnormal = FPBits::MIN_SUBNORMAL;
|
||||
const StorageType max_subnormal = FPBits::MAX_SUBNORMAL;
|
||||
const StorageType min_normal = FPBits::MIN_NORMAL;
|
||||
const StorageType max_normal = FPBits::MAX_NORMAL;
|
||||
const StorageType min_subnormal = FPBits::min_subnormal().uintval();
|
||||
const StorageType max_subnormal = FPBits::max_subnormal().uintval();
|
||||
const StorageType min_normal = FPBits::min_normal().uintval();
|
||||
const StorageType max_normal = FPBits::max_normal().uintval();
|
||||
|
||||
public:
|
||||
typedef T (*NextAfterFunc)(T, T);
|
||||
|
@ -38,7 +38,14 @@ private:
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
static constexpr StorageType MIN_SUBNORMAL =
|
||||
FPBits::min_subnormal().uintval();
|
||||
static constexpr StorageType MAX_SUBNORMAL =
|
||||
FPBits::max_subnormal().uintval();
|
||||
static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval();
|
||||
static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval();
|
||||
|
||||
static inline mpfr::RoundingMode to_mpfr_rounding_mode(int mode) {
|
||||
switch (mode) {
|
||||
@ -95,10 +102,8 @@ public:
|
||||
|
||||
void testSubnormalRange(RIntFunc func) {
|
||||
constexpr StorageType COUNT = 100'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_SUBNORMAL - FPBits::MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType i = FPBits::MIN_SUBNORMAL; i <= FPBits::MAX_SUBNORMAL;
|
||||
i += STEP) {
|
||||
constexpr StorageType STEP = (MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType i = MIN_SUBNORMAL; i <= MAX_SUBNORMAL; i += STEP) {
|
||||
T x = T(FPBits(i));
|
||||
for (int mode : ROUNDING_MODES) {
|
||||
LIBC_NAMESPACE::fputil::set_round(mode);
|
||||
@ -110,10 +115,8 @@ public:
|
||||
|
||||
void testNormalRange(RIntFunc func) {
|
||||
constexpr StorageType COUNT = 100'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_NORMAL - FPBits::MIN_NORMAL) / COUNT;
|
||||
for (StorageType i = FPBits::MIN_NORMAL; i <= FPBits::MAX_NORMAL;
|
||||
i += STEP) {
|
||||
constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT;
|
||||
for (StorageType i = MIN_NORMAL; i <= MAX_NORMAL; i += STEP) {
|
||||
T x = T(FPBits(i));
|
||||
// In normal range on x86 platforms, the long double implicit 1 bit can be
|
||||
// zero making the numbers NaN. We will skip them.
|
||||
|
@ -28,7 +28,14 @@ class RemQuoTestTemplate : public LIBC_NAMESPACE::testing::Test {
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
static constexpr StorageType MIN_SUBNORMAL =
|
||||
FPBits::min_subnormal().uintval();
|
||||
static constexpr StorageType MAX_SUBNORMAL =
|
||||
FPBits::max_subnormal().uintval();
|
||||
static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval();
|
||||
static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval();
|
||||
|
||||
public:
|
||||
typedef T (*RemQuoFunc)(T, T, int *);
|
||||
@ -97,11 +104,9 @@ public:
|
||||
|
||||
void testSubnormalRange(RemQuoFunc func) {
|
||||
constexpr StorageType COUNT = 100'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_SUBNORMAL - FPBits::MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType v = FPBits::MIN_SUBNORMAL, w = FPBits::MAX_SUBNORMAL;
|
||||
v <= FPBits::MAX_SUBNORMAL && w >= FPBits::MIN_SUBNORMAL;
|
||||
v += STEP, w -= STEP) {
|
||||
constexpr StorageType STEP = (MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType v = MIN_SUBNORMAL, w = MAX_SUBNORMAL;
|
||||
v <= MAX_SUBNORMAL && w >= MIN_SUBNORMAL; v += STEP, w -= STEP) {
|
||||
T x = T(FPBits(v)), y = T(FPBits(w));
|
||||
mpfr::BinaryOutput<T> result;
|
||||
mpfr::BinaryInput<T> input{x, y};
|
||||
@ -112,11 +117,9 @@ public:
|
||||
|
||||
void testNormalRange(RemQuoFunc func) {
|
||||
constexpr StorageType COUNT = 1'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_NORMAL - FPBits::MIN_NORMAL) / COUNT;
|
||||
for (StorageType v = FPBits::MIN_NORMAL, w = FPBits::MAX_NORMAL;
|
||||
v <= FPBits::MAX_NORMAL && w >= FPBits::MIN_NORMAL;
|
||||
v += STEP, w -= STEP) {
|
||||
constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT;
|
||||
for (StorageType v = MIN_NORMAL, w = MAX_NORMAL;
|
||||
v <= MAX_NORMAL && w >= MIN_NORMAL; v += STEP, w -= STEP) {
|
||||
T x = T(FPBits(v)), y = T(FPBits(w));
|
||||
mpfr::BinaryOutput<T> result;
|
||||
mpfr::BinaryInput<T> input{x, y};
|
||||
|
@ -37,7 +37,15 @@ private:
|
||||
const F neg_zero = F(FPBits::zero(Sign::NEG));
|
||||
const F inf = F(FPBits::inf());
|
||||
const F neg_inf = F(FPBits::inf(Sign::NEG));
|
||||
const F nan = F(FPBits::build_quiet_nan(1));
|
||||
const F nan = F(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval();
|
||||
static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval();
|
||||
static constexpr StorageType MAX_SUBNORMAL =
|
||||
FPBits::max_subnormal().uintval();
|
||||
static constexpr StorageType MIN_SUBNORMAL =
|
||||
FPBits::min_subnormal().uintval();
|
||||
|
||||
static constexpr I INTEGER_MIN = I(1) << (sizeof(I) * 8 - 1);
|
||||
static constexpr I INTEGER_MAX = -(INTEGER_MIN + 1);
|
||||
|
||||
@ -215,10 +223,8 @@ public:
|
||||
|
||||
void testSubnormalRange(RoundToIntegerFunc func) {
|
||||
constexpr StorageType COUNT = 1'000'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_SUBNORMAL - FPBits::MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType i = FPBits::MIN_SUBNORMAL; i <= FPBits::MAX_SUBNORMAL;
|
||||
i += STEP) {
|
||||
constexpr StorageType STEP = (MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType i = MIN_SUBNORMAL; i <= MAX_SUBNORMAL; i += STEP) {
|
||||
F x = F(FPBits(i));
|
||||
if (x == F(0.0))
|
||||
continue;
|
||||
@ -259,10 +265,8 @@ public:
|
||||
return;
|
||||
|
||||
constexpr StorageType COUNT = 1'000'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_NORMAL - FPBits::MIN_NORMAL) / COUNT;
|
||||
for (StorageType i = FPBits::MIN_NORMAL; i <= FPBits::MAX_NORMAL;
|
||||
i += STEP) {
|
||||
constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT;
|
||||
for (StorageType i = MIN_NORMAL; i <= MAX_NORMAL; i += STEP) {
|
||||
F x = F(FPBits(i));
|
||||
// In normal range on x86 platforms, the long double implicit 1 bit can be
|
||||
// zero making the numbers NaN. We will skip them.
|
||||
|
@ -109,10 +109,13 @@ public:
|
||||
std::ofstream log(logFile);
|
||||
log << " Performance tests with inputs in denormal range:\n";
|
||||
run_perf_in_range(myFunc, otherFunc, /* startingBit= */ StorageType(0),
|
||||
/* endingBit= */ FPBits::MAX_SUBNORMAL, 1'000'001, log);
|
||||
/* endingBit= */ FPBits::max_subnormal().uintval(),
|
||||
1'000'001, log);
|
||||
log << "\n Performance tests with inputs in normal range:\n";
|
||||
run_perf_in_range(myFunc, otherFunc, /* startingBit= */ FPBits::MIN_NORMAL,
|
||||
/* endingBit= */ FPBits::MAX_NORMAL, 100'000'001, log);
|
||||
run_perf_in_range(myFunc, otherFunc,
|
||||
/* startingBit= */ FPBits::min_normal().uintval(),
|
||||
/* endingBit= */ FPBits::max_normal().uintval(),
|
||||
100'000'001, log);
|
||||
log << "\n Performance tests with inputs in normal range with exponents "
|
||||
"close to each other:\n";
|
||||
run_perf_in_range(
|
||||
@ -126,11 +129,12 @@ public:
|
||||
log << " Diff tests with inputs in denormal range:\n";
|
||||
diffCount += run_diff_in_range(
|
||||
myFunc, otherFunc, /* startingBit= */ StorageType(0),
|
||||
/* endingBit= */ FPBits::MAX_SUBNORMAL, 1'000'001, log);
|
||||
/* endingBit= */ FPBits::max_subnormal().uintval(), 1'000'001, log);
|
||||
log << "\n Diff tests with inputs in normal range:\n";
|
||||
diffCount += run_diff_in_range(
|
||||
myFunc, otherFunc, /* startingBit= */ FPBits::MIN_NORMAL,
|
||||
/* endingBit= */ FPBits::MAX_NORMAL, 100'000'001, log);
|
||||
myFunc, otherFunc,
|
||||
/* startingBit= */ FPBits::min_normal().uintval(),
|
||||
/* endingBit= */ FPBits::max_normal().uintval(), 100'000'001, log);
|
||||
log << "\n Diff tests with inputs in normal range with exponents "
|
||||
"close to each other:\n";
|
||||
diffCount += run_diff_in_range(
|
||||
|
@ -93,10 +93,11 @@ public:
|
||||
std::ofstream log(logFile);
|
||||
log << " Performance tests with inputs in denormal range:\n";
|
||||
runPerfInRange(myFunc, otherFunc, /* startingBit= */ StorageType(0),
|
||||
/* endingBit= */ FPBits::MAX_SUBNORMAL, log);
|
||||
/* endingBit= */ FPBits::max_subnormal().uintval(), log);
|
||||
log << "\n Performance tests with inputs in normal range:\n";
|
||||
runPerfInRange(myFunc, otherFunc, /* startingBit= */ FPBits::MIN_NORMAL,
|
||||
/* endingBit= */ FPBits::MAX_NORMAL, log);
|
||||
runPerfInRange(myFunc, otherFunc,
|
||||
/* startingBit= */ FPBits::min_normal().uintval(),
|
||||
/* endingBit= */ FPBits::max_normal().uintval(), log);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
void test_na_n_arg(FuncPtr func) {
|
||||
EXPECT_FP_EQ(nan, func(nan, inf));
|
||||
|
@ -25,7 +25,7 @@ private:
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
public:
|
||||
void test_special_numbers(Func func) {
|
||||
@ -39,14 +39,16 @@ public:
|
||||
EXPECT_FP_EQ(func(inf, neg_inf, nan), nan);
|
||||
|
||||
// Test underflow rounding up.
|
||||
EXPECT_FP_EQ(func(T(0.5), FPBits::min_denormal(), FPBits::min_denormal()),
|
||||
T(FPBits(StorageType(2))));
|
||||
// Test underflow rounding down.
|
||||
T v = T(FPBits(FPBits::MIN_NORMAL + StorageType(1)));
|
||||
EXPECT_FP_EQ(
|
||||
func(T(1) / T(FPBits::MIN_NORMAL << 1), v, FPBits::min_normal()), v);
|
||||
func(T(0.5), T(FPBits::min_subnormal()), T(FPBits::min_subnormal())),
|
||||
T(FPBits(StorageType(2))));
|
||||
// Test underflow rounding down.
|
||||
StorageType MIN_NORMAL = FPBits::min_normal().uintval();
|
||||
T v = T(FPBits(MIN_NORMAL + StorageType(1)));
|
||||
EXPECT_FP_EQ(func(T(1) / T(MIN_NORMAL << 1), v, T(FPBits::min_normal())),
|
||||
v);
|
||||
// Test overflow.
|
||||
T z = FPBits::max_normal();
|
||||
T z = T(FPBits::max_normal());
|
||||
EXPECT_FP_EQ(func(T(1.75), z, -z), T(0.75) * z);
|
||||
// Exact cancellation.
|
||||
EXPECT_FP_EQ(func(T(3.0), T(5.0), -T(15.0)), T(0.0));
|
||||
|
@ -22,16 +22,16 @@ private:
|
||||
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
using Sign = LIBC_NAMESPACE::fputil::Sign;
|
||||
const T nan = FPBits::build_quiet_nan(1);
|
||||
const T inf = FPBits::inf(Sign::POS);
|
||||
const T neg_inf = FPBits::inf(Sign::NEG);
|
||||
const T zero = FPBits::zero(Sign::POS);
|
||||
const T neg_zero = FPBits::zero(Sign::NEG);
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
const T inf = T(FPBits::inf(Sign::POS));
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
|
||||
const T max_normal = FPBits::max_normal();
|
||||
const T min_normal = FPBits::min_normal();
|
||||
const T max_subnormal = FPBits::max_denormal();
|
||||
const T min_subnormal = FPBits::min_denormal();
|
||||
const T max_normal = T(FPBits::max_normal());
|
||||
const T min_normal = T(FPBits::min_normal());
|
||||
const T max_subnormal = T(FPBits::max_subnormal());
|
||||
const T min_subnormal = T(FPBits::min_subnormal());
|
||||
|
||||
public:
|
||||
void test_special_numbers(Func func) {
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
using Sign = LIBC_NAMESPACE::fputil::Sign;
|
||||
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero(Sign::POS))));
|
||||
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero(Sign::NEG))));
|
||||
EXPECT_EQ(FP_ILOGBNAN, func(T(FPBits::build_quiet_nan(1))));
|
||||
EXPECT_EQ(FP_ILOGBNAN, func(T(FPBits::build_quiet_nan(Sign::POS, 1))));
|
||||
EXPECT_EQ(INT_MAX, func(T(FPBits::inf(Sign::POS))));
|
||||
EXPECT_EQ(INT_MAX, func(T(FPBits::inf(Sign::NEG))));
|
||||
}
|
||||
@ -76,11 +76,11 @@ public:
|
||||
void test_subnormal_range(typename ILogbFunc<T>::Func func) {
|
||||
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
constexpr StorageType MIN_SUBNORMAL = FPBits::min_subnormal().uintval();
|
||||
constexpr StorageType MAX_SUBNORMAL = FPBits::max_subnormal().uintval();
|
||||
constexpr StorageType COUNT = 10'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_SUBNORMAL - FPBits::MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType v = FPBits::MIN_SUBNORMAL; v <= FPBits::MAX_SUBNORMAL;
|
||||
v += STEP) {
|
||||
constexpr StorageType STEP = (MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType v = MIN_SUBNORMAL; v <= MAX_SUBNORMAL; v += STEP) {
|
||||
T x = T(FPBits(v));
|
||||
if (isnan(x) || isinf(x) || x == 0.0)
|
||||
continue;
|
||||
@ -95,11 +95,11 @@ public:
|
||||
void test_normal_range(typename ILogbFunc<T>::Func func) {
|
||||
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval();
|
||||
constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval();
|
||||
constexpr StorageType COUNT = 10'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_NORMAL - FPBits::MIN_NORMAL) / COUNT;
|
||||
for (StorageType v = FPBits::MIN_NORMAL; v <= FPBits::MAX_NORMAL;
|
||||
v += STEP) {
|
||||
constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT;
|
||||
for (StorageType v = MIN_NORMAL; v <= MAX_NORMAL; v += STEP) {
|
||||
T x = T(FPBits(v));
|
||||
if (isnan(x) || isinf(x) || x == 0.0)
|
||||
continue;
|
||||
|
@ -29,7 +29,7 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::Test {
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
// A normalized mantissa to be used with tests.
|
||||
static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x1234;
|
||||
|
@ -38,12 +38,14 @@ class NextAfterTestTemplate : public LIBC_NAMESPACE::testing::Test {
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
const StorageType min_subnormal = FPBits::MIN_SUBNORMAL;
|
||||
const StorageType max_subnormal = FPBits::MAX_SUBNORMAL;
|
||||
const StorageType min_normal = FPBits::MIN_NORMAL;
|
||||
const StorageType max_normal = FPBits::MAX_NORMAL;
|
||||
static constexpr StorageType min_subnormal =
|
||||
FPBits::min_subnormal().uintval();
|
||||
static constexpr StorageType max_subnormal =
|
||||
FPBits::max_subnormal().uintval();
|
||||
static constexpr StorageType min_normal = FPBits::min_normal().uintval();
|
||||
static constexpr StorageType max_normal = FPBits::max_normal().uintval();
|
||||
|
||||
public:
|
||||
typedef T (*NextAfterFunc)(T, T);
|
||||
|
@ -40,16 +40,18 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::Test {
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
const long double to_zero = ToFPBits::zero();
|
||||
const long double to_neg_zero = ToFPBits::zero(Sign::NEG);
|
||||
const long double to_nan = ToFPBits::build_quiet_nan(1);
|
||||
const long double to_zero = ToFPBits::zero().get_val();
|
||||
const long double to_neg_zero = ToFPBits::zero(Sign::NEG).get_val();
|
||||
const long double to_nan = ToFPBits::build_quiet_nan(Sign::POS, 1).get_val();
|
||||
|
||||
const StorageType min_subnormal = FPBits::MIN_SUBNORMAL;
|
||||
const StorageType max_subnormal = FPBits::MAX_SUBNORMAL;
|
||||
const StorageType min_normal = FPBits::MIN_NORMAL;
|
||||
const StorageType max_normal = FPBits::MAX_NORMAL;
|
||||
static constexpr StorageType min_subnormal =
|
||||
FPBits::min_subnormal().uintval();
|
||||
static constexpr StorageType max_subnormal =
|
||||
FPBits::max_subnormal().uintval();
|
||||
static constexpr StorageType min_normal = FPBits::min_normal().uintval();
|
||||
static constexpr StorageType max_normal = FPBits::max_normal().uintval();
|
||||
|
||||
public:
|
||||
typedef T (*NextTowardFunc)(T, long double);
|
||||
|
@ -35,7 +35,7 @@ private:
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
public:
|
||||
void testSpecialNumbers(RIntFunc func) {
|
||||
|
@ -25,7 +25,7 @@ class RemQuoTestTemplate : public LIBC_NAMESPACE::testing::Test {
|
||||
const T neg_inf = T(FPBits::inf(Sign::NEG));
|
||||
const T zero = T(FPBits::zero(Sign::POS));
|
||||
const T neg_zero = T(FPBits::zero(Sign::NEG));
|
||||
const T nan = T(FPBits::build_quiet_nan(1));
|
||||
const T nan = T(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
public:
|
||||
typedef T (*RemQuoFunc)(T, T, int *);
|
||||
|
@ -30,11 +30,17 @@ private:
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
using Sign = LIBC_NAMESPACE::fputil::Sign;
|
||||
|
||||
const F zero = F(LIBC_NAMESPACE::fputil::FPBits<F>::zero(Sign::POS));
|
||||
const F neg_zero = F(LIBC_NAMESPACE::fputil::FPBits<F>::zero(Sign::NEG));
|
||||
const F inf = F(LIBC_NAMESPACE::fputil::FPBits<F>::inf(Sign::POS));
|
||||
const F neg_inf = F(LIBC_NAMESPACE::fputil::FPBits<F>::inf(Sign::NEG));
|
||||
const F nan = F(LIBC_NAMESPACE::fputil::FPBits<F>::build_quiet_nan(1));
|
||||
const F zero = F(FPBits::zero(Sign::POS));
|
||||
const F neg_zero = F(FPBits::zero(Sign::NEG));
|
||||
const F inf = F(FPBits::inf(Sign::POS));
|
||||
const F neg_inf = F(FPBits::inf(Sign::NEG));
|
||||
const F nan = F(FPBits::build_quiet_nan(Sign::POS, 1));
|
||||
|
||||
static constexpr StorageType MAX_SUBNORMAL =
|
||||
FPBits::max_subnormal().uintval();
|
||||
static constexpr StorageType MIN_SUBNORMAL =
|
||||
FPBits::min_subnormal().uintval();
|
||||
|
||||
static constexpr I INTEGER_MIN = I(1) << (sizeof(I) * 8 - 1);
|
||||
static constexpr I INTEGER_MAX = -(INTEGER_MIN + 1);
|
||||
|
||||
@ -111,10 +117,8 @@ public:
|
||||
|
||||
void testSubnormalRange(RoundToIntegerFunc func) {
|
||||
constexpr StorageType COUNT = 1'000'001;
|
||||
constexpr StorageType STEP =
|
||||
(FPBits::MAX_SUBNORMAL - FPBits::MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType i = FPBits::MIN_SUBNORMAL; i <= FPBits::MAX_SUBNORMAL;
|
||||
i += STEP) {
|
||||
constexpr StorageType STEP = (MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT;
|
||||
for (StorageType i = MIN_SUBNORMAL; i <= MAX_SUBNORMAL; i += STEP) {
|
||||
F x = F(FPBits(i));
|
||||
if (x == F(0.0))
|
||||
continue;
|
||||
|
@ -585,8 +585,10 @@ TEST(LlvmLibcSPrintfTest, OctConv) {
|
||||
|
||||
TEST_F(LlvmLibcSPrintfTest, FloatHexExpConv) {
|
||||
ForceRoundingMode r(RoundingMode::Nearest);
|
||||
double inf = LIBC_NAMESPACE::fputil::FPBits<double>::inf();
|
||||
double nan = LIBC_NAMESPACE::fputil::FPBits<double>::build_nan(1);
|
||||
double inf = LIBC_NAMESPACE::fputil::FPBits<double>::inf().get_val();
|
||||
double nan = LIBC_NAMESPACE::fputil::FPBits<double>::build_nan(
|
||||
LIBC_NAMESPACE::fputil::Sign::POS, 1)
|
||||
.get_val();
|
||||
written = LIBC_NAMESPACE::sprintf(buff, "%a", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "0x1p+0");
|
||||
|
||||
@ -949,11 +951,15 @@ TEST_F(LlvmLibcSPrintfTest, FloatHexExpConv) {
|
||||
|
||||
TEST_F(LlvmLibcSPrintfTest, FloatDecimalConv) {
|
||||
ForceRoundingMode r(RoundingMode::Nearest);
|
||||
double inf = LIBC_NAMESPACE::fputil::FPBits<double>::inf();
|
||||
double nan = LIBC_NAMESPACE::fputil::FPBits<double>::build_nan(1);
|
||||
long double ld_inf = LIBC_NAMESPACE::fputil::FPBits<long double>::inf();
|
||||
long double ld_nan =
|
||||
LIBC_NAMESPACE::fputil::FPBits<long double>::build_nan(1);
|
||||
double inf = LIBC_NAMESPACE::fputil::FPBits<double>::inf().get_val();
|
||||
double nan = LIBC_NAMESPACE::fputil::FPBits<double>::build_nan(
|
||||
LIBC_NAMESPACE::fputil::Sign::POS, 1)
|
||||
.get_val();
|
||||
long double ld_inf =
|
||||
LIBC_NAMESPACE::fputil::FPBits<long double>::inf().get_val();
|
||||
long double ld_nan = LIBC_NAMESPACE::fputil::FPBits<long double>::build_nan(
|
||||
LIBC_NAMESPACE::fputil::Sign::POS, 1)
|
||||
.get_val();
|
||||
|
||||
char big_buff[10000]; // Used for long doubles and other extremely wide
|
||||
// numbers.
|
||||
@ -1790,8 +1796,10 @@ TEST_F(LlvmLibcSPrintfTest, FloatDecimalConv) {
|
||||
|
||||
TEST_F(LlvmLibcSPrintfTest, FloatExponentConv) {
|
||||
ForceRoundingMode r(RoundingMode::Nearest);
|
||||
double inf = LIBC_NAMESPACE::fputil::FPBits<double>::inf();
|
||||
double nan = LIBC_NAMESPACE::fputil::FPBits<double>::build_nan(1);
|
||||
double inf = LIBC_NAMESPACE::fputil::FPBits<double>::inf().get_val();
|
||||
double nan = LIBC_NAMESPACE::fputil::FPBits<double>::build_nan(
|
||||
LIBC_NAMESPACE::fputil::Sign::POS, 1)
|
||||
.get_val();
|
||||
|
||||
written = LIBC_NAMESPACE::sprintf(buff, "%e", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.000000e+00");
|
||||
@ -2422,8 +2430,10 @@ TEST_F(LlvmLibcSPrintfTest, FloatExponentConv) {
|
||||
|
||||
TEST_F(LlvmLibcSPrintfTest, FloatAutoConv) {
|
||||
ForceRoundingMode r(RoundingMode::Nearest);
|
||||
double inf = LIBC_NAMESPACE::fputil::FPBits<double>::inf();
|
||||
double nan = LIBC_NAMESPACE::fputil::FPBits<double>::build_nan(1);
|
||||
double inf = LIBC_NAMESPACE::fputil::FPBits<double>::inf().get_val();
|
||||
double nan = LIBC_NAMESPACE::fputil::FPBits<double>::build_nan(
|
||||
LIBC_NAMESPACE::fputil::Sign::POS, 1)
|
||||
.get_val();
|
||||
|
||||
written = LIBC_NAMESPACE::sprintf(buff, "%g", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1");
|
||||
|
@ -230,8 +230,10 @@ TEST(LlvmLibcSScanfTest, FloatConvSimple) {
|
||||
int ret_val;
|
||||
float result = 0;
|
||||
|
||||
float inf = LIBC_NAMESPACE::fputil::FPBits<float>::inf();
|
||||
float nan = LIBC_NAMESPACE::fputil::FPBits<float>::build_nan(1);
|
||||
float inf = LIBC_NAMESPACE::fputil::FPBits<float>::inf().get_val();
|
||||
float nan = LIBC_NAMESPACE::fputil::FPBits<float>::build_nan(
|
||||
LIBC_NAMESPACE::fputil::Sign::POS, 1)
|
||||
.get_val();
|
||||
|
||||
ret_val = LIBC_NAMESPACE::sscanf("123", "%f", &result);
|
||||
EXPECT_EQ(ret_val, 1);
|
||||
@ -294,9 +296,10 @@ TEST(LlvmLibcSScanfTest, FloatConvLengthModifier) {
|
||||
double d_result = 0;
|
||||
long double ld_result = 0;
|
||||
|
||||
double d_inf = LIBC_NAMESPACE::fputil::FPBits<double>::inf();
|
||||
long double ld_nan =
|
||||
LIBC_NAMESPACE::fputil::FPBits<long double>::build_nan(1);
|
||||
double d_inf = LIBC_NAMESPACE::fputil::FPBits<double>::inf().get_val();
|
||||
long double ld_nan = LIBC_NAMESPACE::fputil::FPBits<long double>::build_nan(
|
||||
LIBC_NAMESPACE::fputil::Sign::POS, 1)
|
||||
.get_val();
|
||||
|
||||
ret_val = LIBC_NAMESPACE::sscanf("123", "%lf", &d_result);
|
||||
EXPECT_EQ(ret_val, 1);
|
||||
@ -391,8 +394,10 @@ TEST(LlvmLibcSScanfTest, FloatConvComplexParsing) {
|
||||
int ret_val;
|
||||
float result = 0;
|
||||
|
||||
float inf = LIBC_NAMESPACE::fputil::FPBits<float>::inf();
|
||||
float nan = LIBC_NAMESPACE::fputil::FPBits<float>::build_nan(1);
|
||||
float inf = LIBC_NAMESPACE::fputil::FPBits<float>::inf().get_val();
|
||||
float nan = LIBC_NAMESPACE::fputil::FPBits<float>::build_nan(
|
||||
LIBC_NAMESPACE::fputil::Sign::POS, 1)
|
||||
.get_val();
|
||||
|
||||
ret_val = LIBC_NAMESPACE::sscanf("0x1.0e3", "%f", &result);
|
||||
EXPECT_EQ(ret_val, 1);
|
||||
@ -463,7 +468,7 @@ TEST(LlvmLibcSScanfTest, FloatConvMaxWidth) {
|
||||
int ret_val;
|
||||
float result = 0;
|
||||
|
||||
float inf = LIBC_NAMESPACE::fputil::FPBits<float>::inf();
|
||||
float inf = LIBC_NAMESPACE::fputil::FPBits<float>::inf().get_val();
|
||||
|
||||
ret_val = LIBC_NAMESPACE::sscanf("123", "%3f", &result);
|
||||
EXPECT_EQ(ret_val, 1);
|
||||
|
@ -49,7 +49,7 @@ template <> struct ExtraPrecision<long double> {
|
||||
template <typename T>
|
||||
static inline unsigned int get_precision(double ulp_tolerance) {
|
||||
if (ulp_tolerance <= 0.5) {
|
||||
return LIBC_NAMESPACE::fputil::FPBits<T>::MANTISSA_PRECISION;
|
||||
return LIBC_NAMESPACE::fputil::FPBits<T>::FRACTION_LEN + 1;
|
||||
} else {
|
||||
return ExtraPrecision<T>::VALUE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user