14
14
15
15
#pragma once
16
16
17
+ #include < fenv.h>
17
18
#include < stddef.h>
18
19
#include < stdint.h>
19
20
@@ -618,7 +619,7 @@ sus_pure_const inline constexpr OverflowOut<T> add_with_overflow(T x,
618
619
};
619
620
}
620
621
621
- template <class T , class U = decltype(to_signed (std::declval<T>()))>
622
+ template <class T , class U = decltype(into_signed (std::declval<T>()))>
622
623
requires (std::is_integral_v<T> && !std::is_signed_v<T> &&
623
624
::sus::mem::size_of<T>() <= 8 &&
624
625
::sus::mem::size_of<T>() == ::sus::mem::size_of<U>())
@@ -631,7 +632,7 @@ sus_pure_const inline constexpr OverflowOut<T> add_with_overflow_signed(
631
632
};
632
633
}
633
634
634
- template <class T , class U = decltype(to_unsigned (std::declval<T>()))>
635
+ template <class T , class U = decltype(into_unsigned (std::declval<T>()))>
635
636
requires (std::is_integral_v<T> && std::is_signed_v<T> &&
636
637
::sus::mem::size_of<T>() <= 8 &&
637
638
::sus::mem::size_of<T>() == ::sus::mem::size_of<U>())
@@ -668,7 +669,7 @@ sus_pure_const inline constexpr OverflowOut<T> sub_with_overflow(T x,
668
669
};
669
670
}
670
671
671
- template <class T , class U = decltype(to_unsigned (std::declval<T>()))>
672
+ template <class T , class U = decltype(into_unsigned (std::declval<T>()))>
672
673
requires (std::is_integral_v<T> && std::is_signed_v<T> &&
673
674
::sus::mem::size_of<T>() <= 8 &&
674
675
::sus::mem::size_of<T>() == ::sus::mem::size_of<U>())
@@ -1258,12 +1259,14 @@ sus_pure_const sus_always_inline constexpr int32_t exponent_bits(
1258
1259
unchecked_shr (into_unsigned_integer (x) & mask, 52 ));
1259
1260
}
1260
1261
1261
- sus_pure_const sus_always_inline constexpr int32_t exponent_value (
1262
+ // / This function requires that `x` is a normal value to produce a value result.
1263
+ sus_pure_const sus_always_inline constexpr int32_t float_normal_exponent_value (
1262
1264
float x) noexcept {
1263
1265
return exponent_bits (x) - int32_t {127 };
1264
1266
}
1265
1267
1266
- sus_pure_const sus_always_inline constexpr int32_t exponent_value (
1268
+ // / This function requires that `x` is a normal value to produce a value result.
1269
+ sus_pure_const sus_always_inline constexpr int32_t float_normal_exponent_value (
1267
1270
double x) noexcept {
1268
1271
return exponent_bits (x) - int32_t {1023 };
1269
1272
}
@@ -1399,8 +1402,10 @@ sus_pure_const inline constexpr T truncate_float(T x) noexcept {
1399
1402
: uint32_t {52 };
1400
1403
1401
1404
if (float_is_inf_or_nan (x) || float_is_zero (x)) return x;
1405
+ if (float_nonzero_is_subnormal (x)) [[unlikely]]
1406
+ return T{0 };
1402
1407
1403
- const int32_t exponent = exponent_value (x);
1408
+ const int32_t exponent = float_normal_exponent_value (x);
1404
1409
1405
1410
// If the exponent is greater than the most negative mantissa
1406
1411
// exponent, then x is already an integer.
@@ -1521,4 +1526,31 @@ sus_pure_const inline T next_toward(T from, T to) {
1521
1526
return std::nexttoward (from, to);
1522
1527
}
1523
1528
1529
+ #pragma warning(push)
1530
+ // MSVC claims that "overflow in constant arithmetic" occurs on the static_cast
1531
+ // in `into_smaller_float()` but we check for overflow first, the conversion is
1532
+ // in range.
1533
+ #pragma warning(disable : 4756)
1534
+
1535
+ // Not constexpr as rounding is always toward zero in a constexpr context.
1536
+ template <class Out , class T >
1537
+ requires (std::is_floating_point_v<T> && ::sus::mem::size_of<T>() == 8 &&
1538
+ ::sus::mem::size_of<Out>() == 4 )
1539
+ sus_pure_const inline Out into_smaller_float (T x) noexcept {
1540
+ if (x <= T{max_value<Out>()} && x >= T{min_value<Out>()}) [[likely]] {
1541
+ // SAFETY: Because the value `x` is at or between two valid values of type
1542
+ // `Out`, the static_cast does not cause UB.
1543
+ return static_cast <Out>(x); // Handles values in range.
1544
+ }
1545
+ if (x > T{max_value<Out>()}) {
1546
+ return infinity<Out>(); // Handles large values and INFINITY.
1547
+ }
1548
+ if (x < T{min_value<Out>()}) {
1549
+ return negative_infinity<Out>(); // Handles small values and NEG_INFINITY.
1550
+ }
1551
+ return nan <Out>(); // All that's left are NaNs.
1552
+ }
1553
+
1554
+ #pragma warning(pop)
1555
+
1524
1556
} // namespace sus::num::__private
0 commit comments