From 4e9fa1c05b6537af2c5400905416a521f712dccf Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 09:47:39 -0400 Subject: [PATCH 001/140] Add fast types to readme --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b6253ec..9dbc95a9 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ as well as emulated PPC64LE and STM32 using QEMU with the following compilers: # Synopsis -Decimal provides 3 types: +Decimal provides 3 IEEE-754 compliant types: ```cpp namespace boost { @@ -75,6 +75,20 @@ class decimal128; } //namespace boost ``` +and also 3 similar but non-compliant types with improved runtime performance: + +```cpp +namespace boost { +namespace decimal { + +class decimal32_fast; +class decimal64_fast; +class decimal128_fast; + +} //namespace decimal +} //namespace boost +``` + These types operate like built-in floating point types. They have their own implementations of the Standard-Library functions (e.g. like those found in ``, ``, ``, etc.). From ff87114f271f6bb5e15e46a795f5d78b2e9418b9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 3 Oct 2024 15:23:37 -0400 Subject: [PATCH 002/140] Add fast math macro to cmath impls --- include/boost/decimal/detail/cmath/acos.hpp | 2 ++ include/boost/decimal/detail/cmath/acosh.hpp | 7 +++++++ include/boost/decimal/detail/cmath/asin.hpp | 10 +++++++++- include/boost/decimal/detail/cmath/atan.hpp | 7 ++++++- include/boost/decimal/detail/cmath/atan2.hpp | 9 ++++++++- include/boost/decimal/detail/cmath/atanh.hpp | 8 ++++++++ include/boost/decimal/detail/cmath/cbrt.hpp | 8 +++++++- include/boost/decimal/detail/cmath/cos.hpp | 6 +++++- include/boost/decimal/detail/cmath/cosh.hpp | 2 ++ include/boost/decimal/detail/cmath/ellint_1.hpp | 4 ++++ include/boost/decimal/detail/cmath/ellint_2.hpp | 4 ++++ include/boost/decimal/detail/cmath/erf.hpp | 4 ++++ include/boost/decimal/detail/cmath/exp.hpp | 2 ++ include/boost/decimal/detail/cmath/expm1.hpp | 2 ++ include/boost/decimal/detail/cmath/fdim.hpp | 2 ++ include/boost/decimal/detail/cmath/fmax.hpp | 2 ++ include/boost/decimal/detail/cmath/fmin.hpp | 2 ++ include/boost/decimal/detail/cmath/frexp.hpp | 2 ++ include/boost/decimal/detail/cmath/frexp10.hpp | 2 ++ include/boost/decimal/detail/cmath/hypot.hpp | 16 ++++++++++++++-- include/boost/decimal/detail/cmath/ilogb.hpp | 2 ++ include/boost/decimal/detail/cmath/isfinite.hpp | 4 ++++ include/boost/decimal/detail/cmath/isgreater.hpp | 4 ++++ include/boost/decimal/detail/cmath/isless.hpp | 6 ++++++ .../boost/decimal/detail/cmath/isunordered.hpp | 4 ++++ include/boost/decimal/detail/cmath/ldexp.hpp | 2 ++ include/boost/decimal/detail/cmath/legendre.hpp | 6 ++++++ include/boost/decimal/detail/cmath/lgamma.hpp | 11 +++++++++++ include/boost/decimal/detail/cmath/log.hpp | 6 ++++++ include/boost/decimal/detail/cmath/log10.hpp | 8 ++++++++ include/boost/decimal/detail/cmath/log1p.hpp | 6 ++++++ include/boost/decimal/detail/cmath/logb.hpp | 7 +++++++ include/boost/decimal/detail/cmath/modf.hpp | 2 ++ include/boost/decimal/detail/cmath/next.hpp | 7 +++++++ include/boost/decimal/detail/cmath/pow.hpp | 13 +++++++++++++ include/boost/decimal/detail/cmath/remainder.hpp | 7 +++++++ include/boost/decimal/detail/cmath/remquo.hpp | 7 +++++++ .../boost/decimal/detail/cmath/riemann_zeta.hpp | 7 ++++++- include/boost/decimal/detail/cmath/rint.hpp | 14 ++++++++++++++ include/boost/decimal/detail/cmath/round.hpp | 14 ++++++++++++++ include/boost/decimal/detail/cmath/sin.hpp | 6 +++++- include/boost/decimal/detail/cmath/sinh.hpp | 2 ++ include/boost/decimal/detail/cmath/sqrt.hpp | 7 +++++++ include/boost/decimal/detail/cmath/tan.hpp | 7 +++++++ include/boost/decimal/detail/cmath/tanh.hpp | 2 ++ include/boost/decimal/detail/cmath/tgamma.hpp | 6 ++++++ 46 files changed, 259 insertions(+), 9 deletions(-) diff --git a/include/boost/decimal/detail/cmath/acos.hpp b/include/boost/decimal/detail/cmath/acos.hpp index 72e2de3f..2760d1c9 100644 --- a/include/boost/decimal/detail/cmath/acos.hpp +++ b/include/boost/decimal/detail/cmath/acos.hpp @@ -30,10 +30,12 @@ template constexpr auto acos_impl(T x) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(x)) { return x; } + #endif constexpr auto half_pi {numbers::pi_v / 2}; const auto absx {fabs(static_cast(x))}; diff --git a/include/boost/decimal/detail/cmath/acosh.hpp b/include/boost/decimal/detail/cmath/acosh.hpp index eebdb9ac..1a1176a6 100644 --- a/include/boost/decimal/detail/cmath/acosh.hpp +++ b/include/boost/decimal/detail/cmath/acosh.hpp @@ -30,6 +30,7 @@ constexpr auto acosh_impl(T x) noexcept T result { }; + #ifndef BOOST_DECIMAL_FAST_MATH if (fpc != FP_NORMAL) { if ((fpc == FP_INFINITE) && (!signbit(x))) @@ -45,6 +46,12 @@ constexpr auto acosh_impl(T x) noexcept result = x; } } + #else + if (fpc == FP_ZERO) + { + result = T{0, 0}; + } + #endif else { constexpr T one { 1, 0 }; diff --git a/include/boost/decimal/detail/cmath/asin.hpp b/include/boost/decimal/detail/cmath/asin.hpp index 7821f533..256b3e17 100644 --- a/include/boost/decimal/detail/cmath/asin.hpp +++ b/include/boost/decimal/detail/cmath/asin.hpp @@ -32,7 +32,11 @@ constexpr auto asin_impl(T x) noexcept const auto fpc {fpclassify(x)}; const auto isneg {signbit(x)}; - if (fpc == FP_ZERO || fpc == FP_NAN) + if (fpc == FP_ZERO + #ifndef BOOST_DECIMAL_FAST_MATH + || fpc == FP_NAN + #endif + ) { return x; } @@ -55,7 +59,11 @@ constexpr auto asin_impl(T x) noexcept } else { + #ifndef BOOST_DECIMAL_FAST_MATH result = std::numeric_limits::quiet_NaN(); + #else + result = T{0}; + #endif } // arcsin(-x) == -arcsin(x) diff --git a/include/boost/decimal/detail/cmath/atan.hpp b/include/boost/decimal/detail/cmath/atan.hpp index 1682d1bc..678433b9 100644 --- a/include/boost/decimal/detail/cmath/atan.hpp +++ b/include/boost/decimal/detail/cmath/atan.hpp @@ -33,7 +33,10 @@ constexpr auto atan_impl(T x) noexcept constexpr T my_pi_half { numbers::pi_v / 2 }; - if (fpc == FP_ZERO || fpc == FP_NAN) + if (fpc == FP_ZERO + #ifndef BOOST_DECIMAL_FAST_MATH + || fpc == FP_NAN) + #endif { result = x; } @@ -41,10 +44,12 @@ constexpr auto atan_impl(T x) noexcept { result = -atan_impl(-x); } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc == FP_INFINITE) { result = my_pi_half; } + #endif else { constexpr T one { 1 }; diff --git a/include/boost/decimal/detail/cmath/atan2.hpp b/include/boost/decimal/detail/cmath/atan2.hpp index a461970c..144c3c9f 100644 --- a/include/boost/decimal/detail/cmath/atan2.hpp +++ b/include/boost/decimal/detail/cmath/atan2.hpp @@ -51,6 +51,7 @@ constexpr auto atan2_impl(T y, T x) noexcept T result { }; + #ifndef BOOST_DECIMAL_FAST_MATH if (fpcx == FP_NAN) { result = x; @@ -59,7 +60,9 @@ constexpr auto atan2_impl(T y, T x) noexcept { result = y; } - else if (fpcy == FP_ZERO && signx) + else + #endif + if (fpcy == FP_ZERO && signx) { result = signy ? -numbers::pi_v : numbers::pi_v; } @@ -67,6 +70,7 @@ constexpr auto atan2_impl(T y, T x) noexcept { result = y; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpcy == FP_INFINITE && isfinitex) { result = atan2_detail::pi_constants::pi_over_two; @@ -85,12 +89,14 @@ constexpr auto atan2_impl(T y, T x) noexcept if (signy) { result = -result; } } + #endif else if (fpcx == FP_ZERO) { result = atan2_detail::pi_constants::pi_over_two; if (signy) { result = -result; } } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpcx == FP_INFINITE && signx && isfinitey) { result = signy ? -numbers::pi_v : numbers::pi_v; @@ -101,6 +107,7 @@ constexpr auto atan2_impl(T y, T x) noexcept result = signy ? -zero : zero; } + #endif else { if (x == T{1, 0}) diff --git a/include/boost/decimal/detail/cmath/atanh.hpp b/include/boost/decimal/detail/cmath/atanh.hpp index edda078b..7a97483b 100644 --- a/include/boost/decimal/detail/cmath/atanh.hpp +++ b/include/boost/decimal/detail/cmath/atanh.hpp @@ -42,7 +42,11 @@ constexpr auto atanh_impl(T x) noexcept if (xx > one) { + #ifndef BOOST_DECIMAL_FAST_MATH result = std::numeric_limits::quiet_NaN(); + #else + result = zero; + #endif } else if (xx < one) { @@ -86,7 +90,11 @@ constexpr auto atanh_impl(T x) noexcept } else { + #ifndef BOOST_DECIMAL_FAST_MATH result = ((!b_neg) ? std::numeric_limits::infinity() : -std::numeric_limits::infinity()); + #else + result = zero; + #endif } } diff --git a/include/boost/decimal/detail/cmath/cbrt.hpp b/include/boost/decimal/detail/cmath/cbrt.hpp index e0df6368..06fd56b2 100644 --- a/include/boost/decimal/detail/cmath/cbrt.hpp +++ b/include/boost/decimal/detail/cmath/cbrt.hpp @@ -31,7 +31,11 @@ constexpr auto cbrt_impl(T x) noexcept T result { }; - if ((fpc == FP_NAN) || (fpc == FP_ZERO)) + if ((fpc == FP_ZERO) + #ifndef BOOST_DECIMAL_FAST_MATH + || (fpc == FP_NAN) + #endif + ) { result = x; } @@ -39,10 +43,12 @@ constexpr auto cbrt_impl(T x) noexcept { result = -cbrt(-x); } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc == FP_INFINITE) { result = std::numeric_limits::infinity(); } + #endif else { int exp10val { }; diff --git a/include/boost/decimal/detail/cmath/cos.hpp b/include/boost/decimal/detail/cmath/cos.hpp index 3b7e790d..304e2fd4 100644 --- a/include/boost/decimal/detail/cmath/cos.hpp +++ b/include/boost/decimal/detail/cmath/cos.hpp @@ -32,14 +32,18 @@ constexpr auto cos_impl(T x) noexcept { T result { }; + #ifndef BOOST_DECIMAL_FAST_MATH const auto fpc = fpclassify(x); // First check non-finite values and small angles + if ((fpc == FP_INFINITE) || (fpc == FP_NAN)) { result = x; } - else if (signbit(x)) + else + #endif + if (signbit(x)) { result = cos(-x); } diff --git a/include/boost/decimal/detail/cmath/cosh.hpp b/include/boost/decimal/detail/cmath/cosh.hpp index 4c1ab2bf..d2f067d1 100644 --- a/include/boost/decimal/detail/cmath/cosh.hpp +++ b/include/boost/decimal/detail/cmath/cosh.hpp @@ -38,6 +38,7 @@ constexpr auto cosh_impl(T x) noexcept { result = one; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc != FP_NORMAL) { if (fpc == FP_INFINITE) @@ -49,6 +50,7 @@ constexpr auto cosh_impl(T x) noexcept result = abs(x); } } + #endif else { if (signbit(x)) diff --git a/include/boost/decimal/detail/cmath/ellint_1.hpp b/include/boost/decimal/detail/cmath/ellint_1.hpp index 76303d29..96033fea 100644 --- a/include/boost/decimal/detail/cmath/ellint_1.hpp +++ b/include/boost/decimal/detail/cmath/ellint_1.hpp @@ -53,7 +53,11 @@ constexpr auto ellint_1_impl(T m, T phi) noexcept } else if((fabs(m) > one) || (fpc_phi != FP_NORMAL) || (fpc_m != FP_NORMAL)) { + #ifndef BOOST_DECIMAL_FAST_MATH result = std::numeric_limits::quiet_NaN(); + #else + result = T{0}; + #endif } else if(signbit(phi)) { diff --git a/include/boost/decimal/detail/cmath/ellint_2.hpp b/include/boost/decimal/detail/cmath/ellint_2.hpp index 916a7e58..a84e3555 100644 --- a/include/boost/decimal/detail/cmath/ellint_2.hpp +++ b/include/boost/decimal/detail/cmath/ellint_2.hpp @@ -53,7 +53,11 @@ constexpr auto ellint_2_impl(T m, T phi) noexcept } else if((fabs(m) > one) || (fpc_phi != FP_NORMAL) || (fpc_m != FP_NORMAL)) { + #ifndef BOOST_DECIMAL_FAST_MATH result = std::numeric_limits::quiet_NaN(); + #else + result = T{0}; + #endif } else if(signbit(phi)) { diff --git a/include/boost/decimal/detail/cmath/erf.hpp b/include/boost/decimal/detail/cmath/erf.hpp index 4c82596c..417a0575 100644 --- a/include/boost/decimal/detail/cmath/erf.hpp +++ b/include/boost/decimal/detail/cmath/erf.hpp @@ -766,10 +766,12 @@ constexpr auto erf_impl(T z) noexcept { return z; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fp == FP_INFINITE) { return z < T{0} ? T{-1} : T{1}; } + #endif return detail::erf_calc_impl(z, false); } @@ -785,10 +787,12 @@ constexpr auto erfc_impl(T z) noexcept { return z; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fp == FP_INFINITE) { return z < T{0} ? T{2} : T{0}; } + #endif return detail::erf_calc_impl(z, true); } diff --git a/include/boost/decimal/detail/cmath/exp.hpp b/include/boost/decimal/detail/cmath/exp.hpp index e72b2c3a..f80eb1b8 100644 --- a/include/boost/decimal/detail/cmath/exp.hpp +++ b/include/boost/decimal/detail/cmath/exp.hpp @@ -39,6 +39,7 @@ constexpr auto exp_impl(T x) noexcept { result = one; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc != FP_NORMAL) { if (fpc == FP_INFINITE) @@ -50,6 +51,7 @@ constexpr auto exp_impl(T x) noexcept result = x; } } // LCOV_EXCL_LINE + #endif else { if (signbit(x)) diff --git a/include/boost/decimal/detail/cmath/expm1.hpp b/include/boost/decimal/detail/cmath/expm1.hpp index ae7796a2..4c9b0b45 100644 --- a/include/boost/decimal/detail/cmath/expm1.hpp +++ b/include/boost/decimal/detail/cmath/expm1.hpp @@ -38,6 +38,7 @@ constexpr auto expm1_impl(T x) noexcept { result = x; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc != FP_NORMAL) { if (fpc == FP_INFINITE) @@ -56,6 +57,7 @@ constexpr auto expm1_impl(T x) noexcept result = x; } } + #endif else { if (abs(x) > numbers::ln2_v) diff --git a/include/boost/decimal/detail/cmath/fdim.hpp b/include/boost/decimal/detail/cmath/fdim.hpp index b868b315..b70abc9b 100644 --- a/include/boost/decimal/detail/cmath/fdim.hpp +++ b/include/boost/decimal/detail/cmath/fdim.hpp @@ -25,6 +25,7 @@ constexpr auto fdim(T x, T y) noexcept { constexpr T zero {0, 0}; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(x) || isinf(x)) { return x; @@ -33,6 +34,7 @@ constexpr auto fdim(T x, T y) noexcept { return y; } + #endif if (y >= x) { diff --git a/include/boost/decimal/detail/cmath/fmax.hpp b/include/boost/decimal/detail/cmath/fmax.hpp index ca978791..1822bc7f 100644 --- a/include/boost/decimal/detail/cmath/fmax.hpp +++ b/include/boost/decimal/detail/cmath/fmax.hpp @@ -25,6 +25,7 @@ constexpr auto fmax(T1 lhs, T2 rhs) noexcept { using promoted_type = detail::promote_args_t; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) && !isnan(rhs)) { return static_cast(rhs); @@ -34,6 +35,7 @@ constexpr auto fmax(T1 lhs, T2 rhs) noexcept { return static_cast(lhs); } + #endif return lhs > rhs ? static_cast(lhs) : static_cast(rhs); } diff --git a/include/boost/decimal/detail/cmath/fmin.hpp b/include/boost/decimal/detail/cmath/fmin.hpp index d4e13cfa..4021020b 100644 --- a/include/boost/decimal/detail/cmath/fmin.hpp +++ b/include/boost/decimal/detail/cmath/fmin.hpp @@ -24,6 +24,7 @@ constexpr auto fmin(T1 lhs, T2 rhs) noexcept { using promoted_type = detail::promote_args_t; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) && !isnan(rhs)) { return static_cast(rhs); @@ -33,6 +34,7 @@ constexpr auto fmin(T1 lhs, T2 rhs) noexcept { return static_cast(lhs); } + #endif return lhs < rhs ? static_cast(lhs) : static_cast(rhs); } diff --git a/include/boost/decimal/detail/cmath/frexp.hpp b/include/boost/decimal/detail/cmath/frexp.hpp index 8b2edbef..ae454ec2 100644 --- a/include/boost/decimal/detail/cmath/frexp.hpp +++ b/include/boost/decimal/detail/cmath/frexp.hpp @@ -38,6 +38,7 @@ constexpr auto frexp_impl(T v, int* expon) noexcept { if (expon != nullptr) { *expon = 0; } + #ifndef BOOST_DECIMAL_FAST_MATH if (v_fp == FP_NAN) { result_frexp = std::numeric_limits::quiet_NaN(); @@ -46,6 +47,7 @@ constexpr auto frexp_impl(T v, int* expon) noexcept { result_frexp = std::numeric_limits::infinity(); } + #endif } else { diff --git a/include/boost/decimal/detail/cmath/frexp10.hpp b/include/boost/decimal/detail/cmath/frexp10.hpp index 5bc5e9fa..6d6e75d6 100644 --- a/include/boost/decimal/detail/cmath/frexp10.hpp +++ b/include/boost/decimal/detail/cmath/frexp10.hpp @@ -37,11 +37,13 @@ constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_t *expptr = 0; return 0; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (isinf(num) || isnan(num)) { *expptr = 0; return (std::numeric_limits::max)(); } + #endif auto num_exp {num.biased_exponent()}; auto num_sig {num.full_significand()}; diff --git a/include/boost/decimal/detail/cmath/hypot.hpp b/include/boost/decimal/detail/cmath/hypot.hpp index 898b7be7..cb354a37 100644 --- a/include/boost/decimal/detail/cmath/hypot.hpp +++ b/include/boost/decimal/detail/cmath/hypot.hpp @@ -30,19 +30,29 @@ constexpr auto hypot_impl(T x, T y) noexcept { constexpr T zero {0, 0}; - if (abs(x) == zero || isnan(y)) + if (abs(x) == zero + #ifndef BOOST_DECIMAL_FAST_MATH + || isnan(y) + #endif + ) { return y; } - else if (abs(y) == zero || isnan(x)) + else if (abs(y) == zero + #ifndef BOOST_DECIMAL_FAST_MATH + || isnan(x) + #endif + ) { return x; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (isinf(x) || isinf(y)) { // Return +inf even if the other value is nan return std::numeric_limits::infinity(); } + #endif auto new_x {abs(x)}; auto new_y {abs(y)}; @@ -64,6 +74,7 @@ constexpr auto hypot_impl(T x, T y) noexcept template constexpr auto hypot_impl(T x, T y, T z) noexcept { + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(x) || isinf(y) || isinf(z)) { return std::numeric_limits::infinity(); @@ -80,6 +91,7 @@ constexpr auto hypot_impl(T x, T y, T z) noexcept { return z; } + #endif const auto a {fmax(fmax(x, y), z)}; const auto x_over_a {x / a}; diff --git a/include/boost/decimal/detail/cmath/ilogb.hpp b/include/boost/decimal/detail/cmath/ilogb.hpp index 5e175545..3f032dba 100644 --- a/include/boost/decimal/detail/cmath/ilogb.hpp +++ b/include/boost/decimal/detail/cmath/ilogb.hpp @@ -30,6 +30,7 @@ constexpr auto ilogb(T d) noexcept { result = static_cast(FP_ILOGB0); } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc == FP_INFINITE) { result = static_cast(INT_MAX); @@ -38,6 +39,7 @@ constexpr auto ilogb(T d) noexcept { result = static_cast(FP_ILOGBNAN); } + #endif else { const auto offset = detail::num_digits(d.full_significand()) - 1; diff --git a/include/boost/decimal/detail/cmath/isfinite.hpp b/include/boost/decimal/detail/cmath/isfinite.hpp index d1306656..8ca37443 100644 --- a/include/boost/decimal/detail/cmath/isfinite.hpp +++ b/include/boost/decimal/detail/cmath/isfinite.hpp @@ -22,7 +22,11 @@ BOOST_DECIMAL_EXPORT template constexpr auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (T rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, T, bool) { + #ifndef BOOST_DECIMAL_FAST_MATH return !isinf(rhs) && !isnan(rhs); + #else + return true; + #endif } } // namespace decimal diff --git a/include/boost/decimal/detail/cmath/isgreater.hpp b/include/boost/decimal/detail/cmath/isgreater.hpp index 3538d82e..95db13cb 100644 --- a/include/boost/decimal/detail/cmath/isgreater.hpp +++ b/include/boost/decimal/detail/cmath/isgreater.hpp @@ -22,10 +22,12 @@ BOOST_DECIMAL_EXPORT template constexpr auto isgreater(T lhs, T rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, T, bool) { + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isnan(rhs)) { return false; } + #endif return lhs > rhs; } @@ -34,10 +36,12 @@ BOOST_DECIMAL_EXPORT template constexpr auto isgreaterequal(T lhs, T rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, T, bool) { + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isnan(rhs)) { return false; } + #endif return lhs >= rhs; } diff --git a/include/boost/decimal/detail/cmath/isless.hpp b/include/boost/decimal/detail/cmath/isless.hpp index 9ad61fdc..7efd0208 100644 --- a/include/boost/decimal/detail/cmath/isless.hpp +++ b/include/boost/decimal/detail/cmath/isless.hpp @@ -22,10 +22,12 @@ BOOST_DECIMAL_EXPORT template constexpr auto isless(T lhs, T rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, T, bool) { + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isnan(rhs)) { return false; } + #endif return lhs < rhs; } @@ -34,10 +36,12 @@ BOOST_DECIMAL_EXPORT template constexpr auto islessequal(T lhs, T rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, T, bool) { + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isnan(rhs)) { return false; } + #endif return lhs <= rhs; } @@ -46,10 +50,12 @@ BOOST_DECIMAL_EXPORT template constexpr auto islessgreater(T lhs, T rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, T, bool) { + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isnan(rhs)) { return false; } + #endif return lhs < rhs || lhs > rhs; } diff --git a/include/boost/decimal/detail/cmath/isunordered.hpp b/include/boost/decimal/detail/cmath/isunordered.hpp index 43ddb332..3f3e6989 100644 --- a/include/boost/decimal/detail/cmath/isunordered.hpp +++ b/include/boost/decimal/detail/cmath/isunordered.hpp @@ -22,7 +22,11 @@ BOOST_DECIMAL_EXPORT template constexpr auto isunordered(T lhs, T rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, T, bool) { + #ifndef BOOST_DECIMAL_FAST_MATH return isnan(lhs) || isnan(rhs); + #else + return false; + #endif } } // namespace decimal diff --git a/include/boost/decimal/detail/cmath/ldexp.hpp b/include/boost/decimal/detail/cmath/ldexp.hpp index 47e5cf61..ebdefd99 100644 --- a/include/boost/decimal/detail/cmath/ldexp.hpp +++ b/include/boost/decimal/detail/cmath/ldexp.hpp @@ -30,6 +30,7 @@ constexpr auto ldexp_impl(T v, int e2) noexcept if (v_fp != FP_NORMAL) { + #ifndef BOOST_DECIMAL_FAST_MATH if (v_fp == FP_NAN) { result = std::numeric_limits::quiet_NaN(); @@ -39,6 +40,7 @@ constexpr auto ldexp_impl(T v, int e2) noexcept result = std::numeric_limits::infinity(); } else + #endif { result = T { 0, 0 }; } diff --git a/include/boost/decimal/detail/cmath/legendre.hpp b/include/boost/decimal/detail/cmath/legendre.hpp index 273f81c0..9752087a 100644 --- a/include/boost/decimal/detail/cmath/legendre.hpp +++ b/include/boost/decimal/detail/cmath/legendre.hpp @@ -39,12 +39,18 @@ constexpr auto legendre_impl(unsigned l, T x) noexcept { if (x < -1 || x > 1 || l > 128) { + #ifndef BOOST_DECIMAL_FAST_MATH return std::numeric_limits::quiet_NaN(); + #else + return T{0}; + #endif } + #ifndef BOOST_DECIMAL_FAST_MATH else if (isnan(x)) { return x; } + #endif T p0 {1}; T p1 {x}; diff --git a/include/boost/decimal/detail/cmath/lgamma.hpp b/include/boost/decimal/detail/cmath/lgamma.hpp index 51348aef..af53ed2a 100644 --- a/include/boost/decimal/detail/cmath/lgamma.hpp +++ b/include/boost/decimal/detail/cmath/lgamma.hpp @@ -37,6 +37,7 @@ constexpr auto lgamma_impl(T x) noexcept const auto fpc = fpclassify(x); + #ifndef BOOST_DECIMAL_FAST_MATH if (fpc != FP_NORMAL) { if ((fpc == FP_ZERO) || (fpc == FP_INFINITE)) @@ -48,10 +49,20 @@ constexpr auto lgamma_impl(T x) noexcept result = x; } } + #else + if (fpc == FP_ZERO) + { + result = std::numeric_limits::max(); + } + #endif else if ((is_pure_int) && (nx < 0)) { // Pure negative integer argument. + #ifndef BOOST_DECIMAL_FAST_MATH result = std::numeric_limits::infinity(); + #else + result = T{0}; + #endif } else if ((is_pure_int) && ((nx == 1) || (nx == 2))) { diff --git a/include/boost/decimal/detail/cmath/log.hpp b/include/boost/decimal/detail/cmath/log.hpp index bf2350b2..87d25d41 100644 --- a/include/boost/decimal/detail/cmath/log.hpp +++ b/include/boost/decimal/detail/cmath/log.hpp @@ -38,12 +38,18 @@ constexpr auto log_impl(T x) noexcept } else if (signbit(x) || (fpc == FP_NAN)) { + #ifndef BOOST_DECIMAL_FAST_MATH result = std::numeric_limits::quiet_NaN(); + #else + result = T{0}; + #endif } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc == FP_INFINITE) { result = std::numeric_limits::infinity(); } + #endif else if (x < one) { // Handle reflection. diff --git a/include/boost/decimal/detail/cmath/log10.hpp b/include/boost/decimal/detail/cmath/log10.hpp index 6e884259..97100d6d 100644 --- a/include/boost/decimal/detail/cmath/log10.hpp +++ b/include/boost/decimal/detail/cmath/log10.hpp @@ -33,11 +33,19 @@ constexpr auto log10_impl(T x) noexcept if (fpc == FP_ZERO) { + #ifndef BOOST_DECIMAL_FAST_MATH result = -std::numeric_limits::infinity(); + #else + result = T{0}; + #endif } else if (signbit(x)) { + #ifndef BOOST_DECIMAL_FAST_MATH result = std::numeric_limits::quiet_NaN(); + #else + result = T{0}; + #endif } else if (fpc != FP_NORMAL) { diff --git a/include/boost/decimal/detail/cmath/log1p.hpp b/include/boost/decimal/detail/cmath/log1p.hpp index 810293ff..58de2216 100644 --- a/include/boost/decimal/detail/cmath/log1p.hpp +++ b/include/boost/decimal/detail/cmath/log1p.hpp @@ -37,6 +37,7 @@ constexpr auto log1p_impl(T x) noexcept { result = x; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc != FP_NORMAL) { result = @@ -44,12 +45,17 @@ constexpr auto log1p_impl(T x) noexcept ((fpc == FP_INFINITE) && signbit(x)) ? std::numeric_limits::quiet_NaN() : x ); } + #endif else if (-x >= one) { + #ifndef BOOST_DECIMAL_FAST_MATH result = ( (-x == one) ? -std::numeric_limits::infinity() : std::numeric_limits::quiet_NaN() ); + #else + result = T{0}; + #endif } else { diff --git a/include/boost/decimal/detail/cmath/logb.hpp b/include/boost/decimal/detail/cmath/logb.hpp index 91aede87..00be8063 100644 --- a/include/boost/decimal/detail/cmath/logb.hpp +++ b/include/boost/decimal/detail/cmath/logb.hpp @@ -24,6 +24,7 @@ constexpr auto logb(T num) noexcept { const auto fpc {fpclassify(num)}; + #ifndef BOOST_DECIMAL_FAST_MATH if (fpc == FP_ZERO) { return -std::numeric_limits::infinity(); @@ -36,6 +37,12 @@ constexpr auto logb(T num) noexcept { return num; } + #else + if (fpc == FP_ZERO) + { + return T{0}; + } + #endif const auto offset = detail::num_digits(num.full_significand()) - 1; const auto expval = static_cast(static_cast(num.unbiased_exponent()) + offset); diff --git a/include/boost/decimal/detail/cmath/modf.hpp b/include/boost/decimal/detail/cmath/modf.hpp index e133ee4d..a799e5d9 100644 --- a/include/boost/decimal/detail/cmath/modf.hpp +++ b/include/boost/decimal/detail/cmath/modf.hpp @@ -33,11 +33,13 @@ constexpr auto modf(T x, T* iptr) noexcept *iptr = x; return is_neg ? -zero : zero; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (isnan(x)) { *iptr = x; return x; } + #endif *iptr = (x > zero) ? floor(x) : ceil(x); return (x - *iptr); diff --git a/include/boost/decimal/detail/cmath/next.hpp b/include/boost/decimal/detail/cmath/next.hpp index 4ad4acac..f0febcaf 100644 --- a/include/boost/decimal/detail/cmath/next.hpp +++ b/include/boost/decimal/detail/cmath/next.hpp @@ -33,6 +33,7 @@ template ::epsilon(); diff --git a/include/boost/decimal/detail/cmath/pow.hpp b/include/boost/decimal/detail/cmath/pow.hpp index 0b615b7f..e9dd2ba4 100644 --- a/include/boost/decimal/detail/cmath/pow.hpp +++ b/include/boost/decimal/detail/cmath/pow.hpp @@ -57,6 +57,7 @@ constexpr auto pow(T b, IntegralType p) noexcept result = ((p < static_cast(0)) ? std::numeric_limits::infinity() : ((p_is_odd && signbit(b)) ? -zero : zero)); } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc_x == FP_INFINITE) { if (signbit(b)) @@ -91,6 +92,7 @@ constexpr auto pow(T b, IntegralType p) noexcept result = std::numeric_limits::quiet_NaN(); // LCOV_EXCL_LINE } + #endif else { using local_unsigned_integral_type = std::make_unsigned_t; @@ -173,6 +175,7 @@ constexpr auto pow(T x, T a) noexcept } else if (fpc_x == FP_ZERO) { + #ifndef BOOST_DECIMAL_FAST_MATH if ((fpc_a == FP_NORMAL) || (fpc_a == FP_INFINITE)) { // pow(+/-0, exp), where exp is negative and finite, returns +infinity. @@ -187,7 +190,14 @@ constexpr auto pow(T x, T a) noexcept { result = std::numeric_limits::quiet_NaN(); } + #else + if (fpc_a == FP_NORMAL) + { + result = T{0}; + } + #endif } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc_x == FP_INFINITE) { if ((fpc_a == FP_NORMAL) || (fpc_a == FP_INFINITE)) @@ -206,12 +216,14 @@ constexpr auto pow(T x, T a) noexcept { result = x; } + #endif else { if (fpc_a == FP_ZERO) { result = one; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc_a == FP_INFINITE) { result = @@ -221,6 +233,7 @@ constexpr auto pow(T x, T a) noexcept : one ); } + #endif else { const T a_log_x { a * log(x) }; diff --git a/include/boost/decimal/detail/cmath/remainder.hpp b/include/boost/decimal/detail/cmath/remainder.hpp index 1a151602..8ed8a4d6 100644 --- a/include/boost/decimal/detail/cmath/remainder.hpp +++ b/include/boost/decimal/detail/cmath/remainder.hpp @@ -26,6 +26,7 @@ constexpr auto remainder(T x, T y) noexcept constexpr T zero {0, 0}; constexpr T half {5, -1}; + #ifndef BOOST_DECIMAL_FAST_MATH if ((isinf(x) && !isinf(y)) || (abs(y) == zero && !isnan(x))) { @@ -39,6 +40,12 @@ constexpr auto remainder(T x, T y) noexcept { return y; } + #else + if (abs(y) == zero) + { + return zero; + } + #endif T n {}; const T frac {modf(x / y, &n)}; diff --git a/include/boost/decimal/detail/cmath/remquo.hpp b/include/boost/decimal/detail/cmath/remquo.hpp index 13fed3da..783aec92 100644 --- a/include/boost/decimal/detail/cmath/remquo.hpp +++ b/include/boost/decimal/detail/cmath/remquo.hpp @@ -30,6 +30,7 @@ constexpr auto remquo(T x, T y, int* quo) noexcept constexpr T zero {0, 0}; constexpr T half {5, -1}; + #ifndef BOOST_DECIMAL_FAST_MATH if ((isinf(x) && !isinf(y)) || (abs(y) == zero && !isnan(x))) { @@ -43,6 +44,12 @@ constexpr auto remquo(T x, T y, int* quo) noexcept { return y; } + #else + if (abs(y) == zero) + { + return zero; + } + #endif // Compute quo auto div {x / y}; diff --git a/include/boost/decimal/detail/cmath/riemann_zeta.hpp b/include/boost/decimal/detail/cmath/riemann_zeta.hpp index 8ad26d5c..21915d65 100644 --- a/include/boost/decimal/detail/cmath/riemann_zeta.hpp +++ b/include/boost/decimal/detail/cmath/riemann_zeta.hpp @@ -44,10 +44,12 @@ constexpr auto riemann_zeta_impl(T x) noexcept result = T { 5, -1, true }; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc != FP_NORMAL) { result = ((fpc == FP_INFINITE) ? (is_neg ? -std::numeric_limits::infinity() : one) : x); } + #endif else { if (is_neg) @@ -89,8 +91,11 @@ constexpr auto riemann_zeta_impl(T x) noexcept else { // The argument is exaclty one. The result is complex-infinity. - + #ifndef BOOST_DECIMAL_FAST_MATH result = std::numeric_limits::quiet_NaN(); + #else + result = T{0}; + #endif } } else diff --git a/include/boost/decimal/detail/cmath/rint.hpp b/include/boost/decimal/detail/cmath/rint.hpp index 940c57ce..831f6104 100644 --- a/include/boost/decimal/detail/cmath/rint.hpp +++ b/include/boost/decimal/detail/cmath/rint.hpp @@ -55,6 +55,7 @@ constexpr auto lrint_impl(T num) noexcept -> Int constexpr T lmax {(std::numeric_limits::max)()}; constexpr T lmin {(std::numeric_limits::min)()}; + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(num) || isnan(num)) { // Implementation defined what to return here @@ -64,6 +65,12 @@ constexpr auto lrint_impl(T num) noexcept -> Int { return 0; } + #else + if (abs(num) == zero) + { + return zero; + } + #endif int expptr {}; auto sig {frexp10(num, &expptr)}; // Always returns detail::precision digits @@ -112,10 +119,17 @@ constexpr auto rint(T num) noexcept constexpr T zero {0, 0}; constexpr T max_round_value {1 / std::numeric_limits::epsilon()}; + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(num) || isnan(num) || abs(num) == zero || abs(num) > max_round_value) { return num; } + #else + if (abs(num) == zero || abs(num) > max_round_value) + { + return num; + } + #endif int expptr {}; auto sig {frexp10(num, &expptr)}; // Always returns detail::precision digits diff --git a/include/boost/decimal/detail/cmath/round.hpp b/include/boost/decimal/detail/cmath/round.hpp index 3d9e8582..4d78a0b3 100644 --- a/include/boost/decimal/detail/cmath/round.hpp +++ b/include/boost/decimal/detail/cmath/round.hpp @@ -28,10 +28,17 @@ constexpr auto round(T num) noexcept constexpr T zero {0, 0}; constexpr T half {5, -1}; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(num) || isinf(num) || abs(num) == zero) { return num; } + #else + if (abs(num) == zero) + { + return num; + } + #endif T iptr {}; const auto x {modf(num, &iptr)}; @@ -66,6 +73,7 @@ constexpr auto int_round_impl(T num) noexcept -> Int const auto rounded_val {round(num)}; + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(num) || isnan(num)) { return std::numeric_limits::min(); @@ -74,6 +82,12 @@ constexpr auto int_round_impl(T num) noexcept -> Int { return 0; } + #else + if (abs(num) == zero) + { + return 0; + } + #endif if (rounded_val > lmax) { diff --git a/include/boost/decimal/detail/cmath/sin.hpp b/include/boost/decimal/detail/cmath/sin.hpp index 03f5dc03..d3aea106 100644 --- a/include/boost/decimal/detail/cmath/sin.hpp +++ b/include/boost/decimal/detail/cmath/sin.hpp @@ -35,7 +35,11 @@ constexpr auto sin_impl(T x) noexcept const auto fpc = fpclassify(x); // First check non-finite values and small angles. - if (fabs(x) < std::numeric_limits::epsilon() || (fpc == FP_INFINITE) || (fpc == FP_NAN)) + if (fabs(x) < std::numeric_limits::epsilon() + #ifndef BOOST_DECIMAL_FAST_MATH + || (fpc == FP_INFINITE) || (fpc == FP_NAN) + #endif + ) { result = x; } diff --git a/include/boost/decimal/detail/cmath/sinh.hpp b/include/boost/decimal/detail/cmath/sinh.hpp index 123b37c3..98b165a9 100644 --- a/include/boost/decimal/detail/cmath/sinh.hpp +++ b/include/boost/decimal/detail/cmath/sinh.hpp @@ -37,6 +37,7 @@ constexpr auto sinh_impl(T x) noexcept { result = x; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc != FP_NORMAL) { if (fpc == FP_INFINITE) @@ -48,6 +49,7 @@ constexpr auto sinh_impl(T x) noexcept result = x; } } + #endif else { if (signbit(x)) diff --git a/include/boost/decimal/detail/cmath/sqrt.hpp b/include/boost/decimal/detail/cmath/sqrt.hpp index 15711df9..ac17096f 100644 --- a/include/boost/decimal/detail/cmath/sqrt.hpp +++ b/include/boost/decimal/detail/cmath/sqrt.hpp @@ -30,6 +30,7 @@ constexpr auto sqrt_impl(T x) noexcept T result { }; + #ifndef BOOST_DECIMAL_FAST_MATH if ((fpc == FP_NAN) || (fpc == FP_ZERO)) { result = x; @@ -42,6 +43,12 @@ constexpr auto sqrt_impl(T x) noexcept { result = std::numeric_limits::infinity(); } + #else + if (signbit(x)) + { + result = T{0}; + } + #endif else { int exp10val { }; diff --git a/include/boost/decimal/detail/cmath/tan.hpp b/include/boost/decimal/detail/cmath/tan.hpp index 511fd369..5ec3e2d3 100644 --- a/include/boost/decimal/detail/cmath/tan.hpp +++ b/include/boost/decimal/detail/cmath/tan.hpp @@ -33,6 +33,7 @@ constexpr auto tan(T x) noexcept const auto fpc = fpclassify(x); // First check non-finite values and small angles. + #ifndef BOOST_DECIMAL_FAST_MATH if (fabs(x) < std::numeric_limits::epsilon() || (fpc == FP_NAN)) { result = x; @@ -45,6 +46,12 @@ constexpr auto tan(T x) noexcept { result = -tan(-x); } + #else + if (fabs(x) < std::numeric_limits::epsilon()) + { + result = x; + } + #endif else { // Perform argument reduction. diff --git a/include/boost/decimal/detail/cmath/tanh.hpp b/include/boost/decimal/detail/cmath/tanh.hpp index 819b16d2..940d7a3a 100644 --- a/include/boost/decimal/detail/cmath/tanh.hpp +++ b/include/boost/decimal/detail/cmath/tanh.hpp @@ -38,6 +38,7 @@ constexpr auto tanh_impl(T x) noexcept { result = x; } + #ifndef BOOST_DECIMAL_FAST_MATH else if (fpc != FP_NORMAL) { if (fpc == FP_INFINITE) @@ -56,6 +57,7 @@ constexpr auto tanh_impl(T x) noexcept result = x; } } + #endif else { if (signbit(x)) diff --git a/include/boost/decimal/detail/cmath/tgamma.hpp b/include/boost/decimal/detail/cmath/tgamma.hpp index cac238ac..35a5c140 100644 --- a/include/boost/decimal/detail/cmath/tgamma.hpp +++ b/include/boost/decimal/detail/cmath/tgamma.hpp @@ -43,6 +43,7 @@ constexpr auto tgamma_impl(T x) noexcept { result = (is_neg ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); } + #ifndef BOOST_DECIMAL_FAST_MATH else if(fpc == FP_INFINITE) { result = (is_neg ? std::numeric_limits::quiet_NaN() : std::numeric_limits::infinity()); @@ -51,11 +52,16 @@ constexpr auto tgamma_impl(T x) noexcept { result = x; } + #endif } else if (is_pure_int && is_neg) { // Pure negative integer argument. + #ifndef BOOST_DECIMAL_FAST_MATH result = std::numeric_limits::quiet_NaN(); + #else + result = T{0}; + #endif } else { From 5ba059a593a368972bb47c7c43086fc4bbbf423b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 3 Oct 2024 15:42:48 -0400 Subject: [PATCH 003/140] Add fast math to dec32 non-finite funcs --- include/boost/decimal/decimal32.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index 00accccd..686d30bd 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -805,26 +805,43 @@ constexpr auto signbit BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal32 rhs) constexpr auto isnan BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal32 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_ & detail::d32_nan_mask) == detail::d32_nan_mask; + #else + return false; + #endif } constexpr auto issignaling BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal32 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_ & detail::d32_snan_mask) == detail::d32_snan_mask; + #else + return false; + #endif } constexpr auto isinf BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal32 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return ((rhs.bits_ & detail::d32_nan_mask) == detail::d32_inf_mask); + #else + return false; + #endif } constexpr auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal32 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return ((rhs.bits_ & detail::d32_inf_mask) != detail::d32_inf_mask); + #else + return false; + #endif } constexpr auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal32 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH // Check for de-normals const auto sig {rhs.full_significand()}; const auto exp {rhs.unbiased_exponent()}; @@ -835,6 +852,9 @@ constexpr auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal32 rhs) } return (sig != 0) && isfinite(rhs); + #else + return rhs.full_significand() != 0; + #endif } constexpr auto operator+(decimal32 rhs) noexcept -> decimal32 From 51c715afac13c1a6e5e2577558bc3f5c9d769a9c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 3 Oct 2024 15:44:49 -0400 Subject: [PATCH 004/140] Add fast math to dec32_fast non-finite funcs --- include/boost/decimal/decimal32_fast.hpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 348e84dc..eaa5f25d 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -453,22 +453,38 @@ constexpr auto signbit(decimal32_fast val) noexcept -> bool constexpr auto isinf(decimal32_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d32_fast_inf; + #else + return false; + #endif } constexpr auto isnan(decimal32_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d32_fast_qnan || val.significand_ == detail::d32_fast_snan; + #else + return false; + #endif } constexpr auto issignaling(decimal32_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d32_fast_snan; + #else + return false; + #endif } constexpr auto isnormal(decimal32_fast val) noexcept -> bool { - return (val.significand_ != 0) && isfinite(val) && (val.exponent_ > static_cast(detail::precision_v - 1)); + return (val.significand_ != 0) + #ifndef BOOST_DECIMAL_FAST_MATH + && isfinite(val) && (val.exponent_ > static_cast(detail::precision_v - 1)) + #endif + ; } constexpr auto isfinite(decimal32_fast val) noexcept -> bool From 8af37faf27d4fc76be4be1c6ce61bce4cff56522 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 3 Oct 2024 16:11:32 -0400 Subject: [PATCH 005/140] Add fast math to dec64 non-finite funcs --- include/boost/decimal/decimal64.hpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 95df42ed..bcc5b1fe 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -1082,21 +1082,34 @@ constexpr auto signbit BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 rhs) constexpr auto isnan BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_ & detail::d64_nan_mask) == detail::d64_nan_mask; + #else + return false; + #endif } constexpr auto isinf BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return ((rhs.bits_ & detail::d64_nan_mask) == detail::d64_inf_mask); + #else + return false; + #endif } constexpr auto issignaling BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_ & detail::d64_snan_mask) == detail::d64_snan_mask; + #else + return false; + #endif } constexpr auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH // Check for de-normals const auto sig {rhs.full_significand()}; const auto exp {rhs.unbiased_exponent()}; @@ -1107,16 +1120,27 @@ constexpr auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 rhs) } return (sig != 0) && isfinite(rhs); + #else + return rhs.full_significand() != 0; + #endif } constexpr auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return ((rhs.bits_ & detail::d64_inf_mask) != detail::d64_inf_mask); + #else + return true; + #endif } constexpr auto not_finite(decimal64 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return ((rhs.bits_ & detail::d64_inf_mask) == detail::d64_inf_mask); + #else + return false; + #endif } constexpr auto operator+(decimal64 rhs) noexcept -> decimal64 From 4bcd6e99b86c2b7ad9f8cfc88112149b99c06285 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 3 Oct 2024 16:15:13 -0400 Subject: [PATCH 006/140] Add fast math to dec64_fast non-finite funcs --- include/boost/decimal/decimal64_fast.hpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 1d3742db..88ad4bec 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -458,28 +458,44 @@ constexpr auto signbit(decimal64_fast val) noexcept -> bool constexpr auto isinf(decimal64_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d64_fast_inf; + #else + return false; + #endif } constexpr auto isnan(decimal64_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d64_fast_qnan || val.significand_ == detail::d64_fast_snan; + #else + return false; + #endif } constexpr auto issignaling(decimal64_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d64_fast_snan; + #else + return false; + #endif } constexpr auto isnormal(decimal64_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH if (val.exponent_ <= static_cast(detail::precision_v - 1)) { return false; } return (val.significand_ != 0) && isfinite(val); + #else + return val.significand_ != 0; + #endif } constexpr auto isfinite(decimal64_fast val) noexcept -> bool From 571a6a610f230b3107fcc5fc8b3b9e3c3295a741 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 3 Oct 2024 16:17:05 -0400 Subject: [PATCH 007/140] Add fast math to dec128 non-finite funcs --- include/boost/decimal/decimal128.hpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/boost/decimal/decimal128.hpp b/include/boost/decimal/decimal128.hpp index 1da9b031..d1183014 100644 --- a/include/boost/decimal/decimal128.hpp +++ b/include/boost/decimal/decimal128.hpp @@ -1122,21 +1122,34 @@ constexpr auto signbit BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) constexpr auto isnan BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_.high & detail::d128_nan_mask_high_bits) == detail::d128_nan_mask_high_bits; + #else + return false; + #endif } constexpr auto isinf BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_.high & detail::d128_nan_mask_high_bits) == detail::d128_inf_mask_high_bits; + #else + return false; + #endif } constexpr auto issignaling BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_.high & detail::d128_snan_mask_high_bits) == detail::d128_snan_mask_high_bits; + #else + return false; + #endif } constexpr auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH // Check for de-normals const auto sig {rhs.full_significand()}; const auto exp {rhs.unbiased_exponent()}; @@ -1147,16 +1160,27 @@ constexpr auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs } return (sig != 0) && isfinite(rhs); + #else + return rhs.full_significand() != 0; + #endif } constexpr auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_.high & detail::d128_inf_mask_high_bits) != detail::d128_inf_mask_high_bits; + #else + return true; + #endif } constexpr auto not_finite(decimal128 rhs) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_.high & detail::d128_inf_mask_high_bits) == detail::d128_inf_mask_high_bits; + #else + return false; + #endif } constexpr auto operator+(decimal128 rhs) noexcept -> decimal128 From a61089d4e2057d31b8e9fdfe32d88b66591b8cae Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 3 Oct 2024 16:19:00 -0400 Subject: [PATCH 008/140] Add fast math to dec128_fast --- include/boost/decimal/decimal128_fast.hpp | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index 655669f9..e3cf9966 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -468,37 +468,61 @@ constexpr auto signbit(decimal128_fast val) noexcept -> bool constexpr auto isinf(decimal128_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_.high == detail::d128_fast_inf_high_bits; + #else + return false; + #endif } constexpr auto isnan(decimal128_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_.high >= detail::d128_fast_qnan_high_bits; + #else + return false; + #endif } constexpr auto issignaling(decimal128_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_.high == detail::d128_fast_snan_high_bits; + #else + return false; + #endif } constexpr auto isnormal(decimal128_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH if (val.exponent_ <= static_cast(detail::precision_v - 1)) { return false; } return (val.significand_ != 0) && isfinite(val); + #else + return val.significand_ != 0; + #endif } constexpr auto isfinite(decimal128_fast val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_.high < detail::d128_fast_inf_high_bits; + #else + return true; + #endif } constexpr auto not_finite(const decimal128_fast& val) noexcept -> bool { + #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_.high >= detail::d128_fast_inf_high_bits; + #else + return false; + #endif } constexpr auto operator==(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> bool From 4d4e64627869ca11c22d60ab9314f6e66fea666d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 3 Oct 2024 16:53:47 -0400 Subject: [PATCH 009/140] Fix closure --- include/boost/decimal/detail/cmath/atan.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/detail/cmath/atan.hpp b/include/boost/decimal/detail/cmath/atan.hpp index 678433b9..26fd3edd 100644 --- a/include/boost/decimal/detail/cmath/atan.hpp +++ b/include/boost/decimal/detail/cmath/atan.hpp @@ -35,8 +35,9 @@ constexpr auto atan_impl(T x) noexcept if (fpc == FP_ZERO #ifndef BOOST_DECIMAL_FAST_MATH - || fpc == FP_NAN) + || fpc == FP_NAN #endif + ) { result = x; } From ecdea343240e594989fac6695815929acf7db50e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 09:52:37 -0400 Subject: [PATCH 010/140] Remove unused alias --- include/boost/decimal/detail/cmath/frexp10.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/boost/decimal/detail/cmath/frexp10.hpp b/include/boost/decimal/detail/cmath/frexp10.hpp index 6d6e75d6..76339bae 100644 --- a/include/boost/decimal/detail/cmath/frexp10.hpp +++ b/include/boost/decimal/detail/cmath/frexp10.hpp @@ -28,8 +28,6 @@ namespace decimal { BOOST_DECIMAL_EXPORT template constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_type { - using ReturnType = typename T::significand_type; - constexpr T zero {0, 0}; if (num == zero) @@ -41,7 +39,7 @@ constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_t else if (isinf(num) || isnan(num)) { *expptr = 0; - return (std::numeric_limits::max)(); + return (std::numeric_limits::max)(); } #endif From 9d1de04d93e8f4042ded2dde9ceae7e685a35b28 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 09:57:10 -0400 Subject: [PATCH 011/140] Fix GCC unused variable warnings --- include/boost/decimal/decimal128.hpp | 5 +++++ include/boost/decimal/decimal128_fast.hpp | 5 +++++ include/boost/decimal/decimal32.hpp | 4 ++++ include/boost/decimal/decimal32_fast.hpp | 3 +++ include/boost/decimal/decimal64.hpp | 5 +++++ include/boost/decimal/decimal64_fast.hpp | 3 +++ 6 files changed, 25 insertions(+) diff --git a/include/boost/decimal/decimal128.hpp b/include/boost/decimal/decimal128.hpp index d1183014..9639eb40 100644 --- a/include/boost/decimal/decimal128.hpp +++ b/include/boost/decimal/decimal128.hpp @@ -1125,6 +1125,7 @@ constexpr auto isnan BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) n #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_.high & detail::d128_nan_mask_high_bits) == detail::d128_nan_mask_high_bits; #else + static_cast(rhs); return false; #endif } @@ -1134,6 +1135,7 @@ constexpr auto isinf BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) n #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_.high & detail::d128_nan_mask_high_bits) == detail::d128_inf_mask_high_bits; #else + static_cast(rhs); return false; #endif } @@ -1143,6 +1145,7 @@ constexpr auto issignaling BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_.high & detail::d128_snan_mask_high_bits) == detail::d128_snan_mask_high_bits; #else + static_cast(rhs); return false; #endif } @@ -1170,6 +1173,7 @@ constexpr auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_.high & detail::d128_inf_mask_high_bits) != detail::d128_inf_mask_high_bits; #else + static_cast(rhs); return true; #endif } @@ -1179,6 +1183,7 @@ constexpr auto not_finite(decimal128 rhs) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_.high & detail::d128_inf_mask_high_bits) == detail::d128_inf_mask_high_bits; #else + static_cast(rhs); return false; #endif } diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index e3cf9966..f4bd65d5 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -471,6 +471,7 @@ constexpr auto isinf(decimal128_fast val) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_.high == detail::d128_fast_inf_high_bits; #else + static_cast(val); return false; #endif } @@ -480,6 +481,7 @@ constexpr auto isnan(decimal128_fast val) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_.high >= detail::d128_fast_qnan_high_bits; #else + static_cast(val); return false; #endif } @@ -489,6 +491,7 @@ constexpr auto issignaling(decimal128_fast val) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_.high == detail::d128_fast_snan_high_bits; #else + static_cast(val); return false; #endif } @@ -512,6 +515,7 @@ constexpr auto isfinite(decimal128_fast val) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_.high < detail::d128_fast_inf_high_bits; #else + static_cast(val); return true; #endif } @@ -521,6 +525,7 @@ constexpr auto not_finite(const decimal128_fast& val) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_.high >= detail::d128_fast_inf_high_bits; #else + static_cast(val); return false; #endif } diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index 686d30bd..df4e3629 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -808,6 +808,7 @@ constexpr auto isnan BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal32 rhs) no #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_ & detail::d32_nan_mask) == detail::d32_nan_mask; #else + static_cast(rhs); return false; #endif } @@ -817,6 +818,7 @@ constexpr auto issignaling BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal32 r #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_ & detail::d32_snan_mask) == detail::d32_snan_mask; #else + static_cast(rhs); return false; #endif } @@ -826,6 +828,7 @@ constexpr auto isinf BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal32 rhs) no #ifndef BOOST_DECIMAL_FAST_MATH return ((rhs.bits_ & detail::d32_nan_mask) == detail::d32_inf_mask); #else + static_cast(rhs); return false; #endif } @@ -835,6 +838,7 @@ constexpr auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal32 rhs) #ifndef BOOST_DECIMAL_FAST_MATH return ((rhs.bits_ & detail::d32_inf_mask) != detail::d32_inf_mask); #else + static_cast(rhs); return false; #endif } diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index eaa5f25d..b650ff2d 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -456,6 +456,7 @@ constexpr auto isinf(decimal32_fast val) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d32_fast_inf; #else + static_cast(val); return false; #endif } @@ -465,6 +466,7 @@ constexpr auto isnan(decimal32_fast val) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d32_fast_qnan || val.significand_ == detail::d32_fast_snan; #else + static_cast(val); return false; #endif } @@ -474,6 +476,7 @@ constexpr auto issignaling(decimal32_fast val) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d32_fast_snan; #else + static_cast(val); return false; #endif } diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index bcc5b1fe..59e5e64d 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -1085,6 +1085,7 @@ constexpr auto isnan BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 rhs) no #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_ & detail::d64_nan_mask) == detail::d64_nan_mask; #else + static_cast(rhs); return false; #endif } @@ -1094,6 +1095,7 @@ constexpr auto isinf BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 rhs) no #ifndef BOOST_DECIMAL_FAST_MATH return ((rhs.bits_ & detail::d64_nan_mask) == detail::d64_inf_mask); #else + static_cast(rhs); return false; #endif } @@ -1103,6 +1105,7 @@ constexpr auto issignaling BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 r #ifndef BOOST_DECIMAL_FAST_MATH return (rhs.bits_ & detail::d64_snan_mask) == detail::d64_snan_mask; #else + static_cast(rhs); return false; #endif } @@ -1130,6 +1133,7 @@ constexpr auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 rhs) #ifndef BOOST_DECIMAL_FAST_MATH return ((rhs.bits_ & detail::d64_inf_mask) != detail::d64_inf_mask); #else + static_cast(rhs); return true; #endif } @@ -1139,6 +1143,7 @@ constexpr auto not_finite(decimal64 rhs) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return ((rhs.bits_ & detail::d64_inf_mask) == detail::d64_inf_mask); #else + static_cast(rhs); return false; #endif } diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 88ad4bec..5a30f1a6 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -461,6 +461,7 @@ constexpr auto isinf(decimal64_fast val) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d64_fast_inf; #else + static_cast(val); return false; #endif } @@ -471,6 +472,7 @@ constexpr auto isnan(decimal64_fast val) noexcept -> bool return val.significand_ == detail::d64_fast_qnan || val.significand_ == detail::d64_fast_snan; #else + static_cast(val); return false; #endif } @@ -480,6 +482,7 @@ constexpr auto issignaling(decimal64_fast val) noexcept -> bool #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d64_fast_snan; #else + static_cast(val); return false; #endif } From 4b8b844890537cb9d3a3c15e74c6cac1d9cad726 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 10:15:18 -0400 Subject: [PATCH 012/140] Expand section on macros --- doc/decimal/config.adoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/decimal/config.adoc b/doc/decimal/config.adoc index 4c299754..71988278 100644 --- a/doc/decimal/config.adoc +++ b/doc/decimal/config.adoc @@ -8,6 +8,8 @@ https://www.boost.org/LICENSE_1_0.txt = Configuration Macros :idprefix: config_ +== User Configurable Macros + The following configuration macros are available: - `BOOST_DECIMAL_DISABLE_CASSERT`: Disables the use of `` and all run-time assertions. @@ -28,3 +30,15 @@ const auto res = std::acos(test_val); - `BOOST_DECIMAL_FAST_MATH` performs optimizations similar to that of the `-ffast-math` compiler flag such as removing all checks for non-finite values. This flag increases the performance of the basis operations (e.g. add, sub, mul, div, and comparisons) by up to 20%. + +- `BOOST_DECIMAL_DEC_EVAL_METHOD`: See section for explanation + +== Automatic Configuration Macros + +- `BOOST_DECIMAL_CXX20_CONSTEXPR`: This is defined to `constexpr` when compiling with C++20 or greater, otherwise it expands to nothing. + +- `BOOST_DECIMAL_CONSTEXPR`: This is defined to `constexpr` when any of the following are met: + * _MSC_FULL_VER >= 192528326 + * __GNUC__ >= 9 + * Compiler has: __builtin_is_constant_evaluated() + * C++20 support with: std::is_constant_evaluated() From 2410a77062a2ac366e04dab411b21135e6ef2012 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 10:44:27 -0400 Subject: [PATCH 013/140] Add separators to charconv docs --- doc/decimal/charconv.adoc | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/doc/decimal/charconv.adoc b/doc/decimal/charconv.adoc index e3e48038..0197fb90 100644 --- a/doc/decimal/charconv.adoc +++ b/doc/decimal/charconv.adoc @@ -17,6 +17,8 @@ The standard for does not distinguish between underflow and overflow `boost::decimal::from_chars` modifies `value` in order to communicate this to the user in a divergence from the standard. This behavior is the same as that of https://www.boost.org/doc/libs/master/libs/charconv/doc/html/charconv.html#from_chars_usage_notes_for_from_chars_for_floating_point_types[`boost::charconv::from_chars_erange`]. +[#chars_format] +== chars_format [source, c++] ---- namespace boost { @@ -30,6 +32,17 @@ enum class chars_format : unsigned general = fixed | scientific }; +} //namespace decimal +} //namespace boost +---- + +[#from_chars_result] +== from_chars_result +[source, c++] +---- +namespace boost { +namespace decimal { + struct from_chars_result { const char* ptr; @@ -40,6 +53,17 @@ struct from_chars_result constexpr explicit operator bool() const noexcept { return ec == std::errc{}; } } +} //namespace decimal +} //namespace boost +---- + +[#to_chars_result] +== to_chars_result +[source, c++] +---- +namespace boost { +namespace decimal { + struct to_chars_result { char* ptr; @@ -50,9 +74,31 @@ struct to_chars_result constexpr explicit operator bool() const noexcept { return ec == std::errc{}; } } +} //namespace decimal +} //namespace boost +---- + +[#from_chars] +== from_chars +[source, c++] +---- +namespace boost { +namespace decimal { + template constexpr from_chars_result from_chars(const char* first, const char* last, DecimalType& value, chars_format fmt = chars_format::general) +} //namespace decimal +} //namespace boost +---- + +[#to_chars] +== to_chars +[source, c++] +---- +namespace boost { +namespace decimal { + template BOOST_DECIMAL_CONSTEXPR to_chars_result to_chars(char* first, char* last, DecimalType value) noexcept; @@ -74,6 +120,8 @@ NOTE: `BOOST_DECIMAL_CONSTEXPR` is defined if: - C++20 support with: `std::is_constant_evaluated()` The library offers an additional feature for sizing buffers without specified precision and in general format + +== limits [source, c++] ---- namespace boost { From 8fca3d1e2bd4ffcaec23a75679e82904f513dc94 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 10:57:21 -0400 Subject: [PATCH 014/140] Add API reference section at the top --- doc/decimal.adoc | 1 + doc/decimal/api_reference.adoc | 41 ++++++++++++++++++++++++++++++++++ doc/decimal/charconv.adoc | 1 + 3 files changed, 43 insertions(+) create mode 100644 doc/decimal/api_reference.adoc diff --git a/doc/decimal.adoc b/doc/decimal.adoc index b929d3ac..a954151d 100644 --- a/doc/decimal.adoc +++ b/doc/decimal.adoc @@ -16,6 +16,7 @@ https://www.boost.org/LICENSE_1_0.txt :leveloffset: +1 include::decimal/overview.adoc[] +include::decimal/api_reference.adoc[] include::decimal/generic_decimal.adoc[] include::decimal/decimal32.adoc[] include::decimal/decimal64.adoc[] diff --git a/doc/decimal/api_reference.adoc b/doc/decimal/api_reference.adoc new file mode 100644 index 00000000..d6439603 --- /dev/null +++ b/doc/decimal/api_reference.adoc @@ -0,0 +1,41 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#api_reference] += API Reference +:idprefix: api_ref_ + +== Types + +=== IEEE 754 Compliant Types + +- <> +- <> +- <> + +=== Non-IEEE 754 Compliant Types + +- <> +- <> +- <> + +== Structures + +- <> +- <> + +== Enums + +- <> + +== Constants + +- <> +- <> + +== Macros + +See: <> diff --git a/doc/decimal/charconv.adoc b/doc/decimal/charconv.adoc index 0197fb90..df146c81 100644 --- a/doc/decimal/charconv.adoc +++ b/doc/decimal/charconv.adoc @@ -121,6 +121,7 @@ NOTE: `BOOST_DECIMAL_CONSTEXPR` is defined if: The library offers an additional feature for sizing buffers without specified precision and in general format +[#charconv_limits] == limits [source, c++] ---- From d2d488c14b504eee8224ff646b17820002f0c192 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 10:59:47 -0400 Subject: [PATCH 015/140] Remove attribute from limits section --- doc/decimal/limits.adoc | 192 ++++++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/doc/decimal/limits.adoc b/doc/decimal/limits.adoc index 7e7e2291..8f83644c 100644 --- a/doc/decimal/limits.adoc +++ b/doc/decimal/limits.adoc @@ -28,45 +28,45 @@ struct numeric_limits public: #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_signed = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_integer = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_exact = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_infinity = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = true; + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; // These members were deprecated in C++23 #if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L))) - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_denorm_style has_denorm = std::denorm_present; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_denorm_loss = true; + static constexpr std::float_denorm_style has_denorm = std::denorm_present; + static constexpr bool has_denorm_loss = true; #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_indeterminate; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_modulo = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits = 7; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int radix = 10; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent = -95; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = min_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent = 96; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = max_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = numeric_limits::traps; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = true; + static constexpr std::float_round_style round_style = std::round_indeterminate; + static constexpr bool is_iec559 = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 7; + static constexpr int digits10 = digits; + static constexpr int max_digits10 = digits; + static constexpr int radix = 10; + static constexpr int min_exponent = -95; + static constexpr int min_exponent10 = min_exponent; + static constexpr int max_exponent = 96; + static constexpr int max_exponent10 = max_exponent; + static constexpr bool traps = numeric_limits::traps; + static constexpr bool tinyness_before = true; // Member functions - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal32 min() - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal32 max(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal32 lowest(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal32 epsilon(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal32 round_error(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal32 infinity(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal32 quiet_NaN(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal32 signaling_NaN(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal32 denorm_min(); + static constexpr boost::decimal::decimal32 min() + static constexpr boost::decimal::decimal32 max(); + static constexpr boost::decimal::decimal32 lowest(); + static constexpr boost::decimal::decimal32 epsilon(); + static constexpr boost::decimal::decimal32 round_error(); + static constexpr boost::decimal::decimal32 infinity(); + static constexpr boost::decimal::decimal32 quiet_NaN(); + static constexpr boost::decimal::decimal32 signaling_NaN(); + static constexpr boost::decimal::decimal32 denorm_min(); }; template <> @@ -81,45 +81,45 @@ struct numeric_limits public: #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_signed = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_integer = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_exact = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_infinity = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = true; + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; // These members were deprecated in C++23 #if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L))) - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_denorm_style has_denorm = std::denorm_present; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_denorm_loss = true; + static constexpr std::float_denorm_style has_denorm = std::denorm_present; + static constexpr bool has_denorm_loss = true; #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_indeterminate; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_modulo = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits = 16; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int radix = 10; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent = -382; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = min_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent = 385; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = max_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = numeric_limits::traps; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = true; + static constexpr std::float_round_style round_style = std::round_indeterminate; + static constexpr bool is_iec559 = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 16; + static constexpr int digits10 = digits; + static constexpr int max_digits10 = digits; + static constexpr int radix = 10; + static constexpr int min_exponent = -382; + static constexpr int min_exponent10 = min_exponent; + static constexpr int max_exponent = 385; + static constexpr int max_exponent10 = max_exponent; + static constexpr bool traps = numeric_limits::traps; + static constexpr bool tinyness_before = true; // Member functions - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal64 min() - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal64 max(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal64 lowest(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal64 epsilon(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal64 round_error(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal64 infinity(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal64 quiet_NaN(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal64 signaling_NaN(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal64 denorm_min(); + static constexpr boost::decimal::decimal64 min() + static constexpr boost::decimal::decimal64 max(); + static constexpr boost::decimal::decimal64 lowest(); + static constexpr boost::decimal::decimal64 epsilon(); + static constexpr boost::decimal::decimal64 round_error(); + static constexpr boost::decimal::decimal64 infinity(); + static constexpr boost::decimal::decimal64 quiet_NaN(); + static constexpr boost::decimal::decimal64 signaling_NaN(); + static constexpr boost::decimal::decimal64 denorm_min(); }; template<> @@ -134,45 +134,45 @@ struct numeric_limits public: #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_signed = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_integer = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_exact = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_infinity = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = true; + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; // These members were deprecated in C++23 #if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L))) - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_denorm_style has_denorm = std::denorm_present; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_denorm_loss = true; + static constexpr std::float_denorm_style has_denorm = std::denorm_present; + static constexpr bool has_denorm_loss = true; #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_indeterminate; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_modulo = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits = 34; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int radix = 10; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent = -6142; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = min_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent = 6145; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = max_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = numeric_limits::traps; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = true; + static constexpr std::float_round_style round_style = std::round_indeterminate; + static constexpr bool is_iec559 = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 34; + static constexpr int digits10 = digits; + static constexpr int max_digits10 = digits; + static constexpr int radix = 10; + static constexpr int min_exponent = -6142; + static constexpr int min_exponent10 = min_exponent; + static constexpr int max_exponent = 6145; + static constexpr int max_exponent10 = max_exponent; + static constexpr bool traps = numeric_limits::traps; + static constexpr bool tinyness_before = true; // Member functions - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal128 min() - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal128 max(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal128 lowest(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal128 epsilon(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal128 round_error(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal128 infinity(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal128 quiet_NaN(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal128 signaling_NaN(); - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr boost::decimal::decimal128 denorm_min(); + static constexpr boost::decimal::decimal128 min() + static constexpr boost::decimal::decimal128 max(); + static constexpr boost::decimal::decimal128 lowest(); + static constexpr boost::decimal::decimal128 epsilon(); + static constexpr boost::decimal::decimal128 round_error(); + static constexpr boost::decimal::decimal128 infinity(); + static constexpr boost::decimal::decimal128 quiet_NaN(); + static constexpr boost::decimal::decimal128 signaling_NaN(); + static constexpr boost::decimal::decimal128 denorm_min(); }; } // Namespace std From 1af115d1079928c3684a8b57741520a3c5093bce Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 11:16:33 -0400 Subject: [PATCH 016/140] Fix clang unused parameter errors --- include/boost/decimal/detail/cmath/isfinite.hpp | 1 + include/boost/decimal/detail/cmath/isunordered.hpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/boost/decimal/detail/cmath/isfinite.hpp b/include/boost/decimal/detail/cmath/isfinite.hpp index 8ca37443..c9a9fa1d 100644 --- a/include/boost/decimal/detail/cmath/isfinite.hpp +++ b/include/boost/decimal/detail/cmath/isfinite.hpp @@ -25,6 +25,7 @@ constexpr auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (T rhs) noexcep #ifndef BOOST_DECIMAL_FAST_MATH return !isinf(rhs) && !isnan(rhs); #else + static_cast(rhs); return true; #endif } diff --git a/include/boost/decimal/detail/cmath/isunordered.hpp b/include/boost/decimal/detail/cmath/isunordered.hpp index 3f3e6989..8d687291 100644 --- a/include/boost/decimal/detail/cmath/isunordered.hpp +++ b/include/boost/decimal/detail/cmath/isunordered.hpp @@ -25,6 +25,8 @@ constexpr auto isunordered(T lhs, T rhs) noexcept #ifndef BOOST_DECIMAL_FAST_MATH return isnan(lhs) || isnan(rhs); #else + static_cast(lhs); + static_cast(rhs); return false; #endif } From 4e743d915ab57469915548ec2b3ab2dd8c729aef Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 12:13:22 -0400 Subject: [PATCH 017/140] Add detection of header charconv with macro if available --- include/boost/decimal/detail/config.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 7507557a..7cb539ac 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -312,4 +312,13 @@ typedef unsigned __int128 uint128_t; # define BOOST_DECIMAL_FAST_MATH #endif +#if __cplusplus >= 201703L +# if __has_include() +# ifndef BOOST_DECIMAL_BUILD_MODULE +# include +# endif +# define BOOST_DECIMAL_HAS_STD_CHARCONV +# endif +#endif + #endif // BOOST_DECIMAL_DETAIL_CONFIG_HPP From 238c7099b7b7d17f67a9522eca9cd6dad691641f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 12:14:06 -0400 Subject: [PATCH 018/140] Add from_chars overload that takes and return std:: types --- include/boost/decimal/charconv.hpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/boost/decimal/charconv.hpp b/include/boost/decimal/charconv.hpp index 1ad74ea8..51669ffa 100644 --- a/include/boost/decimal/charconv.hpp +++ b/include/boost/decimal/charconv.hpp @@ -119,6 +119,36 @@ BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* la return detail::from_chars_general_impl(first, last, value, fmt); } +#ifdef BOOST_DECIMAL_HAS_STD_CHARCONV +template +BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, DecimalType& value, std::chars_format fmt) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::from_chars_result) +{ + from_chars_result boost_r {}; + switch (fmt) + { + case std::chars_format::scientific: + boost_r = from_chars(first, last, value, chars_format::scientific); + break; + case std::chars_format::fixed: + boost_r = from_chars(first, last, value, chars_format::fixed); + break; + case std::chars_format::hex: + boost_r = from_chars(first, last, value, chars_format::hex); + break; + case std::chars_format::general: + boost_r = from_chars(first, last, value, chars_format::general); + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP + } + + return std::from_chars_result {boost_r.ptr, boost_r.ec}; +} +#endif + // --------------------------------------------------------------------------------------------------------------------- // to_chars and implementation // --------------------------------------------------------------------------------------------------------------------- From 606737d521879d349f45283c5d98a42c7c2dde2a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 12:14:23 -0400 Subject: [PATCH 019/140] Add testing of std:: types from_chars overload --- test/test_from_chars.cpp | 133 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/test/test_from_chars.cpp b/test/test_from_chars.cpp index bc612897..4964a5de 100644 --- a/test/test_from_chars.cpp +++ b/test/test_from_chars.cpp @@ -202,6 +202,122 @@ void test_hex_values() BOOST_TEST_EQ(v3, res_3); } +#ifdef BOOST_DECIMAL_HAS_STD_CHARCONV + +template +void test_from_chars_scientific_std() +{ + std::uniform_real_distribution dist(1e-10F, 1e10F); + + constexpr auto max_iter {std::is_same::value ? N / 4 : N}; + + for (std::size_t i {}; i < max_iter; ++i) + { + char buffer[256] {}; + const auto val {dist(rng)}; + auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), val, boost::charconv::chars_format::scientific); + + if (!r) + { + continue; // LCOV_EXCL_LINE + } + + *r.ptr = '\0'; + + T return_value; + const std::from_chars_result r_dec = from_chars(buffer, buffer + std::strlen(buffer), return_value, std::chars_format::scientific); + const auto ret_value_float = static_cast(return_value); + const auto float_distance = std::abs(boost::math::float_distance(ret_value_float, val)); + + if (!(BOOST_TEST(float_distance <= 10) && BOOST_TEST(r_dec.ec == std::errc()))) + { + // LCOV_EXCL_START + std::cerr << " Value: " << val + << "\n Buffer: " << buffer + << "\n Ret Val: " << return_value + << "\nFloat dist: " << float_distance << std::endl; + // LCOV_EXCL_STOP + } + } +} + +template +void test_from_chars_fixed_std() +{ + std::uniform_real_distribution dist(1e-10F, 1e10F); + + constexpr auto max_iter {std::is_same::value ? N / 4 : N}; + + for (std::size_t i {}; i < max_iter; ++i) + { + char buffer[256] {}; + const auto val {dist(rng)}; + auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), val, boost::charconv::chars_format::fixed); + + if (!r) + { + continue; // LCOV_EXCL_LINE + } + + *r.ptr = '\0'; + + T return_value; + const std::from_chars_result r_dec = from_chars(buffer, buffer + std::strlen(buffer), return_value, std::chars_format::fixed); + + const auto ret_value_float = static_cast(return_value); + const auto float_distance = std::abs(boost::math::float_distance(ret_value_float, val)); + + if (!(BOOST_TEST(float_distance <= 10) && BOOST_TEST(r_dec.ec == std::errc()))) + { + // LCOV_EXCL_START + std::cerr << " Value: " << val + << "\n Buffer: " << buffer + << "\n Ret Val: " << return_value + << "\nFloat dist: " << float_distance << std::endl; + // LCOV_EXCL_STOP + } + } +} + +template +void test_from_chars_general_std() +{ + std::uniform_real_distribution dist(1e-10F, 1e10F); + + constexpr auto max_iter {std::is_same::value ? N / 4 : N}; + + for (std::size_t i {}; i < max_iter; ++i) + { + char buffer[256] {}; + const auto val {dist(rng)}; + auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), val, boost::charconv::chars_format::general); + + if (!r) + { + continue; // LCOV_EXCL_LINE + } + + *r.ptr = '\0'; + + T return_value; + const std::from_chars_result r_dec = from_chars(buffer, buffer + std::strlen(buffer), return_value, std::chars_format::general); + const auto ret_value_float = static_cast(return_value); + const auto float_distance = std::abs(boost::math::float_distance(ret_value_float, val)); + + if (!(BOOST_TEST(float_distance <= 10) && BOOST_TEST(r_dec.ec == std::errc()))) + { + // LCOV_EXCL_START + std::cerr << " Value: " << val + << "\n Buffer: " << buffer + << "\n Ret Val: " << return_value + << "\nFloat dist: " << float_distance << std::endl; + // LCOV_EXCL_STOP + } + } +} + +#endif + int main() { test_from_chars_scientific(); @@ -219,6 +335,23 @@ int main() test_from_chars_general(); test_from_chars_general(); + #ifdef BOOST_DECIMAL_HAS_STD_CHARCONV + test_from_chars_scientific_std(); + test_from_chars_scientific_std(); + test_from_chars_scientific_std(); + test_from_chars_scientific_std(); + + test_from_chars_fixed_std(); + test_from_chars_fixed_std(); + test_from_chars_fixed_std(); + test_from_chars_fixed_std(); + + test_from_chars_general_std(); + test_from_chars_general_std(); + test_from_chars_general_std(); + test_from_chars_general_std(); + #endif + test_non_finite_values(); test_non_finite_values(); test_non_finite_values(); From 062d70a42d2b483f4bcf900b863a662b100df7c1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 12:21:36 -0400 Subject: [PATCH 020/140] Add std::from_chars support to the docs --- doc/decimal/charconv.adoc | 11 ++++++++++- doc/decimal/config.adoc | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/doc/decimal/charconv.adoc b/doc/decimal/charconv.adoc index df146c81..fdfeac74 100644 --- a/doc/decimal/charconv.adoc +++ b/doc/decimal/charconv.adoc @@ -86,12 +86,21 @@ namespace boost { namespace decimal { template -constexpr from_chars_result from_chars(const char* first, const char* last, DecimalType& value, chars_format fmt = chars_format::general) +constexpr boost::decimal::from_chars_result from_chars(const char* first, const char* last, DecimalType& value, boost::decimal::chars_format fmt = boost::decimal::chars_format::general) noexcept + +#ifdef BOOST_DECIMAL_HAS_STD_CHARCONV + +template +constexpr std::from_chars_result from_chars(const char* first, const char* last, DecimalType& value, std::chars_format fmt) noexcept + +#endif } //namespace decimal } //namespace boost ---- +IMPORTANT: If `std::chars_format` is used the function will return a `std::from_chars_result` and if `boost::decimal::chars_format` is used *OR* no format is specified then a `boost::decimal::from_chars_result` will be returned. + [#to_chars] == to_chars [source, c++] diff --git a/doc/decimal/config.adoc b/doc/decimal/config.adoc index 71988278..f0d112c8 100644 --- a/doc/decimal/config.adoc +++ b/doc/decimal/config.adoc @@ -42,3 +42,7 @@ This flag increases the performance of the basis operations (e.g. add, sub, mul, * __GNUC__ >= 9 * Compiler has: __builtin_is_constant_evaluated() * C++20 support with: std::is_constant_evaluated() + +- `BOOST_DECIMAL_HAS_STD_CHARCONV`: This macro is defined if header `` exists and the language standard used is >= C++17 + * We only need the structs and enums out of the header so we are not concerned with being overly restrictive about the feature test macros. + Implementations of integer `std::from_chars` and `std::to_chars` existed far before the floating points were completed to allow the feature test macro to be properly set. From 8ea8d0c18d60b3d9e380af11a9da7119b820a67f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 13:28:17 -0400 Subject: [PATCH 021/140] Add to chars overloads for std:: types and enums --- include/boost/decimal/charconv.hpp | 69 +++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/charconv.hpp b/include/boost/decimal/charconv.hpp index 51669ffa..21a7a2ce 100644 --- a/include/boost/decimal/charconv.hpp +++ b/include/boost/decimal/charconv.hpp @@ -120,8 +120,8 @@ BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* la } #ifdef BOOST_DECIMAL_HAS_STD_CHARCONV -template -BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, DecimalType& value, std::chars_format fmt) noexcept +BOOST_DECIMAL_EXPORT template +constexpr auto from_chars(const char* first, const char* last, DecimalType& value, std::chars_format fmt) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::from_chars_result) { from_chars_result boost_r {}; @@ -941,6 +941,71 @@ BOOST_DECIMAL_EXPORT BOOST_DECIMAL_CONSTEXPR auto to_chars(char* first, char* la return detail::to_chars_impl(first, last, value, fmt, precision); } +#ifdef BOOST_DECIMAL_HAS_STD_CHARCONV + +BOOST_DECIMAL_EXPORT template +BOOST_DECIMAL_CONSTEXPR auto to_chars(char* first, char* last, DecimalType value, std::chars_format fmt) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::to_chars_result) +{ + to_chars_result boost_r {}; + switch (fmt) + { + case std::chars_format::scientific: + boost_r = detail::to_chars_impl(first, last, value, chars_format::scientific); + break; + case std::chars_format::fixed: + boost_r = detail::to_chars_impl(first, last, value, chars_format::fixed); + break; + case std::chars_format::hex: + boost_r = detail::to_chars_impl(first, last, value, chars_format::hex); + break; + case std::chars_format::general: + boost_r = detail::to_chars_impl(first, last, value, chars_format::general); + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP + } + + return std::to_chars_result {boost_r.ptr, boost_r.ec}; +} + +BOOST_DECIMAL_EXPORT template +BOOST_DECIMAL_CONSTEXPR auto to_chars(char* first, char* last, DecimalType value, std::chars_format fmt, int precision) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::to_chars_result) +{ + if (precision < 0) + { + precision = 6; + } + + to_chars_result boost_r {}; + switch (fmt) + { + case std::chars_format::scientific: + boost_r = detail::to_chars_impl(first, last, value, chars_format::scientific, precision); + break; + case std::chars_format::fixed: + boost_r = detail::to_chars_impl(first, last, value, chars_format::fixed, precision); + break; + case std::chars_format::hex: + boost_r = detail::to_chars_impl(first, last, value, chars_format::hex, precision); + break; + case std::chars_format::general: + boost_r = detail::to_chars_impl(first, last, value, chars_format::general, precision); + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP + } + + return std::to_chars_result {boost_r.ptr, boost_r.ec}; +} + +#endif // BOOST_DECIMAL_HAS_STD_CHARCONV + template struct limits { From 5a464247924ef803409108f5071407baec7f2c73 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 13:28:30 -0400 Subject: [PATCH 022/140] Add testing of std types --- test/test_to_chars.cpp | 186 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/test/test_to_chars.cpp b/test/test_to_chars.cpp index a6b7479c..c9b2ee4e 100644 --- a/test/test_to_chars.cpp +++ b/test/test_to_chars.cpp @@ -235,6 +235,178 @@ void test_hex_format() } } +#ifdef BOOST_DECIMAL_HAS_STD_CHARCONV + +template +void test_scientific_format_std() +{ + constexpr double max_value = 1e10; + std::uniform_real_distribution dist(-max_value, max_value); + + for (std::size_t i {}; i < N; ++i) + { + char buffer[256] {}; + + const auto val {dist(rng)}; + const T dec_val {val}; + + std::to_chars_result to_r = to_chars(buffer, buffer + sizeof(buffer), dec_val, std::chars_format::scientific); + BOOST_TEST(to_r.ec == std::errc()); + + T ret_val; + std::from_chars_result from_r = from_chars(buffer, buffer + std::strlen(buffer), ret_val, std::chars_format::scientific); + if (!BOOST_TEST(from_r.ec == std::errc())) + { + // LCOV_EXCL_START + std::cerr << std::setprecision(std::numeric_limits::digits10) + << "Value: " << dec_val + << "\nBuffer: " << buffer + << "\nError: " << static_cast(from_r.ec) << std::endl; + + continue; + // LCOV_EXCL_STOP + } + + if (!BOOST_TEST_EQ(dec_val, ret_val)) + { + // LCOV_EXCL_START + std::cerr << std::setprecision(std::numeric_limits::digits10) + << " Value: " << dec_val + << "\n Buffer: " << buffer + << "\nRet val: " << ret_val << std::endl; + // LCOV_EXCL_STOP + } + } +} + +template +void test_fixed_format_std() +{ + constexpr double max_value = 1e10; + std::uniform_real_distribution dist(-max_value, max_value); + + for (std::size_t i {}; i < N; ++i) + { + char buffer[256] {}; + + const auto val {dist(rng)}; + const T dec_val {val}; + + std::to_chars_result to_r = to_chars(buffer, buffer + sizeof(buffer), dec_val, std::chars_format::fixed); + BOOST_TEST(to_r.ec == std::errc()); + + T ret_val; + std::from_chars_result from_r = from_chars(buffer, buffer + std::strlen(buffer), ret_val, std::chars_format::fixed); + if (!BOOST_TEST(from_r.ec == std::errc())) + { + // LCOV_EXCL_START + std::cerr << std::setprecision(std::numeric_limits::digits10) + << "Value: " << dec_val + << "\nBuffer: " << buffer + << "\nError: " << static_cast(from_r.ec) << std::endl; + + continue; + // LCOV_EXCL_STOP + } + + if (!BOOST_TEST_EQ(dec_val, ret_val)) + { + // LCOV_EXCL_START + std::cerr << std::setprecision(std::numeric_limits::digits10) + << " Value: " << dec_val + << "\n Buffer: " << buffer + << "\nRet val: " << ret_val << std::endl; + // LCOV_EXCL_STOP + } + } +} + +template +void test_hex_format_std() +{ + constexpr double max_value = 1e10; + std::uniform_real_distribution dist(-max_value, max_value); + + for (std::size_t i {}; i < N; ++i) + { + char buffer[256] {}; + + const auto val {dist(rng)}; + const T dec_val {val}; + + std::to_chars_result to_r = to_chars(buffer, buffer + sizeof(buffer), dec_val, std::chars_format::hex); + BOOST_TEST(to_r.ec == std::errc()); + + T ret_val; + std::from_chars_result from_r = from_chars(buffer, buffer + std::strlen(buffer), ret_val, std::chars_format::hex); + if (!BOOST_TEST(from_r.ec == std::errc())) + { + // LCOV_EXCL_START + std::cerr << std::setprecision(std::numeric_limits::digits10) + << "Value: " << dec_val + << "\nBuffer: " << buffer + << "\nError: " << static_cast(from_r.ec) << std::endl; + + continue; + // LCOV_EXCL_STOP + } + + if (!BOOST_TEST_EQ(dec_val, ret_val)) + { + // LCOV_EXCL_START + std::cerr << std::setprecision(std::numeric_limits::digits10) + << " Value: " << dec_val + << "\n Buffer: " << buffer + << "\nRet val: " << ret_val << std::endl; + // LCOV_EXCL_STOP + } + } +} + +template +void test_general_format_std() +{ + constexpr double max_value = 1e10; + std::uniform_real_distribution dist(-max_value, max_value); + + for (std::size_t i {}; i < N; ++i) + { + char buffer[256] {}; + + const auto val {dist(rng)}; + const T dec_val {val}; + + std::to_chars_result to_r = to_chars(buffer, buffer + sizeof(buffer), dec_val, std::chars_format::general); + BOOST_TEST(to_r.ec == std::errc()); + + T ret_val; + std::from_chars_result from_r = from_chars(buffer, buffer + std::strlen(buffer), ret_val, std::chars_format::general); + if (!BOOST_TEST(from_r.ec == std::errc())) + { + // LCOV_EXCL_START + std::cerr << std::setprecision(std::numeric_limits::digits10) + << "Value: " << dec_val + << "\nBuffer: " << buffer + << "\nError: " << static_cast(from_r.ec) << std::endl; + + continue; + // LCOV_EXCL_STOP + } + + if (!BOOST_TEST_EQ(dec_val, ret_val)) + { + // LCOV_EXCL_START + std::cerr << std::setprecision(std::numeric_limits::digits10) + << " Value: " << dec_val + << "\n Buffer: " << buffer + << "\nRet val: " << ret_val << std::endl; + // LCOV_EXCL_STOP + } + } +} + +#endif + template void test_value(T val, chars_format fmt, int precision, const char* result) { @@ -667,6 +839,20 @@ int main() test_error_value("e1000a00000000000000000000p06", chars_format::hex, precision); } + #ifdef BOOST_DECIMAL_HAS_STD_CHARCONV + test_scientific_format_std(); + test_scientific_format_std(); + + test_fixed_format_std(); + test_fixed_format_std(); + + test_hex_format_std(); + test_hex_format_std(); + + test_general_format_std(); + test_general_format_std(); + #endif + return boost::report_errors(); } From d6c5d0f47fa4bc2bb73aa46f23b71c376040f72f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 13:31:09 -0400 Subject: [PATCH 023/140] Document the additional std:: based overloads --- doc/decimal/charconv.adoc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/decimal/charconv.adoc b/doc/decimal/charconv.adoc index fdfeac74..10c846ce 100644 --- a/doc/decimal/charconv.adoc +++ b/doc/decimal/charconv.adoc @@ -93,7 +93,7 @@ constexpr boost::decimal::from_chars_result from_chars(const char* first, const template constexpr std::from_chars_result from_chars(const char* first, const char* last, DecimalType& value, std::chars_format fmt) noexcept -#endif +#endif // BOOST_DECIMAL_HAS_STD_CHARCONV } //namespace decimal } //namespace boost @@ -117,6 +117,16 @@ BOOST_DECIMAL_CONSTEXPR to_chars_result to_chars(char* first, char* last, Decima template BOOST_DECIMAL_CONSTEXPR to_chars_result to_chars(char* first, char* last, DecimalType value, chars_format fmt, int precision) noexcept; +#ifdef BOOST_DECIMAL_HAS_STD_CHARCONV + +template +BOOST_DECIMAL_CONSTEXPR std::to_chars_result to_chars(char* first, char* last, DecimalType value, std::chars_format fmt) noexcept; + +template +BOOST_DECIMAL_CONSTEXPR std::to_chars_result to_chars(char* first, char* last, DecimalType value, std::chars_format fmt, int precision) noexcept; + +#endif // BOOST_DECIMAL_HAS_STD_CHARCONV + } //namespace decimal } //namespace boost ---- @@ -128,6 +138,8 @@ NOTE: `BOOST_DECIMAL_CONSTEXPR` is defined if: - Compiler has: `__builtin_is_constant_evaluated()` - C++20 support with: `std::is_constant_evaluated()` +IMPORTANT: Same as `from_chars`, `boost::decimal::to_chars` will return a `std::to_chars_result` if `std::chars_format` is used to specify the format; otherwise it returns a `boost::decimal::to_chars_result`. + The library offers an additional feature for sizing buffers without specified precision and in general format [#charconv_limits] From 2820006caa88a1c7cffca2a7e5910611e30b025f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 14:45:49 -0400 Subject: [PATCH 024/140] Add fast type literals --- include/boost/decimal/literals.hpp | 122 ++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 4 deletions(-) diff --git a/include/boost/decimal/literals.hpp b/include/boost/decimal/literals.hpp index 15019854..73d55540 100644 --- a/include/boost/decimal/literals.hpp +++ b/include/boost/decimal/literals.hpp @@ -34,17 +34,17 @@ BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(const char* str) -> decimal return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DF(const char* str, std::size_t) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator "" _DF(const char* str, std::size_t len) -> decimal32 { decimal32 d; - from_chars(str, str + detail::strlen(str), d); + from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(const char* str, std::size_t) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(const char* str, std::size_t len) -> decimal32 { decimal32 d; - from_chars(str, str + detail::strlen(str), d); + from_chars(str, str + len, d); return d; } @@ -58,6 +58,44 @@ BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(unsigned long long v) -> de return decimal32{v}; } +BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(const char* str) -> decimal32_fast +{ + decimal32_fast d; + from_chars(str, str + detail::strlen(str), d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(const char* str) -> decimal32_fast +{ + decimal32_fast d; + from_chars(str, str + detail::strlen(str), d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(const char* str, std::size_t len) -> decimal32_fast +{ + decimal32_fast d; + from_chars(str, str + len, d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(const char* str, std::size_t len) -> decimal32_fast +{ + decimal32_fast d; + from_chars(str, str + len, d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(unsigned long long v) -> decimal32_fast +{ + return decimal32_fast{v}; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(unsigned long long v) -> decimal32_fast +{ + return decimal32_fast{v}; +} + BOOST_DECIMAL_EXPORT constexpr auto operator "" _DD(const char* str) -> decimal64 { decimal64 d; @@ -96,6 +134,44 @@ BOOST_DECIMAL_EXPORT constexpr auto operator "" _dd(unsigned long long v) -> de return decimal64{v}; } +BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(const char* str) -> decimal64_fast +{ + decimal64_fast d; + from_chars(str, str + detail::strlen(str), d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(const char* str) -> decimal64_fast +{ + decimal64_fast d; + from_chars(str, str + detail::strlen(str), d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(const char* str, std::size_t len) -> decimal64_fast +{ + decimal64_fast d; + from_chars(str, str + len, d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(const char* str, std::size_t len) -> decimal64_fast +{ + decimal64_fast d; + from_chars(str, str + len, d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(unsigned long long v) -> decimal64_fast +{ + return decimal64_fast{v}; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(unsigned long long v) -> decimal64_fast +{ + return decimal64_fast{v}; +} + BOOST_DECIMAL_EXPORT constexpr auto operator "" _DL(const char* str) -> decimal128 { decimal128 d; @@ -134,6 +210,44 @@ BOOST_DECIMAL_EXPORT constexpr auto operator "" _dl(unsigned long long v) -> de return decimal128{v}; } +BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(const char* str) -> decimal128_fast +{ + decimal128_fast d; + from_chars(str, str + detail::strlen(str), d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(const char* str) -> decimal128_fast +{ + decimal128_fast d; + from_chars(str, str + detail::strlen(str), d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(const char* str, std::size_t len) -> decimal128_fast +{ + decimal128_fast d; + from_chars(str, str + len, d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(const char* str, std::size_t len) -> decimal128_fast +{ + decimal128_fast d; + from_chars(str, str + len, d); + return d; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(unsigned long long v) -> decimal128_fast +{ + return decimal128_fast{v}; +} + +BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(unsigned long long v) -> decimal128_fast +{ + return decimal128_fast{v}; +} + } // namespace decimal } // namespace boost From 60eb9a4a21fab74bfdf01d6088fbe6aa508cdf54 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 14:45:57 -0400 Subject: [PATCH 025/140] Add testing of fast type literals --- test/test_literals.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/test/test_literals.cpp b/test/test_literals.cpp index de47f36b..e8edc200 100644 --- a/test/test_literals.cpp +++ b/test/test_literals.cpp @@ -26,6 +26,23 @@ void test_decimal32_literals() BOOST_TEST(isinf(5e300_df)); } +void test_decimal32_fast_literals() +{ + BOOST_TEST_EQ(decimal32_fast(0), 0_DFF); + BOOST_TEST_EQ(decimal32_fast(3), 3_DFF); + BOOST_TEST_EQ(decimal32_fast(3.1), 3.1_DFF); + BOOST_TEST_EQ(decimal32_fast(3, 1), 3e1_DFF); + BOOST_TEST(isinf(5e100_DFF)); + BOOST_TEST(isinf(5e300_DFF)); + + BOOST_TEST_EQ(decimal32_fast(0), 0_dff); + BOOST_TEST_EQ(decimal32_fast(3), 3_dff); + BOOST_TEST_EQ(decimal32_fast(3.1), 3.1_dff); + BOOST_TEST_EQ(decimal32_fast(3, 1), 3e1_dff); + BOOST_TEST(isinf(5e100_dff)); + BOOST_TEST(isinf(5e300_dff)); +} + void test_decimal64_literals() { BOOST_TEST_EQ(decimal64(0), 0_DD); @@ -47,6 +64,27 @@ void test_decimal64_literals() #endif } +void test_decimal64_fast_literals() +{ + BOOST_TEST_EQ(decimal64_fast(0), 0_DDF); + BOOST_TEST_EQ(decimal64_fast(3), 3_DDF); + BOOST_TEST_EQ(decimal64_fast(3.1), 3.1_DDF); + BOOST_TEST_EQ(decimal64_fast(3, 1), 3e1_DDF); + + BOOST_TEST_EQ(decimal64_fast(0), 0_ddf); + BOOST_TEST_EQ(decimal64_fast(3), 3_ddf); + BOOST_TEST_EQ(decimal64_fast(3.1), 3.1_ddf); + BOOST_TEST_EQ(decimal64_fast(3, 1), 3e1_ddf); + + // 64-bit long double warn of overflow + #if !(LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024) + BOOST_TEST(isinf(5e1000_ddf)); + BOOST_TEST(isinf(5e3000_ddf)); + BOOST_TEST(isinf(5e1000_DDF)); + BOOST_TEST(isinf(5e3000_DDF)); + #endif +} + void test_decimal128_literals() { BOOST_TEST_EQ(decimal128(0), 0_DL); @@ -60,11 +98,28 @@ void test_decimal128_literals() BOOST_TEST_EQ(decimal128(3, 1), 3e1_dl); } +void test_decimal128_fast_literals() +{ + BOOST_TEST_EQ(decimal128_fast(0), 0_DLF); + BOOST_TEST_EQ(decimal128_fast(3), 3_DLF); + BOOST_TEST_EQ(decimal128_fast(3.1), 3.1_DLF); + BOOST_TEST_EQ(decimal128_fast(3, 1), 3e1_DLF); + + BOOST_TEST_EQ(decimal128_fast(0), 0_dlf); + BOOST_TEST_EQ(decimal128_fast(3), 3_dlf); + BOOST_TEST_EQ(decimal128_fast(3.1), 3.1_dlf); + BOOST_TEST_EQ(decimal128_fast(3, 1), 3e1_dlf); +} + int main() { test_decimal32_literals(); test_decimal64_literals(); test_decimal128_literals(); + test_decimal32_fast_literals(); + test_decimal64_fast_literals(); + test_decimal128_fast_literals(); + return boost::report_errors(); } From b44ee5f00e7819787a09f57b88ddb4f268cf2d1a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 14:46:06 -0400 Subject: [PATCH 026/140] Add documentation of fast type literals --- doc/decimal/literals.adoc | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/doc/decimal/literals.adoc b/doc/decimal/literals.adoc index 5dd6fb45..35fba1c0 100644 --- a/doc/decimal/literals.adoc +++ b/doc/decimal/literals.adoc @@ -19,7 +19,7 @@ constexpr auto operator "" _DF(const char* str) -> decimal32 constexpr auto operator "" _df(const char* str) -> decimal32 constexpr auto operator "" _DF(unsigned long long v) -> decimal32 -constexpr auto operator "" _dF(unsigned long long v) -> decimal32 +constexpr auto operator "" _df(unsigned long long v) -> decimal32 constexpr auto operator "" _DD(const char* str) -> decimal64 constexpr auto operator "" _dd(const char* str) -> decimal64 @@ -33,6 +33,26 @@ constexpr auto operator "" _dl(const char* str) -> decimal128 constexpr auto operator "" _DL(unsigned long long v) -> decimal128 constexpr auto operator "" _dl(unsigned long long v) -> decimal128 +// ----- Fast Type Literals ----- + +constexpr auto operator "" _DFF(const char* str) -> decimal32_fast +constexpr auto operator "" _dff(const char* str) -> decimal32_fast + +constexpr auto operator "" _DFF(unsigned long long v) -> decimal32_fast +constexpr auto operator "" _dff(unsigned long long v) -> decimal32_fast + +constexpr auto operator "" _DDF(const char* str) -> decimal64_fast +constexpr auto operator "" _ddf(const char* str) -> decimal64_fast + +constexpr auto operator "" _DDF(unsigned long long v) -> decimal64_fast +constexpr auto operator "" _ddf(unsigned long long v) -> decimal64_fast + +constexpr auto operator "" _DLF(const char* str) -> decimal128_fast +constexpr auto operator "" _dlf(const char* str) -> decimal128_fast + +constexpr auto operator "" _DLF(unsigned long long v) -> decimal128_fast +constexpr auto operator "" _dlf(unsigned long long v) -> decimal128_fast + } //namespace decimal } //namespace boost ---- From 71ed9997a6bb16d71a65ee2aa556d1a497aeef87 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 15:43:23 -0400 Subject: [PATCH 027/140] Fix exp range of dec32_fast --- include/boost/decimal/decimal32_fast.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index b650ff2d..b9da5379 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -385,7 +385,7 @@ constexpr decimal32_fast::decimal32_fast(T1 coeff, T2 exp, bool sign) noexcept auto biased_exp {static_cast(exp + detail::bias)}; // Decimal32 exponent holds 8 bits - if (biased_exp > UINT32_C(0xFF)) + if (biased_exp > detail::max_biased_exp_v) { significand_ = detail::d32_fast_inf; } From db521579689fb5b6329e523e30e4895f490bfb0a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 4 Oct 2024 15:53:27 -0400 Subject: [PATCH 028/140] Change minimum compiler versions for interop --- doc/decimal/config.adoc | 2 +- include/boost/decimal/detail/config.hpp | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/decimal/config.adoc b/doc/decimal/config.adoc index f0d112c8..f578f489 100644 --- a/doc/decimal/config.adoc +++ b/doc/decimal/config.adoc @@ -45,4 +45,4 @@ This flag increases the performance of the basis operations (e.g. add, sub, mul, - `BOOST_DECIMAL_HAS_STD_CHARCONV`: This macro is defined if header `` exists and the language standard used is >= C++17 * We only need the structs and enums out of the header so we are not concerned with being overly restrictive about the feature test macros. - Implementations of integer `std::from_chars` and `std::to_chars` existed far before the floating points were completed to allow the feature test macro to be properly set. + ** Known compilers that support this lighter requirement are: GCC >= 10, Clang >= 13, and MSVC >= 14.2 diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 7cb539ac..21798fe9 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -314,10 +314,14 @@ typedef unsigned __int128 uint128_t; #if __cplusplus >= 201703L # if __has_include() -# ifndef BOOST_DECIMAL_BUILD_MODULE -# include + // We don't need all of charconv, just: std::to_chars_result, std::from_chars_result, and std::chars_format + // These compilers and versions give us what we need +# if (defined(__clang_major__) && __clang_major__ >= 13) || (defined(__GNUC__) && __GNUC__ >= 10) || defined(_MSC_VER) +# ifndef BOOST_DECIMAL_BUILD_MODULE +# include +# endif +# define BOOST_DECIMAL_HAS_STD_CHARCONV # endif -# define BOOST_DECIMAL_HAS_STD_CHARCONV # endif #endif From edc523f3357463d2e12ba96c5371a18dab54464c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 7 Oct 2024 09:27:36 -0400 Subject: [PATCH 029/140] Update jamfile for modularity --- modules/Jamfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/Jamfile b/modules/Jamfile index 4bef0549..30779928 100644 --- a/modules/Jamfile +++ b/modules/Jamfile @@ -4,11 +4,13 @@ # https://www.boost.org/LICENSE_1_0.txt # bring in the rules for testing -import testing ; +require-b2 5.0.1 ; +import-search /boost/config/checks ; +import config : requires ; import modules ; +import testing ; import path ; import pch ; -import ../../config/checks/config : requires ; project : requirements From 155c5a9c7ed8e988ebfebb9758ced33a85b04a48 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 7 Oct 2024 09:29:55 -0400 Subject: [PATCH 030/140] Add fast types to module file --- modules/decimal.cxx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/modules/decimal.cxx b/modules/decimal.cxx index d70203db..41977a9b 100644 --- a/modules/decimal.cxx +++ b/modules/decimal.cxx @@ -69,6 +69,10 @@ class decimal32; class decimal64; class decimal128; +class decimal32_fast; +class decimal64_fast; +class decimal128_fast; + } // namespace boost::decimal export namespace std { @@ -94,6 +98,27 @@ class numeric_limits; struct numeric_limits; #endif +template <> +#ifdef _MSC_VER +class numeric_limits; +#else +struct numeric_limits; +#endif + +template <> +#ifdef _MSC_VER +class numeric_limits; +#else +struct numeric_limits; +#endif + +template <> +#ifdef _MSC_VER +class numeric_limits; +#else +struct numeric_limits; +#endif + } // Namespace std // MSVC wants to be imported but also does not support importing it... From 6d8e3e5c6e096d2f3571e9cc30d3f107b10906b1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 7 Oct 2024 09:32:51 -0400 Subject: [PATCH 031/140] Export fast types --- include/boost/decimal/decimal128_fast.hpp | 7 ++++++- include/boost/decimal/decimal32_fast.hpp | 5 ++++- include/boost/decimal/decimal64_fast.hpp | 9 +++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index f4bd65d5..8dcfce5e 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -14,9 +14,14 @@ #include #include #include + +#ifndef BOOST_DECIMAL_BUILD_MODULE + #include #include +#endif + #ifndef BOOST_DECIMAL_DECIMAL128_FAST_HPP #define BOOST_DECIMAL_DECIMAL128_FAST_HPP @@ -45,7 +50,7 @@ struct decimal128_fast_components } // namespace detail -class decimal128_fast final +BOOST_DECIMAL_EXPORT class decimal128_fast final { public: using significand_type = detail::uint128; diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index b9da5379..2921d1fe 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -16,8 +16,11 @@ #include #include #include + +#ifndef BOOST_DECIMAL_BUILD_MODULE #include #include +#endif namespace boost { namespace decimal { @@ -40,7 +43,7 @@ struct decimal32_fast_components } -class decimal32_fast final +BOOST_DECIMAL_EXPORT class decimal32_fast final { public: using significand_type = std::uint_fast32_t; diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 5a30f1a6..346e6f7c 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -17,9 +17,14 @@ #include #include #include + +#ifndef BOOST_DECIMAL_BUILD_MODULE + #include #include +#endif + namespace boost { namespace decimal { @@ -41,7 +46,7 @@ struct decimal64_fast_components } // namespace detail -class decimal64_fast final +BOOST_DECIMAL_EXPORT class decimal64_fast final { public: using significand_type = std::uint_fast64_t; @@ -1390,7 +1395,7 @@ constexpr auto copysignd64f(decimal64_fast mag, decimal64_fast sgn) noexcept -> namespace std { -template <> +BOOST_DECIMAL_EXPORT template <> #ifdef _MSC_VER class numeric_limits #else From 041355aeb5d63e24feffda7a67b628f2d0719aaa Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 7 Oct 2024 09:34:12 -0400 Subject: [PATCH 032/140] Export BID conversions --- include/boost/decimal/bid_conversion.hpp | 54 ++++++++++++------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/include/boost/decimal/bid_conversion.hpp b/include/boost/decimal/bid_conversion.hpp index 683c8768..1c4a8f87 100644 --- a/include/boost/decimal/bid_conversion.hpp +++ b/include/boost/decimal/bid_conversion.hpp @@ -20,76 +20,76 @@ namespace decimal { # pragma GCC diagnostic ignored "-Wconversion" #endif -constexpr auto to_bid_d32(decimal32 val) noexcept -> std::uint32_t +BOOST_DECIMAL_EXPORT constexpr auto to_bid_d32(decimal32 val) noexcept -> std::uint32_t { return val.bits_; } -constexpr auto from_bid_d32(std::uint32_t bits) noexcept -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto from_bid_d32(std::uint32_t bits) noexcept -> decimal32 { return from_bits(bits); } -constexpr auto to_bid_d32f(decimal32_fast val) noexcept -> std::uint32_t +BOOST_DECIMAL_EXPORT constexpr auto to_bid_d32f(decimal32_fast val) noexcept -> std::uint32_t { const decimal32 compliant_val {val}; return to_bid_d32(compliant_val); } -constexpr auto from_bid_d32f(std::uint32_t bits) noexcept -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto from_bid_d32f(std::uint32_t bits) noexcept -> decimal32_fast { const auto compliant_val {from_bid_d32(bits)}; const decimal32_fast val {compliant_val}; return val; } -constexpr auto to_bid_d64(decimal64 val) noexcept -> std::uint64_t +BOOST_DECIMAL_EXPORT constexpr auto to_bid_d64(decimal64 val) noexcept -> std::uint64_t { return val.bits_; } -constexpr auto from_bid_d64(std::uint64_t bits) noexcept -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto from_bid_d64(std::uint64_t bits) noexcept -> decimal64 { return from_bits(bits); } -constexpr auto to_bid_d64f(decimal64_fast val) noexcept -> std::uint64_t +BOOST_DECIMAL_EXPORT constexpr auto to_bid_d64f(decimal64_fast val) noexcept -> std::uint64_t { const decimal64 compliant_val {val}; return to_bid_d64(compliant_val); } -constexpr auto from_bid_d64f(std::uint64_t bits) noexcept -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto from_bid_d64f(std::uint64_t bits) noexcept -> decimal64_fast { const auto compliant_val {from_bid_d64(bits)}; const decimal64_fast val {compliant_val}; return val; } -constexpr auto to_bid_d128(decimal128 val) noexcept -> detail::uint128 +BOOST_DECIMAL_EXPORT constexpr auto to_bid_d128(decimal128 val) noexcept -> detail::uint128 { return val.bits_; } -constexpr auto from_bid_d128(detail::uint128 bits) noexcept -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto from_bid_d128(detail::uint128 bits) noexcept -> decimal128 { return from_bits(bits); } #ifdef BOOST_DECIMAL_HAS_INT128 -constexpr auto from_bid_d128(detail::uint128_t bits) noexcept -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto from_bid_d128(detail::uint128_t bits) noexcept -> decimal128 { return from_bits(bits); } #endif -constexpr auto to_bid_d128f(decimal128_fast val) noexcept -> detail::uint128 +BOOST_DECIMAL_EXPORT constexpr auto to_bid_d128f(decimal128_fast val) noexcept -> detail::uint128 { const decimal128 compliant_val {val}; return to_bid_d128(compliant_val); } -constexpr auto from_bid_d128f(detail::uint128 bits) noexcept -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto from_bid_d128f(detail::uint128 bits) noexcept -> decimal128_fast { const auto compliant_val {from_bid_d128(bits)}; const decimal128_fast val {compliant_val}; @@ -97,7 +97,7 @@ constexpr auto from_bid_d128f(detail::uint128 bits) noexcept -> decimal128_fast } #ifdef BOOST_DECIMAL_HAS_INT128 -constexpr auto from_bid_d128f(detail::uint128_t bits) noexcept -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto from_bid_d128f(detail::uint128_t bits) noexcept -> decimal128_fast { const auto compliant_val {from_bid_d128(bits)}; const decimal128_fast val {compliant_val}; @@ -105,76 +105,76 @@ constexpr auto from_bid_d128f(detail::uint128_t bits) noexcept -> decimal128_fas } #endif -constexpr auto to_bid(decimal32 val) noexcept -> std::uint32_t +BOOST_DECIMAL_EXPORT constexpr auto to_bid(decimal32 val) noexcept -> std::uint32_t { return to_bid_d32(val); } -constexpr auto to_bid(decimal32_fast val) noexcept -> std::uint32_t +BOOST_DECIMAL_EXPORT constexpr auto to_bid(decimal32_fast val) noexcept -> std::uint32_t { return to_bid_d32f(val); } -constexpr auto to_bid(decimal64 val) noexcept -> std::uint64_t +BOOST_DECIMAL_EXPORT constexpr auto to_bid(decimal64 val) noexcept -> std::uint64_t { return to_bid_d64(val); } -constexpr auto to_bid(decimal64_fast val) noexcept -> std::uint64_t +BOOST_DECIMAL_EXPORT constexpr auto to_bid(decimal64_fast val) noexcept -> std::uint64_t { return to_bid_d64f(val); } -constexpr auto to_bid(decimal128 val) noexcept -> detail::uint128 +BOOST_DECIMAL_EXPORT constexpr auto to_bid(decimal128 val) noexcept -> detail::uint128 { return to_bid_d128(val); } -constexpr auto to_bid(decimal128_fast val) noexcept -> detail::uint128 +BOOST_DECIMAL_EXPORT constexpr auto to_bid(decimal128_fast val) noexcept -> detail::uint128 { return to_bid_d128f(val); } -template +BOOST_DECIMAL_EXPORT template constexpr auto to_bid(T val) noexcept { return to_bid(val); } -template +BOOST_DECIMAL_EXPORT template constexpr auto from_bid(std::uint32_t bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { return from_bid_d32f(bits); } -template <> +BOOST_DECIMAL_EXPORT template <> constexpr auto from_bid(std::uint32_t bits) noexcept -> decimal32 { return from_bid_d32(bits); } -template +BOOST_DECIMAL_EXPORT template constexpr auto from_bid(std::uint64_t bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { return from_bid_d64f(bits); } -template <> +BOOST_DECIMAL_EXPORT template <> constexpr auto from_bid(std::uint64_t bits) noexcept -> decimal64 { return from_bid_d64(bits); } -template +BOOST_DECIMAL_EXPORT template constexpr auto from_bid(detail::uint128 bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { return from_bid_d128f(bits); } -template <> +BOOST_DECIMAL_EXPORT template <> constexpr auto from_bid(detail::uint128 bits) noexcept -> decimal128 { return from_bid_d128(bits); From f1a688cdf26e193648572bbf31f51fb486f06609 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 7 Oct 2024 09:35:22 -0400 Subject: [PATCH 033/140] Export DPD conversions --- include/boost/decimal/dpd_conversion.hpp | 34 ++++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 7ce886f0..4db4d5c1 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -312,7 +312,7 @@ constexpr auto decode_dpd(std::uint32_t dpd_bits, std::uint8_t& d3, std::uint8_t } // namespace detail -template +BOOST_DECIMAL_EXPORT template constexpr auto to_dpd_d32(DecimalType val) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint32_t) { @@ -422,7 +422,7 @@ constexpr auto to_dpd_d32(DecimalType val) noexcept return dpd; } -template +BOOST_DECIMAL_EXPORT template constexpr auto from_dpd_d32(std::uint32_t dpd) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { @@ -507,7 +507,7 @@ constexpr auto from_dpd_d32(std::uint32_t dpd) noexcept return DecimalType{significand, exp, sign}; } -template +BOOST_DECIMAL_EXPORT template constexpr auto to_dpd_d64(DecimalType val) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint64_t) { @@ -618,7 +618,7 @@ constexpr auto to_dpd_d64(DecimalType val) noexcept return dpd; } -template +BOOST_DECIMAL_EXPORT template constexpr auto from_dpd_d64(std::uint64_t dpd) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { @@ -703,7 +703,7 @@ constexpr auto from_dpd_d64(std::uint64_t dpd) noexcept return DecimalType{significand, exp, sign}; } -template +BOOST_DECIMAL_EXPORT template constexpr auto to_dpd_d128(DecimalType val) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, detail::uint128) { @@ -814,7 +814,7 @@ constexpr auto to_dpd_d128(DecimalType val) noexcept return dpd; } -template +BOOST_DECIMAL_EXPORT template constexpr auto from_dpd_d128(detail::uint128 dpd) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { @@ -898,58 +898,58 @@ constexpr auto from_dpd_d128(detail::uint128 dpd) noexcept return DecimalType{significand, exp, sign}; } -constexpr auto to_dpd(decimal32 val) noexcept -> std::uint32_t +BOOST_DECIMAL_EXPORT constexpr auto to_dpd(decimal32 val) noexcept -> std::uint32_t { return to_dpd_d32(val); } -constexpr auto to_dpd(decimal32_fast val) noexcept -> std::uint32_t +BOOST_DECIMAL_EXPORT constexpr auto to_dpd(decimal32_fast val) noexcept -> std::uint32_t { return to_dpd_d32(val); } -constexpr auto to_dpd(decimal64 val) noexcept -> std::uint64_t +BOOST_DECIMAL_EXPORT constexpr auto to_dpd(decimal64 val) noexcept -> std::uint64_t { return to_dpd_d64(val); } -constexpr auto to_dpd(decimal64_fast val) noexcept -> std::uint64_t +BOOST_DECIMAL_EXPORT constexpr auto to_dpd(decimal64_fast val) noexcept -> std::uint64_t { return to_dpd_d64(val); } -constexpr auto to_dpd(decimal128 val) noexcept -> detail::uint128 +BOOST_DECIMAL_EXPORT constexpr auto to_dpd(decimal128 val) noexcept -> detail::uint128 { return to_dpd_d128(val); } -constexpr auto to_dpd(decimal128_fast val) noexcept -> detail::uint128 +BOOST_DECIMAL_EXPORT constexpr auto to_dpd(decimal128_fast val) noexcept -> detail::uint128 { return to_dpd_d128(val); } -template +BOOST_DECIMAL_EXPORT template constexpr auto to_dpd(DecimalType val) noexcept { static_assert(detail::is_decimal_floating_point_v, "Must be a decimal floating point type."); return to_dpd(val); } -template +BOOST_DECIMAL_EXPORT template constexpr auto from_dpd(std::uint32_t bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { return from_dpd_d32(bits); } -template +BOOST_DECIMAL_EXPORT template constexpr auto from_dpd(std::uint64_t bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { return from_dpd_d64(bits); } -template +BOOST_DECIMAL_EXPORT template constexpr auto from_dpd(detail::uint128 bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { @@ -958,7 +958,7 @@ constexpr auto from_dpd(detail::uint128 bits) noexcept #ifdef BOOST_DECIMAL_HAS_INT128 -template +BOOST_DECIMAL_EXPORT template constexpr auto from_dpd(detail::uint128_t bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { From 39cdd7b21b070bb29c83fb28fe6334b497e1458a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 7 Oct 2024 09:56:42 -0400 Subject: [PATCH 034/140] Add gcm cache folder to git ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 253ed7bd..8f58ef91 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ test/metal/bin/ # Modules *.gcm +gcm.cache/ # Mac option *.DS_Store From 61fa4811877233b4b459e01585208fbf84656b8a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 7 Oct 2024 09:56:55 -0400 Subject: [PATCH 035/140] Fix table linkage --- include/boost/decimal/detail/power_tables.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/power_tables.hpp b/include/boost/decimal/detail/power_tables.hpp index 24cae2b2..9268a2b9 100644 --- a/include/boost/decimal/detail/power_tables.hpp +++ b/include/boost/decimal/detail/power_tables.hpp @@ -77,7 +77,7 @@ static_assert(sizeof(emulated_128_pow10) == sizeof(uint128) * 40, "Should have 1 #ifdef BOOST_DECIMAL_HAS_INT128 -static constexpr uint128_t builtin_128_pow10[] = { +BOOST_DECIMAL_CONSTEXPR_VARIABLE uint128_t builtin_128_pow10[] = { uint128_t(1), uint128_t(10), uint128_t(100), @@ -124,7 +124,7 @@ static_assert(sizeof(builtin_128_pow10) == sizeof(boost::decimal::detail::uint12 #endif -static constexpr uint256_t emulated_256_pow10[] = { +BOOST_DECIMAL_CONSTEXPR_VARIABLE uint256_t emulated_256_pow10[] = { uint256_t{uint128{UINT64_C(0), UINT64_C(0)}, uint128{UINT64_C(0), UINT64_C(1)}}, uint256_t{uint128{UINT64_C(0), UINT64_C(0)}, uint128{UINT64_C(0), UINT64_C(10)}}, uint256_t{uint128{UINT64_C(0), UINT64_C(0)}, uint128{UINT64_C(0), UINT64_C(100)}}, From 62b5d3a92fbf3979264677211fd8109714bc39d6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 7 Oct 2024 09:58:56 -0400 Subject: [PATCH 036/140] Fix library metadata --- meta/libraries.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/meta/libraries.json b/meta/libraries.json index 1fed674a..9009763e 100644 --- a/meta/libraries.json +++ b/meta/libraries.json @@ -2,10 +2,12 @@ "key": "decimal", "name": "Decimal", "authors": [ - "Matt Borland" + "Matt Borland", + "Christopher Kormanyos" ], "maintainers": [ - "Matt Borland " + "Matt Borland ", + "Christopher Kormanyos " ], "description": "An implementation of IEEE754 Decimal Floating Point Numbers.", "category": [ From 450d564aca011f3105ffcbfe1ca9261c23e5d846 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 7 Oct 2024 11:00:42 -0400 Subject: [PATCH 037/140] Replace macos-12 with 15 --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca1434ee..1b81fa97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -239,15 +239,15 @@ jobs: - libc++-14-dev - libc++abi-14-dev - - toolset: clang - cxxstd: "03,11,14,17,20,2b" - os: macos-12 - toolset: clang cxxstd: "03,11,14,17,20,2b" os: macos-13 - toolset: clang cxxstd: "03,11,14,17,20,2b" os: macos-14 + - toolset: clang + cxxstd: "03,11,14,17,20,2b" + os: macos-15 timeout-minutes: 180 runs-on: ${{matrix.os}} @@ -526,9 +526,9 @@ jobs: include: - os: ubuntu-20.04 - os: ubuntu-22.04 - - os: macos-12 - os: macos-13 - os: macos-14 + - os: macos-15 runs-on: ${{matrix.os}} @@ -575,9 +575,9 @@ jobs: include: - os: ubuntu-20.04 - os: ubuntu-22.04 - - os: macos-12 - os: macos-13 - os: macos-14 + - os: macos-15 runs-on: ${{matrix.os}} @@ -634,9 +634,9 @@ jobs: include: - os: ubuntu-20.04 - os: ubuntu-22.04 - - os: macos-12 - os: macos-13 - os: macos-14 + - os: macos-15 runs-on: ${{matrix.os}} From df650edeaf75b7c16426a6a3ee97d0c64738a80d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 7 Oct 2024 11:18:55 -0400 Subject: [PATCH 038/140] Refactor computation of 80 and 128 bit ldbls --- .../boost/decimal/detail/fast_float/compute_float80_128.hpp | 4 ++-- include/boost/decimal/detail/to_float.hpp | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/boost/decimal/detail/fast_float/compute_float80_128.hpp b/include/boost/decimal/detail/fast_float/compute_float80_128.hpp index 8fd6e883..af60dfe0 100644 --- a/include/boost/decimal/detail/fast_float/compute_float80_128.hpp +++ b/include/boost/decimal/detail/fast_float/compute_float80_128.hpp @@ -69,8 +69,8 @@ constexpr auto fast_path(const std::int64_t q, const Unsigned_Integer &w, bool n #endif template -constexpr auto compute_float80(std::int64_t q, const Unsigned_Integer &w, - const bool negative, bool &success) noexcept -> long double +constexpr auto compute_float80_128(std::int64_t q, const Unsigned_Integer &w, + const bool negative, bool &success) noexcept -> long double { // GLIBC uses 2^-16444 but MPFR uses 2^-16445 as the smallest subnormal value for 80 bit // 39 is the max number of digits in an uint128_t diff --git a/include/boost/decimal/detail/to_float.hpp b/include/boost/decimal/detail/to_float.hpp index a93e15b8..93f7d975 100644 --- a/include/boost/decimal/detail/to_float.hpp +++ b/include/boost/decimal/detail/to_float.hpp @@ -72,10 +72,9 @@ BOOST_DECIMAL_CXX20_CONSTEXPR auto to_float(Decimal val) noexcept #if BOOST_DECIMAL_LDBL_BITS == 64 result = static_cast(detail::fast_float::compute_float64(exp, new_sig, val.isneg(), success)); #else - result = static_cast(detail::fast_float::compute_float80(exp, new_sig, val.isneg(), success)); + result = static_cast(detail::fast_float::compute_float80_128(exp, new_sig, val.isneg(), success)); #endif } - // TODO(mborland): Add conversion for __float128 and 128 bit long doubles if (BOOST_DECIMAL_UNLIKELY(!success)) { From 833b6e3ce081e20d9834901c789a0fa28e05e4e6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 7 Oct 2024 11:19:10 -0400 Subject: [PATCH 039/140] Enable conversions to 80 and 128 bit long doubles --- include/boost/decimal/decimal64.hpp | 3 +-- include/boost/decimal/decimal64_fast.hpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 59e5e64d..52a8af3b 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -970,8 +970,7 @@ BOOST_DECIMAL_CXX20_CONSTEXPR decimal64::operator double() const noexcept BOOST_DECIMAL_CXX20_CONSTEXPR decimal64::operator long double() const noexcept { - // TODO(mborland): Don't have an exact way of converting to various long doubles - return static_cast(to_float(*this)); + return to_float(*this); } #ifdef BOOST_DECIMAL_HAS_FLOAT16 diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 5a30f1a6..4011dec9 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -885,8 +885,7 @@ BOOST_DECIMAL_CXX20_CONSTEXPR decimal64_fast::operator double() const noexcept BOOST_DECIMAL_CXX20_CONSTEXPR decimal64_fast::operator long double() const noexcept { - // TODO(mborland): Don't have an exact way of converting to various long doubles - return static_cast(to_float(*this)); + return to_float(*this); } #ifdef BOOST_DECIMAL_HAS_FLOAT16 From 43c2d5de4b92927b1fd90566bec9fbfca4eb184e Mon Sep 17 00:00:00 2001 From: ckormanyos Date: Sun, 15 Dec 2024 11:22:27 +0100 Subject: [PATCH 040/140] Update GDB run in metal CI --- .github/workflows/metal.yml | 44 ++++-- test/metal/app_benchmark_non_std_decimal.cpp | 2 +- .../build/test_app_benchmarks_emulator.gdb | 28 ++++ .../build/test_app_benchmarks_emulator.py | 131 ------------------ 4 files changed, 59 insertions(+), 146 deletions(-) create mode 100644 test/metal/target/build/test_app_benchmarks_emulator.gdb delete mode 100644 test/metal/target/build/test_app_benchmarks_emulator.py diff --git a/.github/workflows/metal.yml b/.github/workflows/metal.yml index b0c42613..dcbf8983 100644 --- a/.github/workflows/metal.yml +++ b/.github/workflows/metal.yml @@ -1,6 +1,6 @@ # ------------------------------------------------------------------------------ -# Copyright Matt Borland 2023. -# Copyright Christopher Kormanyos 2023. +# Copyright Matt Borland 2023 - 2024. +# Copyright Christopher Kormanyos 2023 - 2024. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -27,28 +27,44 @@ jobs: fetch-depth: '0' - name: update-tools run: | - sudo apt install libncurses5 libpython2.7 + sudo apt update + wget http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.3-2ubuntu0.1_amd64.deb + sudo apt install ./libtinfo5_6.3-2ubuntu0.1_amd64.deb + wget http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libncursesw5_6.3-2ubuntu0.1_amd64.deb + sudo apt install ./libncursesw5_6.3-2ubuntu0.1_amd64.deb mkdir -p emu_env && cd emu_env - wget --no-check-certificate https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/10.3-2021.10/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 - tar -xf gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 - wget --no-check-certificate https://github.com/xpack-dev-tools/qemu-arm-xpack/releases/download/v7.1.0-1/xpack-qemu-arm-7.1.0-1-linux-x64.tar.gz - tar -xzf xpack-qemu-arm-7.1.0-1-linux-x64.tar.gz + wget --no-check-certificate https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz + tar -xf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz + wget --no-check-certificate https://github.com/xpack-dev-tools/qemu-arm-xpack/releases/download/v8.2.6-1/xpack-qemu-arm-8.2.6-1-linux-x64.tar.gz + tar -xzf xpack-qemu-arm-8.2.6-1-linux-x64.tar.gz working-directory: ./test/metal/ - name: build benchmark_single-stm32f429 run: | + PATH="${{ runner.workspace }}/decimal/test/metal/emu_env/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin:$PATH" + echo 'Query arm-none-eabi-g++ version' + echo + arm-none-eabi-g++ -v + echo mkdir -p bin - emu_env/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-g++ -std=c++17 -Wall -Wextra -Wpedantic -Os -g -gdwarf-2 -ffunction-sections -fdata-sections -x c++ -fno-rtti -fno-use-cxa-atexit -fno-exceptions -fno-nonansi-builtins -fno-threadsafe-statics -fno-enforce-eh-specs -fno-inline-functions -mcpu=cortex-m4 -mtune=cortex-m4 -mthumb -mfloat-abi=soft -mno-unaligned-access -mno-long-calls -I../../include -DBOOST_DECIMAL_DISABLE_CLIB -DAPP_BENCHMARK_STANDALONE_MAIN app_benchmark_non_std_decimal.cpp ./target/micros/stm32f429/make/single/crt.cpp ./target/micros/stm32f429/make/single/mcal_gcc_cxx_completion_with_stdlib.cpp -nostartfiles -Wl,--gc-sections -Wl,-Map,./bin/app_benchmark_non_std_decimal.map -T ./target/micros/stm32f429/make/stm32f429.ld --specs=nano.specs --specs=nosys.specs -Wl,--print-memory-usage -o ./bin/app_benchmark_non_std_decimal.elf - emu_env/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-objcopy ./bin/app_benchmark_non_std_decimal.elf -O ihex ./bin/app_benchmark_non_std_decimal.hex + arm-none-eabi-g++ -std=c++20 -Wall -Wextra -Wpedantic -Os -g -gdwarf-2 -ffunction-sections -fdata-sections -x c++ -fno-rtti -fno-use-cxa-atexit -fno-exceptions -fno-nonansi-builtins -fno-threadsafe-statics -fno-enforce-eh-specs -fno-inline-functions -mcpu=cortex-m4 -mtune=cortex-m4 -mthumb -mfloat-abi=soft -mno-unaligned-access -mno-long-calls -I../../include -DBOOST_DECIMAL_DISABLE_CLIB -DAPP_BENCHMARK_STANDALONE_MAIN app_benchmark_non_std_decimal.cpp ./target/micros/stm32f429/make/single/crt.cpp ./target/micros/stm32f429/make/single/mcal_gcc_cxx_completion_with_stdlib.cpp -nostartfiles -Wl,--gc-sections -Wl,-Map,./bin/app_benchmark_non_std_decimal.map -T ./target/micros/stm32f429/make/stm32f429.ld --specs=nano.specs --specs=nosys.specs -Wl,--print-memory-usage -o ./bin/app_benchmark_non_std_decimal.elf + arm-none-eabi-objcopy ./bin/app_benchmark_non_std_decimal.elf -O ihex ./bin/app_benchmark_non_std_decimal.hex ls -la ./bin/app_benchmark_non_std_decimal.elf ./bin/app_benchmark_non_std_decimal.hex ./bin/app_benchmark_non_std_decimal.map working-directory: ./test/metal/ - name: emulate-target stm32f429 run: | - ./emu_env/xpack-qemu-arm-7.1.0-1/bin/qemu-system-gnuarmeclipse --verbose --mcu STM32F429ZI --nographic --gdb tcp::9999 -d unimp,guest_errors & + PATH="${{ runner.workspace }}/decimal/test/metal/emu_env/xpack-qemu-arm-8.2.6-1/bin:$PATH" + qemu-system-gnuarmeclipse --verbose --mcu STM32F429ZI --nographic --gdb tcp::9999 -d unimp,guest_errors & + sleep 2 working-directory: ./test/metal/ - name: run-test-on-target run: | - ./emu_env/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gdb-py ./bin/app_benchmark_non_std_decimal.elf -x ./target/build/test_app_benchmarks_emulator.py - qemu_result=$? - echo "qemu_result" "$qemu_result" - echo "qemu_result" "$qemu_result" | grep 'qemu_result 0' + sleep 2 + PATH="${{ runner.workspace }}/decimal/test/metal/emu_env/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin:$PATH" + echo 'Run test on target' + echo + arm-none-eabi-gdb ./bin/app_benchmark_non_std_decimal.elf -x ./target/build/test_app_benchmarks_emulator.gdb > ./app_benchmark_non_std_decimal.txt + cat ./app_benchmark_non_std_decimal.txt + echo + echo 'We will now grep for the right answer...' + grep 'value 0xF00DCAFE' ./app_benchmark_non_std_decimal.txt working-directory: ./test/metal/ diff --git a/test/metal/app_benchmark_non_std_decimal.cpp b/test/metal/app_benchmark_non_std_decimal.cpp index 4a6599c7..b818d959 100644 --- a/test/metal/app_benchmark_non_std_decimal.cpp +++ b/test/metal/app_benchmark_non_std_decimal.cpp @@ -12,7 +12,7 @@ // cd /mnt/c/MyGitRepos/cppalliance/decimal/test/metal // mkdir -p bin -// arm-none-eabi-g++ -std=c++17 -Wall -Wextra -Wpedantic -O0 -g -gdwarf-2 -ffunction-sections -fdata-sections -x c++ -fno-rtti -fno-use-cxa-atexit -fno-exceptions -fno-nonansi-builtins -fno-threadsafe-statics -fno-enforce-eh-specs -ftemplate-depth=128 -mcpu=cortex-m4 -mtune=cortex-m4 -mthumb -mfloat-abi=soft -mno-unaligned-access -mno-long-calls -I../../include -DBOOST_DECIMAL_DISABLE_CLIB -DAPP_BENCHMARK_STANDALONE_MAIN app_benchmark_non_std_decimal.cpp ./target/micros/stm32f429/make/single/crt.cpp ./target/micros/stm32f429/make/single/mcal_gcc_cxx_completion_with_stdlib.cpp -nostartfiles -Wl,--gc-sections -Wl,-Map,./bin/app_benchmark_non_std_decimal.map -T ./target/micros/stm32f429/make/stm32f429.ld --specs=nano.specs --specs=nosys.specs -Wl,--print-memory-usage -o ./bin/app_benchmark_non_std_decimal.elf +// arm-none-eabi-g++ -std=c++20 -Wall -Wextra -Wpedantic -O0 -g -gdwarf-2 -ffunction-sections -fdata-sections -x c++ -fno-rtti -fno-use-cxa-atexit -fno-exceptions -fno-nonansi-builtins -fno-threadsafe-statics -fno-enforce-eh-specs -ftemplate-depth=128 -mcpu=cortex-m4 -mtune=cortex-m4 -mthumb -mfloat-abi=soft -mno-unaligned-access -mno-long-calls -I../../include -DBOOST_DECIMAL_DISABLE_CLIB -DAPP_BENCHMARK_STANDALONE_MAIN app_benchmark_non_std_decimal.cpp ./target/micros/stm32f429/make/single/crt.cpp ./target/micros/stm32f429/make/single/mcal_gcc_cxx_completion_with_stdlib.cpp -nostartfiles -Wl,--gc-sections -Wl,-Map,./bin/app_benchmark_non_std_decimal.map -T ./target/micros/stm32f429/make/stm32f429.ld --specs=nano.specs --specs=nosys.specs -Wl,--print-memory-usage -o ./bin/app_benchmark_non_std_decimal.elf // arm-none-eabi-objcopy ./bin/app_benchmark_non_std_decimal.elf -O ihex ./bin/app_benchmark_non_std_decimal.hex // ls -la ./bin/app_benchmark_non_std_decimal.elf ./bin/app_benchmark_non_std_decimal.hex ./bin/app_benchmark_non_std_decimal.map diff --git a/test/metal/target/build/test_app_benchmarks_emulator.gdb b/test/metal/target/build/test_app_benchmarks_emulator.gdb new file mode 100644 index 00000000..c85858ba --- /dev/null +++ b/test/metal/target/build/test_app_benchmarks_emulator.gdb @@ -0,0 +1,28 @@ +# /////////////////////////////////////////////////////////////////// +# // Copyright Christopher Kormanyos 2020 - 2024. +# // Distributed under the Boost Software License, +# // Version 1.0. (See accompanying file LICENSE_1_0.txt +# // or copy at http://www.boost.org/LICENSE_1_0.txt) +# // + +# Connect to the target (e.g., OpenOCD or another GDB server). +target remote localhost:9999 +monitor halt + +# Ensure that the program is loaded. +load + +# Set a breakpoint at the specified subroutine. +break app_benchmark_get_standalone_result + +# Start or continue program execution. +continue + +# Format and print the value of a variable. +printf "value 0x%X\n\n", app_benchmark_standalone_result + +# Delete (all) breakpoint(s). +delete + +# Perform a non-elegant quit of the GDB session. +quit diff --git a/test/metal/target/build/test_app_benchmarks_emulator.py b/test/metal/target/build/test_app_benchmarks_emulator.py deleted file mode 100644 index 44bf8af5..00000000 --- a/test/metal/target/build/test_app_benchmarks_emulator.py +++ /dev/null @@ -1,131 +0,0 @@ -#------------------------------------------------------------------------------- -# Name: test_app_benchmarks_emulator.py -# Purpose: -# -# Author: Christopher Kormanyos -# -# Created: 02/04/2021 -# -# Copyright: Copyright Christopher Kormanyos 2020 - 2023 -# -# Licence: Distributed under the Boost Software License, -# Version 1.0. (See accompanying file LICENSE_1_0.txt -# or copy at http://www.boost.org/LICENSE_1_0.txt) -#------------------------------------------------------------------------------- - -#!/usr/bin/env python2 - -# import python packages -import gdb -import time -import logging -import sys - -#------------------------------------------------------------------------------- -# --- class: qemu_emulator -#------------------------------------------------------------------------------- -class qemu_emulator: - def __init__(self, tcp_port, iterations): - self.tcp_port = tcp_port - self.iterations = iterations - - # qemu initialization - def initialize(self): - self.connect_to_server(self.tcp_port) - self.create_log_file() - self.load_elf() - - # Excute gdb commands - def execute(self, command, from_tty = False, to_string = False): - gdb.execute('{}'.format(command), from_tty, to_string) - - # Create log file - def create_log_file(self): - logging.basicConfig(filename='emu-target.log',level=logging.DEBUG, filemode='w') - logging.info('------- Running GDB Test -----') - - # Connect to server - def connect_to_server(self, tcp_port): - self.execute('target remote localhost:{}'.format(tcp_port)) - self.execute('monitor reset') - self.execute('set confirm off') - - # Load object data base - def load_elf(self): - self.execute('load') - - # Run the benchmark - def run(self): - self.execute('continue') - - def next(self): - self.execute('next') - - # Set gdb Bp - def set_gdb_break_point(self): - my_bp = gdb.Breakpoint('app_benchmark_get_standalone_result') - return my_bp - - # Delete gdb Bp - def delete_gdb_break_point(self, bp): - bp.delete() - - # Get gdb result - def get_gdb_result(self): - my_result = gdb.parse_and_eval("app_benchmark_standalone_result") - return my_result - - # Convert from gdb type to hex - def convert_to_hex(self, gdb_value): - val_as_str = str(gdb_value) - val_as_hex = hex(int(val_as_str)) - return val_as_hex - - # Check the gdb return value - def check_gdb_result(self, result_as_hex): - if result_as_hex == "0xf00dcafe": - return True - else: - return False - -#------------------------------------------------------------------------------- -# --- GDB Script starts here -# See also https://embeddedartistry.com/blog/2020/11/09/metal-gdb-controlling-gdb-through-python-scripts-with-the-gdb-python-api/ -#------------------------------------------------------------------------------- - -# Script Config -tcp_port = 9999 -iterations = 64 - -# Create a qemu object -obj = qemu_emulator(tcp_port, iterations) - -# Initialize -obj.initialize() - -# Set break point -bp1 = obj.set_gdb_break_point() - -# Run the benchmark -obj.run() - -# Get gdb result -my_value = obj.get_gdb_result() -time.sleep(0.5) - -# Delete break point -obj.delete_gdb_break_point(bp1) - -# Convert gdb result to hex -value_as_hex = obj.convert_to_hex(my_value) - -# Print the return value -print("Result value as hex: " + value_as_hex) - -# Check the gdb result and quit -result_is_ok = obj.check_gdb_result(value_as_hex) - -if result_is_ok == True: - sys.exit(0) -else: - sys.exit(-1) From 8d83b733589b2ff96b55b2fb6221f4a9146bd161 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 16 Dec 2024 14:28:04 -0500 Subject: [PATCH 041/140] Use hosted node container --- .github/workflows/ci.yml | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b81fa97..a079dac6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -251,7 +251,11 @@ jobs: timeout-minutes: 180 runs-on: ${{matrix.os}} - container: ${{matrix.container}} + container: + image: ${{matrix.container}} + volumes: + - /node20217:/node20217:rw,rshared + - ${{ startsWith(matrix.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }} steps: - name: Setup environment @@ -275,9 +279,13 @@ jobs: fi apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common tzdata wget curl apt-transport-https ca-certificates make build-essential g++ $PYTHON_PACKAGE python3 perl git cmake fi + if [[ "${{matrix.container}}" == "ubuntu:1"* ]]; then + # Node 20 doesn't work with Ubuntu 16/18 glibc: https://github.com/actions/checkout/issues/1590 + curl -sL https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz | tar -xJ --strip-components 1 -C /node20217 + fi fi git config --global pack.threads 0 - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages if: matrix.install @@ -489,7 +497,7 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Boost shell: cmd @@ -533,11 +541,11 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages if: matrix.install - run: sudo apt install ${{matrix.install}} + run: sudo apt-get -y install ${{matrix.install}} - name: Setup Boost run: | @@ -582,7 +590,7 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages if: matrix.install @@ -641,7 +649,7 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages if: matrix.install @@ -698,7 +706,7 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup MSYS2 environment uses: msys2/setup-msys2@v2 @@ -709,7 +717,7 @@ jobs: pacboy: gcc:p cmake:p ninja:p - name: Fetch Boost.CI - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: boostorg/boost-ci ref: master From 8ac64cb208e7117f803300adb553338005b02b29 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 09:23:06 -0500 Subject: [PATCH 042/140] Change name of func in docs --- doc/decimal/cmath.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/decimal/cmath.adoc b/doc/decimal/cmath.adoc index ea8c0e34..5fef1661 100644 --- a/doc/decimal/cmath.adoc +++ b/doc/decimal/cmath.adoc @@ -459,13 +459,13 @@ constexpr boost::decimal::detail::uint128 frexpd128(decimal128 num, int* expptr) This function is very similar to https://en.cppreference.com/w/cpp/numeric/math/frexp[frexp], but returns the significand and an integral power of 10 since the `FLT_RADIX` of this type is 10. The significand is normalized to the number of digits of precision the type has (e.g. for decimal32 it is [1'000'000, 9'999'999]). -=== trunc_to +=== rescale [source, c++] ---- template -constexpr Decimal trunc_to(Decimal val, int precision = 0); +constexpr Decimal rescale(Decimal val, int precision = 0); ---- The function returns the decimal type with number of fractional digits equal to the value of precision. -`trunc_to` is similar to https://en.cppreference.com/w/cpp/numeric/math/trunc[trunc], and with the default precision argument of 0 it is identical. +`rescale` is similar to https://en.cppreference.com/w/cpp/numeric/math/trunc[trunc], and with the default precision argument of 0 it is identical. From ca66d89667808f2856548ed9d00a035f135e362f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 09:29:13 -0500 Subject: [PATCH 043/140] Rename file and function to rescale --- include/boost/decimal/cmath.hpp | 2 +- .../cmath/{trunc_to.hpp => rescale.hpp} | 11 ++++---- test/test_fixed_width_trunc.cpp | 28 +++++++++---------- 3 files changed, 20 insertions(+), 21 deletions(-) rename include/boost/decimal/detail/cmath/{trunc_to.hpp => rescale.hpp} (87%) diff --git a/include/boost/decimal/cmath.hpp b/include/boost/decimal/cmath.hpp index 922a16f5..7dc1c7e0 100644 --- a/include/boost/decimal/cmath.hpp +++ b/include/boost/decimal/cmath.hpp @@ -71,7 +71,7 @@ #include #include #include -#include +#include #include #include diff --git a/include/boost/decimal/detail/cmath/trunc_to.hpp b/include/boost/decimal/detail/cmath/rescale.hpp similarity index 87% rename from include/boost/decimal/detail/cmath/trunc_to.hpp rename to include/boost/decimal/detail/cmath/rescale.hpp index 91aa9077..b04fe308 100644 --- a/include/boost/decimal/detail/cmath/trunc_to.hpp +++ b/include/boost/decimal/detail/cmath/rescale.hpp @@ -1,9 +1,9 @@ -// Copyright 2024 Matt Borland +// Copyright 2025 Matt Borland // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#ifndef BOOST_DECIMAL_DETAIL_CMATH_TRUNC_TO_HPP -#define BOOST_DECIMAL_DETAIL_CMATH_TRUNC_TO_HPP +#ifndef BOOST_DECIMAL_DETAIL_CMATH_RESCALE_HPP +#define BOOST_DECIMAL_DETAIL_CMATH_RESCALE_HPP #include #include @@ -24,7 +24,7 @@ namespace boost { namespace decimal { BOOST_DECIMAL_EXPORT template -constexpr auto trunc_to(T val, int precision = 0) noexcept +constexpr auto rescale(T val, int precision = 0) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { constexpr auto biggest_val {1 / std::numeric_limits::epsilon()}; @@ -64,8 +64,7 @@ constexpr auto trunc_to(T val, int precision = 0) noexcept return {sig, exp, isneg}; } - } // namespace decimal } // namespace boost -#endif //BOOST_DECIMAL_DETAIL_CMATH_TRUNC_TO_HPP +#endif //BOOST_DECIMAL_DETAIL_CMATH_RESCALE_HPP diff --git a/test/test_fixed_width_trunc.cpp b/test/test_fixed_width_trunc.cpp index b43f3213..482fa568 100644 --- a/test/test_fixed_width_trunc.cpp +++ b/test/test_fixed_width_trunc.cpp @@ -20,30 +20,30 @@ void test() constexpr T validation_val_6 {UINT32_C(123457), 1}; constexpr T validation_val_7 {test_val}; - BOOST_TEST_EQ(trunc_to(test_val, 0), trunc_to(test_val)); - BOOST_TEST_EQ(trunc_to(test_val, 1), validation_val_1); - BOOST_TEST_EQ(trunc_to(test_val, 2), validation_val_2); - BOOST_TEST_EQ(trunc_to(test_val, 3), validation_val_3); - BOOST_TEST_EQ(trunc_to(test_val, 4), validation_val_4); - BOOST_TEST_EQ(trunc_to(test_val, 5), validation_val_5); - BOOST_TEST_EQ(trunc_to(test_val, 6), validation_val_6); - BOOST_TEST_EQ(trunc_to(test_val, 7), validation_val_7); - BOOST_TEST_EQ(trunc_to(test_val, 100), test_val); + BOOST_TEST_EQ(rescale(test_val, 0), rescale(test_val)); + BOOST_TEST_EQ(rescale(test_val, 1), validation_val_1); + BOOST_TEST_EQ(rescale(test_val, 2), validation_val_2); + BOOST_TEST_EQ(rescale(test_val, 3), validation_val_3); + BOOST_TEST_EQ(rescale(test_val, 4), validation_val_4); + BOOST_TEST_EQ(rescale(test_val, 5), validation_val_5); + BOOST_TEST_EQ(rescale(test_val, 6), validation_val_6); + BOOST_TEST_EQ(rescale(test_val, 7), validation_val_7); + BOOST_TEST_EQ(rescale(test_val, 100), test_val); // Non-finite values for (int i = 0; i < 10; ++i) { - BOOST_TEST(isinf(trunc_to(std::numeric_limits::infinity(), i))); - BOOST_TEST(isnan(trunc_to(std::numeric_limits::quiet_NaN(), i))); - BOOST_TEST(isnan(trunc_to(std::numeric_limits::signaling_NaN(), i))); - BOOST_TEST_EQ(trunc_to(T{0}, i), T{0}); + BOOST_TEST(isinf(rescale(std::numeric_limits::infinity(), i))); + BOOST_TEST(isnan(rescale(std::numeric_limits::quiet_NaN(), i))); + BOOST_TEST(isnan(rescale(std::numeric_limits::signaling_NaN(), i))); + BOOST_TEST_EQ(rescale(T{0}, i), T{0}); } // Big value constexpr T big_val {1, 20}; for (int i = 0; i < 10; ++i) { - BOOST_TEST_EQ(trunc_to(big_val, i), big_val); + BOOST_TEST_EQ(rescale(big_val, i), big_val); } } From 6e837dc2b8dc304694f4bf66d4832d3b7b718602 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 09:30:24 -0500 Subject: [PATCH 044/140] Add deprecation message to trunc_to --- include/boost/decimal/detail/cmath/rescale.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/boost/decimal/detail/cmath/rescale.hpp b/include/boost/decimal/detail/cmath/rescale.hpp index b04fe308..323ef2a3 100644 --- a/include/boost/decimal/detail/cmath/rescale.hpp +++ b/include/boost/decimal/detail/cmath/rescale.hpp @@ -64,6 +64,14 @@ constexpr auto rescale(T val, int precision = 0) noexcept return {sig, exp, isneg}; } +BOOST_DECIMAL_EXPORT template +[[deprecated("Renamed to rescale to match existing literature")]] +constexpr auto trunc_to(T val, int precision = 0) noexcept + BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) +{ + return rescale(val, precision); +} + } // namespace decimal } // namespace boost From 1df2fee3184f0c617d833b38013f1e01a9d0ed90 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 09:45:41 -0500 Subject: [PATCH 045/140] Remove garbage lines that confuse LCOV --- test/random_decimal128_fast_math.cpp | 454 -------------------------- test/random_decimal32_fast_math.cpp | 456 --------------------------- test/random_decimal64_fast_math.cpp | 455 -------------------------- 3 files changed, 1365 deletions(-) diff --git a/test/random_decimal128_fast_math.cpp b/test/random_decimal128_fast_math.cpp index d7a41955..2dffcf3f 100644 --- a/test/random_decimal128_fast_math.cpp +++ b/test/random_decimal128_fast_math.cpp @@ -435,447 +435,6 @@ void random_mixed_division(T lower, T upper) BOOST_TEST(isinf(decimal128_fast(dist(rng)) / 0 * dist(rng))); BOOST_TEST(isinf(val1 / zero)); } -/* -void random_and() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal128_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_fast res {dec1 & dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_and() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal128_fast res {dec1 & val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_fast res {val1 & dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_START - } - } -} - -void random_or() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal128_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_fast res {dec1 | dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_or() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal128_fast res {dec1 | val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_fast res {val1 | dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal128_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_fast res {dec1 ^ dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal128_fast res {dec1 ^ val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_fast res {val1 ^ dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_left_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal128_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_fast res {dec1 << dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_left_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal128_fast res {dec1 << val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_fast res {val1 << dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_right_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal128_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_fast res {dec1 >> dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_right_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal128_fast res {dec1 >> val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_fast res {val1 >> dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} -*/ int main() { @@ -974,19 +533,6 @@ int main() spot_check_sub(562, 998980); spot_check_sub(-954783, 746); spot_check_sub(513479119LL, 972535711690LL); - /* - // Bitwise operators - random_and(); - random_mixed_and(); - random_or(); - random_mixed_or(); - random_xor(); - random_mixed_xor(); - random_left_shift(); - random_mixed_left_shift(); - random_right_shift(); - random_mixed_right_shift(); - */ spot_check_mul(27625, 2977); diff --git a/test/random_decimal32_fast_math.cpp b/test/random_decimal32_fast_math.cpp index 6d959dcd..7a1070cf 100644 --- a/test/random_decimal32_fast_math.cpp +++ b/test/random_decimal32_fast_math.cpp @@ -424,448 +424,6 @@ void random_mixed_division(T lower, T upper) BOOST_TEST(isinf(val1 / zero)); } -/* -void random_and() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - decimal32_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_fast res {dec1 & dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_and() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - - const decimal32_fast res {dec1 & val2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_fast res {val1 & dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_or() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - decimal32_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_fast res {dec1 | dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_or() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - - const decimal32_fast res {dec1 | val2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_fast res {val1 | dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - decimal32_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_fast res {dec1 ^ dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - - const decimal32_fast res {dec1 ^ val2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_fast res {val1 ^ dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_left_shift() -{ - std::uniform_int_distribution dist(0, 5); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - decimal32_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_fast res {dec1 << dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_left_shift() -{ - std::uniform_int_distribution dist(0, 5); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - - const decimal32_fast res {dec1 << val2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_fast res {val1 << dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_right_shift() -{ - std::uniform_int_distribution dist(0, 5); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - decimal32_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_fast res {dec1 >> dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_right_shift() -{ - std::uniform_int_distribution dist(0, 5); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - - const decimal32_fast res {dec1 >> val2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_fast res {val1 >> dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} -*/ - int main() { // Values that won't exceed the range of the significand @@ -983,20 +541,6 @@ int main() random_mixed_division(-5'000LL, 5'000LL); random_mixed_division(-sqrt_int_max, sqrt_int_max); - /* - // Bitwise operators - random_and(); - random_mixed_and(); - random_or(); - random_mixed_or(); - random_xor(); - random_mixed_xor(); - random_left_shift(); - random_mixed_left_shift(); - random_right_shift(); - random_mixed_right_shift(); - */ - return boost::report_errors(); } diff --git a/test/random_decimal64_fast_math.cpp b/test/random_decimal64_fast_math.cpp index 3ac32a53..c9ed61f3 100644 --- a/test/random_decimal64_fast_math.cpp +++ b/test/random_decimal64_fast_math.cpp @@ -414,447 +414,6 @@ void random_mixed_division(T lower, T upper) BOOST_TEST(isinf(decimal64_fast(dist(rng)) / 0)); BOOST_TEST(isinf(val1 / zero)); } -/* -void random_and() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal64_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_fast res {dec1 & dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_and() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal64_fast res {dec1 & val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_fast res {val1 & dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_START - } - } -} - -void random_or() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal64_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_fast res {dec1 | dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_or() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal64_fast res {dec1 | val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_fast res {val1 | dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal64_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_fast res {dec1 ^ dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal64_fast res {dec1 ^ val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_fast res {val1 ^ dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_left_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal64_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_fast res {dec1 << dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_left_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal64_fast res {dec1 << val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_fast res {val1 << dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_right_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal64_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_fast res {dec1 >> dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_right_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal64_fast res {dec1 >> val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_fast dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_fast res {val1 >> dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} -*/ int main() { @@ -954,20 +513,6 @@ int main() spot_check_sub(-954783, 746); spot_check_sub(513479119LL, 972535711690LL); - /* - // Bitwise operators - random_and(); - random_mixed_and(); - random_or(); - random_mixed_or(); - random_xor(); - random_mixed_xor(); - random_left_shift(); - random_mixed_left_shift(); - random_right_shift(); - random_mixed_right_shift(); - */ - return boost::report_errors(); } From fe34e837e6f7adf877d694a1fe1634bfb5a4c15f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 09:53:25 -0500 Subject: [PATCH 046/140] Fix overlapping LCOV exclusions --- test/random_decimal64_math.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/random_decimal64_math.cpp b/test/random_decimal64_math.cpp index 2b5839c5..a6b3aaff 100644 --- a/test/random_decimal64_math.cpp +++ b/test/random_decimal64_math.cpp @@ -497,7 +497,7 @@ void random_mixed_and() << "\nDec 2: " << dec2 << "\nDec res: " << res << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_START + // LCOV_EXCL_STOP } } } From 62b5d6969276c84b194a5f37618c540c478c8f27 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 10:03:01 -0500 Subject: [PATCH 047/140] Add missing STD support to LCOV --- test/cover/make_gcov_03_flags.gmk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/cover/make_gcov_03_flags.gmk b/test/cover/make_gcov_03_flags.gmk index 7605ad96..672265fa 100644 --- a/test/cover/make_gcov_03_flags.gmk +++ b/test/cover/make_gcov_03_flags.gmk @@ -33,7 +33,8 @@ CXXFLAGS = -march=native \ -Wall \ -fno-inline-functions \ -fprofile-arcs \ - -ftest-coverage + -ftest-coverage \ + -std=$(STD) C_DEFINES = From 384155e7a926965bc92660062cd1f11b35c8c8f5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 10:03:12 -0500 Subject: [PATCH 048/140] Ignore unused errors in LCOV run --- test/cover/make_gcov_01_generic.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cover/make_gcov_01_generic.gmk b/test/cover/make_gcov_01_generic.gmk index b2fda69b..6e121fb8 100644 --- a/test/cover/make_gcov_01_generic.gmk +++ b/test/cover/make_gcov_01_generic.gmk @@ -63,7 +63,7 @@ gcov: objects @$(GNUECHO) @$(GNUECHO) +++ running lcov @$(LCOV) $(LCOV_BRANCH) -c --directory obj --output-file coverage_unfiltered.info - @$(LCOV) $(LCOV_BRANCH) --remove coverage_unfiltered.info $(LCOV_REMOVES) --output-file coverage.info + @$(LCOV) $(LCOV_BRANCH) --remove coverage_unfiltered.info $(LCOV_REMOVES) --ignore-errors unused --output-file coverage.info @$(GNUECHO) @$(GNUECHO) +++ running genhtml @$(GENHTML) coverage.info $(LCOV_BRANCH) --demangle-cpp --output-directory $(PATH_BIN)/report From 5806a35976d3b308a142909e7f5aa613c82668de Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 11:15:30 -0500 Subject: [PATCH 049/140] Remove IBM test cases to be safe on licensing --- test/Jamfile | 2 -- test/ibm_abs.cpp | 94 ------------------------------------------------ test/ibm_add.cpp | 61 ------------------------------- 3 files changed, 157 deletions(-) delete mode 100644 test/ibm_abs.cpp delete mode 100644 test/ibm_add.cpp diff --git a/test/Jamfile b/test/Jamfile index 17470c92..f3eb7cde 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -48,8 +48,6 @@ compile-fail concepts_test.cpp ; run github_issue_426.cpp ; run github_issue_448.cpp ; run-fail github_issue_519.cpp ; -run ibm_abs.cpp ; -run ibm_add.cpp ; run link_1.cpp link_2.cpp link_3.cpp ; run quick.cpp ; run random_decimal32_comp.cpp ; diff --git a/test/ibm_abs.cpp b/test/ibm_abs.cpp deleted file mode 100644 index e0b43fe5..00000000 --- a/test/ibm_abs.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2023 Matt Borland -// Copyright (c) Mike Cowlishaw, 1981, 2010. -// Parts copyright (c) IBM Corporation, 1981, 2008. -// Distributed under the Boost Software License, Version 1.0. -// https://www.boost.org/LICENSE_1_0.txt -// -// Derived from: https://speleotrove.com/decimal/dectest.html - -#include -#include -#include - -template -void test() -{ - BOOST_TEST_EQ(abs(T(1)), T(1)); - BOOST_TEST_EQ(abs(T(-1)), T(1)); - BOOST_TEST_EQ(abs(T(1.00)), T(1.00)); - BOOST_TEST_EQ(abs(T(-1.00)), T(1.00)); - BOOST_TEST_EQ(abs(T(0)), T(0.0)); - BOOST_TEST_EQ(abs(T(-0.0)), T(0.0)); - BOOST_TEST_EQ(abs(T(2)), T(2)); - BOOST_TEST_EQ(abs(T(-2)), T(2)); - BOOST_TEST_EQ(abs(T(2.00)), T(2.00)); - BOOST_TEST_EQ(abs(T(-2.00)), T(2.00)); - BOOST_TEST_EQ(abs(T(2000000)), T(2000000)); - BOOST_TEST_EQ(abs(T(-2000000)), T(2000000)); - - BOOST_TEST_EQ(abs(T(0.1)), T(0.1)); - BOOST_TEST_EQ(abs(T(0.01)), T(0.01)); - BOOST_TEST_EQ(abs(T(0.001)), T(0.001)); - BOOST_TEST_EQ(abs(T(0.00001)), T(0.00001)); - BOOST_TEST_EQ(abs(T(0.000001)), T(0.000001)); - - BOOST_TEST_EQ(abs(T(-0.1)), T(0.1)); - BOOST_TEST_EQ(abs(T(-0.01)), T(0.01)); - BOOST_TEST_EQ(abs(T(-0.001)), T(0.001)); - BOOST_TEST_EQ(abs(T(-0.00001)), T(0.00001)); - BOOST_TEST_EQ(abs(T(-0.000001)), T(0.000001)); - BOOST_TEST_EQ(abs(T(-0.000000000000000000001)), T(1, -21)); - - BOOST_TEST_EQ(abs(T(2.1)), T(2.1)); - BOOST_TEST_EQ(abs(T(-100)), T(100)); - BOOST_TEST_EQ(abs(T(101.5)), T(101.5)); - BOOST_TEST_EQ(abs(T(-101.5)), T(101.5)); -} - -template -void overflow_underflow_subnormals() -{ - BOOST_DECIMAL_IF_CONSTEXPR (std::is_same::value) - { - BOOST_TEST(isinf(abs(T(9.999e+200)))); - BOOST_TEST_EQ(abs(T(0.1e-200)), T(0.0)); - BOOST_TEST_EQ(abs(T(-0.1e-200)), T(0.0)); - } - #if (BOOST_DECIMAL_LDBL_BITS > 64) - else BOOST_DECIMAL_IF_CONSTEXPR (std::is_same::value) - { - BOOST_TEST(isinf(abs(T(9.999e+999L)))); - BOOST_TEST_EQ(abs(T(0.1e-999L)), T(0.0L)); - BOOST_TEST_EQ(abs(T(-0.1e-999L)), T(0.0L)); - } - #endif -} - -template -void non_finitie_values() -{ - BOOST_TEST_EQ(abs(T(std::numeric_limits::infinity())), T(std::numeric_limits::infinity())); - BOOST_TEST(!signbit(abs(T(std::numeric_limits::quiet_NaN())))); - BOOST_TEST(!signbit(abs(T(-std::numeric_limits::quiet_NaN())))); - BOOST_TEST(!signbit(abs(T(std::numeric_limits::signaling_NaN())))); - BOOST_TEST(!signbit(abs(T(-std::numeric_limits::signaling_NaN())))); -} - - -int main() -{ - test(); - test(); - test(); - - overflow_underflow_subnormals(); - overflow_underflow_subnormals(); - overflow_underflow_subnormals(); - - non_finitie_values(); - non_finitie_values(); - non_finitie_values(); - - return boost::report_errors(); -} - diff --git a/test/ibm_add.cpp b/test/ibm_add.cpp deleted file mode 100644 index 1bef0572..00000000 --- a/test/ibm_add.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2023 Matt Borland -// Copyright (c) Mike Cowlishaw, 1981, 2010. -// Parts copyright (c) IBM Corporation, 1981, 2008. -// Distributed under the Boost Software License, Version 1.0. -// https://www.boost.org/LICENSE_1_0.txt -// -// Derived from: https://speleotrove.com/decimal/dectest.html - -#include -#include -#include -#include -#include - -template -void test() -{ - std::cerr << std::setprecision(std::numeric_limits::digits10); - - BOOST_TEST_EQ(T(1) + T(1), T(2)); - BOOST_TEST_EQ(T(2) + T(3), T(5)); - BOOST_TEST_EQ(T(5.75) + T(3.3), T(9.05)); - BOOST_TEST_EQ(T(5) + T(-2), T(3)); - BOOST_TEST_EQ(T(-5) + T(-3), T(-8)); - BOOST_TEST_EQ(T(-7) + T(2.5), T(-4.5)); - BOOST_TEST_EQ(T(0.7) + T(0.3), T(1.0)); - BOOST_TEST_EQ(T(1.25) + T(1.25), T(2.50)); - BOOST_TEST_EQ(T(1.23456789) + T(1.000000000), T(2.23456789)); - BOOST_TEST_EQ(T(1.23456) + T(1.00044), T(2.23500)); -} - -template -void test_inexact() -{ - BOOST_TEST_EQ(T(0.444444444444444444444) + T(0.5555555555555555555555), T(1.00000000000000000)); - BOOST_TEST_EQ(T(0.444444444444444444449) + T(0.0), T(0.4444444444444444444444)); - BOOST_TEST_EQ(T(0.4444444444444444444499) + T(0.0), T(0.4444444444444444444444)); - BOOST_TEST_EQ(T(0.44444444444444444444999) + T(0.0), T(0.4444444444444444444444)); - - BOOST_DECIMAL_IF_CONSTEXPR (std::is_same::value) - { - BOOST_TEST_EQ(T(0.4444449) + T(0.0), T(0.4444449)); - BOOST_TEST_EQ(T(0.4444449) + T(0.0000001), T(0.4444450)); - BOOST_TEST_EQ(T(0.4444449) + T(0.00000009), T(0.4444450)); - } - -} - -int main() -{ - test(); - test(); - test(); - - test_inexact(); - test_inexact(); - test_inexact(); - - return boost::report_errors(); -} - From cb81ac4c747ad307ea8e4acc0a196e3745daee35 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 13:20:09 -0500 Subject: [PATCH 050/140] Annotate the library should be used from decimal.hpp --- doc/decimal/overview.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/decimal/overview.adoc b/doc/decimal/overview.adoc index 1fab53d8..f27c017a 100644 --- a/doc/decimal/overview.adoc +++ b/doc/decimal/overview.adoc @@ -43,6 +43,9 @@ Coverage can be found on https://app.codecov.io/gh/cppalliance/decimal[Codecov]. == Basic Usage +The entire library should be accessed using the convince header ``. +A short example of the basic usage: + [source, c++] ---- #include From b6773e23be5cfa2117ed0ce6d84986ba205ca710 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 13:22:33 -0500 Subject: [PATCH 051/140] Add format annotations to decimal type docs --- doc/decimal/decimal128.adoc | 2 ++ doc/decimal/decimal32.adoc | 2 ++ doc/decimal/decimal64.adoc | 2 ++ 3 files changed, 6 insertions(+) diff --git a/doc/decimal/decimal128.adoc b/doc/decimal/decimal128.adoc index 1ecbf5d9..9555352c 100644 --- a/doc/decimal/decimal128.adoc +++ b/doc/decimal/decimal128.adoc @@ -19,6 +19,8 @@ Decimal128 is the 128-bit version of the decimal interchange format, and has the - Smallest normalized value - 1.0000...e-6142 - Smallest subnormal - 1e-6176 +The encoding of Decimal128 is in the <>. + [source, c++] ---- #include diff --git a/doc/decimal/decimal32.adoc b/doc/decimal/decimal32.adoc index 27883690..9cb9ede3 100644 --- a/doc/decimal/decimal32.adoc +++ b/doc/decimal/decimal32.adoc @@ -19,6 +19,8 @@ Decimal32 is the 32-bit version of the decimal interchange format, and has the f - Smallest normalized value - 1.000000e-95 - Smallest subnormal - 1e-101 +The encoding of Decimal32 is in the <>. + [source, c++] ---- #include diff --git a/doc/decimal/decimal64.adoc b/doc/decimal/decimal64.adoc index 9f231366..390ca2f8 100644 --- a/doc/decimal/decimal64.adoc +++ b/doc/decimal/decimal64.adoc @@ -19,6 +19,8 @@ Decimal64 is the 64-bit version of the decimal interchange format, and has the f - Smallest normalized value - 1.000000000000000e-382 - Smallest subnormal - 1e-398 +The encoding of Decimal64 is in the <>. + [source, c++] ---- #include From 58c42c35c748a25b736cbdd172267ec2ce38495e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 13:55:29 -0500 Subject: [PATCH 052/140] Add stock data CSV --- examples/AAPL.csv | 253 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 examples/AAPL.csv diff --git a/examples/AAPL.csv b/examples/AAPL.csv new file mode 100644 index 00000000..ff54c640 --- /dev/null +++ b/examples/AAPL.csv @@ -0,0 +1,253 @@ +Date,Open,High,Low,Close,Volume +1/2/24,187.15,188.44,183.89,185.64,"82,488,672" +1/3/24,184.22,185.88,183.43,184.25,"58,414,461" +1/4/24,182.15,183.09,180.88,181.91,"71,983,570" +1/5/24,181.99,182.76,180.17,181.18,"62,379,660" +1/8/24,182.09,185.6,181.5,185.56,"59,144,473" +1/9/24,183.92,185.15,182.73,185.14,"42,841,809" +1/10/24,184.35,186.4,183.92,186.19,"46,792,910" +1/11/24,186.54,187.05,183.62,185.59,"49,128,406" +1/12/24,186.06,186.74,185.19,185.92,"40,477,781" +1/16/24,182.16,184.26,180.93,183.63,"65,603,039" +1/17/24,181.27,182.93,180.3,182.68,"47,317,434" +1/18/24,186.09,189.14,185.83,188.63,"78,005,750" +1/19/24,189.33,191.95,188.82,191.56,"68,902,992" +1/22/24,192.3,195.33,192.26,193.89,"60,133,848" +1/23/24,195.02,195.75,193.83,195.18,"42,355,594" +1/24/24,195.42,196.38,194.34,194.5,"53,631,320" +1/25/24,195.22,196.27,193.11,194.17,"54,822,129" +1/26/24,194.27,194.76,191.94,192.42,"44,594,008" +1/29/24,192.01,192.2,189.58,191.73,"47,145,621" +1/30/24,190.94,191.8,187.47,188.04,"55,859,367" +1/31/24,187.04,187.1,184.35,184.4,"55,467,801" +2/1/24,183.99,186.95,183.82,186.86,"64,885,406" +2/2/24,179.86,187.33,179.25,185.85,"102,551,695" +2/5/24,188.15,189.25,185.84,187.68,"69,668,812" +2/6/24,186.86,189.31,186.77,189.3,"43,490,762" +2/7/24,190.64,191.05,188.61,189.41,"53,438,961" +2/8/24,189.39,189.54,187.35,188.32,"40,962,047" +2/9/24,188.65,189.99,188,188.85,"45,155,219" +2/12/24,188.42,188.67,186.79,187.15,"41,781,930" +2/13/24,185.77,186.21,183.51,185.04,"56,529,527" +2/14/24,185.32,185.53,182.44,184.15,"54,630,520" +2/15/24,183.55,184.49,181.35,183.86,"65,434,500" +2/16/24,183.42,184.85,181.67,182.31,"49,752,473" +2/20/24,181.79,182.43,180,181.56,"53,665,551" +2/21/24,181.94,182.89,180.66,182.32,"41,529,672" +2/22/24,183.48,184.96,182.46,184.37,"52,292,207" +2/23/24,185.01,185.04,182.23,182.52,"45,119,680" +2/26/24,182.24,182.76,180.65,181.16,"40,867,422" +2/27/24,181.1,183.92,179.56,182.63,"54,318,848" +2/28/24,182.51,183.12,180.13,181.42,"48,953,941" +2/29/24,181.27,182.57,179.53,180.75,"136,682,594" +3/1/24,179.55,180.53,177.38,179.66,"73,563,078" +3/4/24,176.15,176.9,173.79,175.1,"81,510,094" +3/5/24,170.76,172.04,169.62,170.12,"95,132,359" +3/6/24,171.06,171.24,168.68,169.12,"68,587,711" +3/7/24,169.15,170.73,168.49,169,"71,765,055" +3/8/24,169,173.7,168.94,170.73,"76,267,039" +3/11/24,172.94,174.38,172.05,172.75,"60,139,473" +3/12/24,173.15,174.03,171.01,173.23,"59,825,367" +3/13/24,172.77,173.19,170.76,171.13,"52,488,688" +3/14/24,172.91,174.31,172.05,173,"72,913,516" +3/15/24,171.17,172.62,170.29,172.62,"121,752,703" +3/18/24,175.57,177.71,173.52,173.72,"75,604,180" +3/19/24,174.34,176.61,173.03,176.08,"55,215,238" +3/20/24,175.72,178.67,175.09,178.67,"53,423,102" +3/21/24,177.05,177.49,170.84,171.37,"106,181,297" +3/22/24,171.76,173.05,170.06,172.28,"71,160,141" +3/25/24,170.57,171.94,169.45,170.85,"54,288,328" +3/26/24,170,171.42,169.58,169.71,"57,388,449" +3/27/24,170.41,173.6,170.11,173.31,"60,273,273" +3/28/24,171.75,172.23,170.51,171.48,"65,672,688" +4/1/24,171.19,171.25,169.48,170.03,"46,240,500" +4/2/24,169.08,169.34,168.23,168.84,"49,329,480" +4/3/24,168.79,170.68,168.58,169.65,"47,691,719" +4/4/24,170.29,171.92,168.82,168.82,"53,704,391" +4/5/24,169.59,170.39,168.95,169.58,"42,104,832" +4/8/24,169.03,169.2,168.24,168.45,"37,425,512" +4/9/24,168.7,170.08,168.35,169.67,"42,451,207" +4/10/24,168.8,169.09,167.11,167.78,"49,709,340" +4/11/24,168.34,175.46,168.16,175.04,"91,070,281" +4/12/24,174.26,178.36,174.21,176.55,"101,670,898" +4/15/24,175.36,176.63,172.5,172.69,"73,531,766" +4/16/24,171.75,173.76,168.27,169.38,"73,711,242" +4/17/24,169.61,170.65,168,168,"50,901,207" +4/18/24,168.03,168.64,166.55,167.04,"43,122,898" +4/19/24,166.21,166.4,164.08,165,"68,149,375" +4/22/24,165.52,167.26,164.77,165.84,"48,116,441" +4/23/24,165.35,167.05,164.92,166.9,"49,537,762" +4/24/24,166.54,169.3,166.21,169.02,"48,251,840" +4/25/24,169.53,170.61,168.15,169.89,"50,558,328" +4/26/24,169.88,171.34,169.18,169.3,"44,838,352" +4/29/24,173.37,176.03,173.1,173.5,"68,169,422" +4/30/24,173.33,174.99,170,170.33,"65,934,781" +5/1/24,169.58,172.71,169.11,169.3,"50,383,152" +5/2/24,172.51,173.42,170.89,173.03,"94,214,922" +5/3/24,186.65,187,182.66,183.38,"163,224,094" +5/6/24,182.35,184.2,180.42,181.71,"78,569,672" +5/7/24,183.45,184.9,181.32,182.4,"77,305,766" +5/8/24,182.85,183.07,181.45,182.74,"45,057,090" +5/9/24,182.56,184.66,182.11,184.57,"48,982,969" +5/10/24,184.9,185.09,182.13,183.05,"50,759,500" +5/13/24,185.44,187.1,184.62,186.28,"72,044,805" +5/14/24,187.51,188.3,186.29,187.43,"52,393,621" +5/15/24,187.91,190.65,187.37,189.72,"70,399,992" +5/16/24,190.47,191.1,189.66,189.84,"52,845,230" +5/17/24,189.51,190.81,189.18,189.87,"41,282,930" +5/20/24,189.33,191.92,189.01,191.04,"44,361,281" +5/21/24,191.09,192.73,190.92,192.35,"42,309,398" +5/22/24,192.27,192.82,190.27,190.9,"34,648,551" +5/23/24,190.98,191,186.63,186.88,"51,005,922" +5/24/24,188.82,190.58,188.04,189.98,"36,326,980" +5/28/24,191.51,193,189.1,189.99,"52,280,047" +5/29/24,189.61,192.25,189.51,190.29,"53,068,020" +5/30/24,190.76,192.18,190.63,191.29,"49,947,941" +5/31/24,191.44,192.57,189.91,192.25,"75,158,281" +6/3/24,192.9,194.99,192.52,194.03,"50,080,539" +6/4/24,194.64,195.32,193.03,194.35,"47,471,449" +6/5/24,195.4,196.9,194.87,195.87,"54,156,793" +6/6/24,195.69,196.5,194.17,194.48,"41,181,754" +6/7/24,194.65,196.94,194.14,196.89,"53,103,910" +6/10/24,196.9,197.3,192.15,193.12,"97,262,078" +6/11/24,193.65,207.16,193.63,207.15,"172,373,297" +6/12/24,207.37,220.2,206.9,213.07,"198,134,297" +6/13/24,214.74,216.75,211.6,214.24,"97,862,727" +6/14/24,213.85,215.17,211.3,212.49,"70,122,750" +6/17/24,213.37,218.95,212.72,216.67,"93,728,305" +6/18/24,217.59,218.63,213,214.29,"79,943,250" +6/20/24,213.93,214.24,208.85,209.68,"86,172,445" +6/21/24,210.39,211.89,207.11,207.49,"246,421,406" +6/24/24,207.72,212.7,206.59,208.14,"80,727,008" +6/25/24,209.15,211.38,208.61,209.07,"56,713,871" +6/26/24,211.5,214.86,210.64,213.25,"66,213,195" +6/27/24,214.69,215.74,212.35,214.1,"49,772,711" +6/28/24,215.77,216.07,210.3,210.62,"82,542,719" +7/1/24,212.09,217.51,211.92,216.75,"60,402,930" +7/2/24,216.15,220.38,215.1,220.27,"58,046,180" +7/3/24,220,221.55,219.03,221.55,"37,369,801" +7/5/24,221.65,226.45,221.65,226.34,"60,412,406" +7/8/24,227.09,227.85,223.25,227.82,"59,085,859" +7/9/24,227.93,229.4,226.37,228.68,"48,169,820" +7/10/24,229.3,233.08,229.25,232.98,"62,627,688" +7/11/24,231.39,232.39,225.77,227.57,"64,710,621" +7/12/24,228.92,232.64,228.68,230.54,"53,046,527" +7/15/24,236.48,237.23,233.09,234.4,"62,631,246" +7/16/24,235,236.27,232.33,234.82,"43,234,281" +7/17/24,229.45,231.46,226.64,228.88,"57,345,879" +7/18/24,230.28,230.44,222.27,224.18,"66,034,594" +7/19/24,224.82,226.8,223.28,224.31,"49,151,449" +7/22/24,227.01,227.78,223.09,223.96,"48,201,840" +7/23/24,224.37,226.94,222.68,225.01,"39,960,262" +7/24/24,224,224.8,217.13,218.54,"61,777,578" +7/25/24,218.93,220.85,214.62,217.49,"51,391,199" +7/26/24,218.7,219.49,216.01,217.96,"41,601,352" +7/29/24,216.96,219.3,215.75,218.24,"36,311,781" +7/30/24,219.19,220.33,216.12,218.8,"41,643,840" +7/31/24,221.44,223.82,220.63,222.08,"50,036,262" +8/1/24,224.37,224.48,217.02,218.36,"62,501,000" +8/2/24,219.15,225.6,217.71,219.86,"105,568,602" +8/5/24,199.09,213.5,196,209.27,"119,548,602" +8/6/24,205.3,209.99,201.07,207.23,"69,660,484" +8/7/24,206.9,213.64,206.39,209.82,"63,516,422" +8/8/24,213.11,214.2,208.83,213.31,"47,161,152" +8/9/24,212.1,216.78,211.97,216.24,"42,201,648" +8/12/24,216.07,219.51,215.6,217.53,"38,028,090" +8/13/24,219.01,221.89,219.01,221.27,"44,155,328" +8/14/24,220.57,223.03,219.7,221.72,"41,960,566" +8/15/24,224.6,225.35,222.76,224.72,"46,414,008" +8/16/24,223.92,226.83,223.65,226.05,"44,340,238" +8/19/24,225.72,225.99,223.04,225.89,"40,687,809" +8/20/24,225.77,227.17,225.45,226.51,"30,299,029" +8/21/24,226.52,227.98,225.05,226.4,"34,765,480" +8/22/24,227.79,228.34,223.9,224.53,"43,695,320" +8/23/24,225.66,228.22,224.33,226.84,"38,677,246" +8/26/24,226.76,227.28,223.89,227.18,"30,602,211" +8/27/24,226,228.85,224.89,228.03,"35,934,559" +8/28/24,227.92,229.86,225.68,226.49,"38,052,168" +8/29/24,230.1,232.92,228.88,229.79,"51,906,301" +8/30/24,230.19,230.4,227.48,229,"52,990,770" +9/3/24,228.55,229,221.17,222.77,"50,087,200" +9/4/24,221.66,221.78,217.48,220.85,"43,840,199" +9/5/24,221.63,225.48,221.52,222.38,"36,615,398" +9/6/24,223.95,225.24,219.77,220.82,"48,423,008" +9/9/24,220.82,221.27,216.71,220.91,"67,179,969" +9/10/24,218.92,221.48,216.73,220.11,"51,591,031" +9/11/24,221.46,223.09,217.89,222.66,"44,587,070" +9/12/24,222.5,223.55,219.82,222.77,"37,498,230" +9/13/24,223.58,224.04,221.91,222.5,"36,766,621" +9/16/24,216.54,217.22,213.92,216.32,"59,357,434" +9/17/24,215.75,216.9,214.5,216.79,"45,519,340" +9/18/24,217.55,222.71,217.54,220.69,"59,894,930" +9/19/24,224.99,229.82,224.63,228.87,"66,781,320" +9/20/24,229.97,233.09,227.62,228.2,"318,679,906" +9/23/24,227.34,229.45,225.81,226.47,"54,146,020" +9/24/24,228.65,229.35,225.73,227.37,"43,556,070" +9/25/24,224.93,227.29,224.02,226.37,"42,308,719" +9/26/24,227.3,228.5,225.41,227.52,"36,636,711" +9/27/24,228.46,229.52,227.3,227.79,"34,025,969" +9/30/24,230.04,233,229.65,233,"54,793,391" +10/1/24,229.52,229.65,223.74,226.21,"63,285,047" +10/2/24,225.89,227.37,223.02,226.78,"32,880,609" +10/3/24,225.14,226.81,223.32,225.67,"34,044,160" +10/4/24,227.9,228,224.13,226.8,"37,345,102" +10/7/24,224.5,225.69,221.33,221.69,"39,505,352" +10/8/24,224.3,225.98,223.25,225.77,"31,855,689" +10/9/24,225.23,229.75,224.83,229.54,"33,591,090" +10/10/24,227.78,229.5,227.17,229.04,"28,183,539" +10/11/24,229.3,229.41,227.34,227.55,"31,759,189" +10/14/24,228.7,231.73,228.6,231.3,"39,882,090" +10/15/24,233.61,237.49,232.37,233.85,"64,751,367" +10/16/24,231.6,232.12,229.84,231.78,"34,082,238" +10/17/24,233.43,233.85,230.52,232.15,"32,993,809" +10/18/24,236.18,236.18,234.01,235,"46,431,473" +10/21/24,234.45,236.85,234.45,236.48,"36,254,473" +10/22/24,233.89,236.22,232.6,235.86,"38,846,578" +10/23/24,234.08,235.14,227.76,230.76,"52,286,980" +10/24/24,229.98,230.82,228.41,230.57,"31,109,500" +10/25/24,229.74,233.22,229.57,231.41,"38,802,301" +10/28/24,233.32,234.73,232.55,233.4,"36,087,129" +10/29/24,233.1,234.33,232.32,233.67,"35,417,246" +10/30/24,232.61,233.47,229.55,230.1,"47,070,910" +10/31/24,229.34,229.83,225.37,225.91,"64,370,090" +11/1/24,220.97,225.35,220.27,222.91,"65,276,738" +11/4/24,220.99,222.79,219.71,222.01,"44,944,473" +11/5/24,221.8,223.95,221.14,223.45,"28,111,340" +11/6/24,222.61,226.07,221.19,222.72,"54,561,121" +11/7/24,224.63,227.88,224.57,227.48,"42,137,688" +11/8/24,227.17,228.66,226.41,226.96,"38,328,820" +11/11/24,225,225.7,221.5,224.23,"42,005,602" +11/12/24,224.55,225.59,223.36,224.23,"40,398,301" +11/13/24,224.01,226.65,222.76,225.12,"48,566,219" +11/14/24,225.02,228.87,225,228.22,"44,923,941" +11/15/24,226.4,226.92,224.27,225,"47,923,699" +11/18/24,225.25,229.74,225.17,228.02,"44,686,020" +11/19/24,226.98,230.16,226.66,228.28,"36,211,770" +11/20/24,228.06,229.93,225.89,229,"35,169,566" +11/21/24,228.88,230.16,225.71,228.52,"42,108,328" +11/22/24,228.06,230.72,228.06,229.87,"38,168,246" +11/25/24,231.46,233.25,229.74,232.87,"90,152,828" +11/26/24,233.33,235.57,233.33,235.06,"45,986,191" +11/27/24,234.47,235.69,233.81,234.93,"33,498,441" +11/29/24,234.81,237.81,233.97,237.33,"28,481,381" +12/2/24,237.27,240.79,237.16,239.59,"48,137,102" +12/3/24,239.81,242.76,238.9,242.65,"38,861,020" +12/4/24,242.87,244.11,241.25,243.01,"44,383,941" +12/5/24,243.99,244.54,242.13,243.04,"40,033,879" +12/6/24,242.91,244.63,242.08,242.84,"36,870,621" +12/9/24,241.83,247.24,241.75,246.75,"44,649,230" +12/10/24,246.89,248.21,245.34,247.77,"36,914,809" +12/11/24,247.96,250.8,246.26,246.49,"45,205,809" +12/12/24,246.89,248.74,245.68,247.96,"32,777,531" +12/13/24,247.82,249.29,246.24,248.13,"33,155,289" +12/16/24,247.99,251.38,247.65,251.04,"51,694,754" +12/17/24,250.08,253.83,249.78,253.48,"51,356,359" +12/18/24,252.16,254.28,247.74,248.05,"56,774,102" +12/19/24,247.5,252,247.09,249.79,"60,882,262" +12/20/24,248.04,255,245.69,254.49,"147,495,297" +12/23/24,254.77,255.65,253.45,255.27,"40,858,770" +12/24/24,255.49,258.21,255.29,258.2,"23,234,711" +12/26/24,258.19,260.1,257.63,259.02,"27,262,980" +12/27/24,257.83,258.7,253.06,255.59,"42,355,320" +12/30/24,252.23,253.5,250.75,252.2,"35,557,539" +12/31/24,252.44,253.28,249.43,250.42,"39,480,719" \ No newline at end of file From d08649fc8ce259e1a39648d3d0ae03761c0fbf01 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 13:55:37 -0500 Subject: [PATCH 053/140] Add 30 day SMA example --- examples/moving_average.cpp | 188 ++++++++++++++++++++++++++++++++++++ test/Jamfile | 1 + 2 files changed, 189 insertions(+) create mode 100644 examples/moving_average.cpp diff --git a/examples/moving_average.cpp b/examples/moving_average.cpp new file mode 100644 index 00000000..b0a35903 --- /dev/null +++ b/examples/moving_average.cpp @@ -0,0 +1,188 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + + +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::decimal; + +auto where_file(const std::string& test_vectors_filename) -> std::string +{ + // Try to open the file in each of the known relative paths + // in order to find out where it is located. + + // Boost-root + std::string test_vectors_filename_relative = "libs/decimal/examples/" + test_vectors_filename; + + std::ifstream in_01(test_vectors_filename_relative.c_str()); + + const bool file_01_is_open { in_01.is_open() }; + + + if(file_01_is_open) + { + in_01.close(); + } + else + { + // Local test directory or IDE + test_vectors_filename_relative = "../examples/" + test_vectors_filename; + + std::ifstream in_02(test_vectors_filename_relative.c_str()); + + const bool file_02_is_open { in_02.is_open() }; + + if(file_02_is_open) + { + in_02.close(); + } + else + { + // test/cover + test_vectors_filename_relative = "../../examples/" + test_vectors_filename; + + std::ifstream in_03(test_vectors_filename_relative.c_str()); + + const bool file_03_is_open { in_03.is_open() }; + + if(file_03_is_open) + { + in_03.close(); + } + else + { + // CMake builds + test_vectors_filename_relative = "../../../../libs/decimal/examples/" + test_vectors_filename; + + std::ifstream in_04(test_vectors_filename_relative.c_str()); + + const bool file_04_is_open { in_04.is_open() }; + + if(file_04_is_open) + { + in_04.close(); + } + else + { + // Try to open the file from the absolute path. + test_vectors_filename_relative = test_vectors_filename; + + std::ifstream in_05(test_vectors_filename_relative.c_str()); + + const bool file_05_is_open { in_05.is_open() }; + + if(file_05_is_open) + { + in_05.close(); + } + else + { + // Clion Cmake builds + test_vectors_filename_relative = "../../../libs/decimal/examples/" + test_vectors_filename; + + std::ifstream in_06(test_vectors_filename_relative.c_str()); + + const bool file_06_is_open { in_06.is_open() }; + if (file_06_is_open) + { + in_06.close(); + } + else + { + test_vectors_filename_relative = ""; + } + } + } + } + } + } + + return test_vectors_filename_relative; +} + +struct daily_data +{ + std::string date; + decimal64 open; + decimal64 high; + decimal64 low; + decimal64 close; + decimal64 volume; +}; + +// Function to split a CSV line into daily_data +auto parse_csv_line(const std::string& line) -> daily_data +{ + std::stringstream ss(line); + std::string token; + daily_data data; + + // Parse each column + std::getline(ss, data.date, ','); + std::getline(ss, token, ','); + from_chars(token.c_str(), token.c_str() + token.size(), data.open); + + std::getline(ss, token, ','); + from_chars(token.c_str(), token.c_str() + token.size(), data.high); + + std::getline(ss, token, ','); + from_chars(token.c_str(), token.c_str() + token.size(), data.low); + + std::getline(ss, token, ','); + from_chars(token.c_str(), token.c_str() + token.size(), data.close); + + std::getline(ss, token, ','); + from_chars(token.c_str(), token.c_str() + token.size(), data.volume); + + return data; +} + +int main() +{ + std::vector stock_data; + const int window_size = 30; + + // Open and read the CSV file + std::ifstream file(where_file("AAPL.csv")); + std::string line; + + // Skip header line + std::getline(file, line); + + // Read data + while (std::getline(file, line)) { + stock_data.push_back(parse_csv_line(line)); + } + + // Calculate and print 30-day moving averages + std::cout << "Date,30-Day Moving Average\n"; + + size_t loop_count = 0; // Trivial counter to ensure this ran in the CI + for (size_t i = window_size - 1; i < stock_data.size(); ++i) + { + decimal64 sum(0); + + // Calculate sum for the window + for (int j = 0; j < window_size; ++j) { + sum += stock_data[i - j].close; + } + + // Calculate average + decimal64 moving_avg = sum / decimal64(window_size); + + // Print result + std::cout << stock_data[i].date << "," + << std::fixed << std::setprecision(2) << moving_avg << "\n"; + + ++loop_count; + } + + return loop_count == 0U; +} diff --git a/test/Jamfile b/test/Jamfile index f3eb7cde..265c6365 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -150,3 +150,4 @@ run ../examples/bit_conversions.cpp ; run ../examples/charconv.cpp ; run ../examples/literals.cpp ; run ../examples/rounding_mode.cpp ; +run ../examples/moving_average.cpp ; From 662cb347572f9265856e986be4b8130debf9e869 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 13:57:37 -0500 Subject: [PATCH 054/140] Add discussion of example to docs --- doc/decimal/examples.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/decimal/examples.adoc b/doc/decimal/examples.adoc index 167a5c22..f0200218 100644 --- a/doc/decimal/examples.adoc +++ b/doc/decimal/examples.adoc @@ -217,3 +217,10 @@ BID format: 31fc4b40 DPD format: 35f00000 ---- +== Financial Applications + +=== Simple Moving Average + +In the examples folder there is a file named `moving_average.cpp`. +This example shows how to parse historical stock data from file and use it. +This serves as a framework for other calculations for securities. From 8d68af9e4afbf217f32580c13019a06e41dca0ae Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 14:00:43 -0500 Subject: [PATCH 055/140] Fix sign conversion --- examples/moving_average.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/moving_average.cpp b/examples/moving_average.cpp index b0a35903..3ac45ca8 100644 --- a/examples/moving_average.cpp +++ b/examples/moving_average.cpp @@ -170,7 +170,7 @@ int main() decimal64 sum(0); // Calculate sum for the window - for (int j = 0; j < window_size; ++j) { + for (size_t j = 0; j < window_size; ++j) { sum += stock_data[i - j].close; } From c7bf93d6c75ff9440f2436fc33b7b3bb4039df10 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 14:06:08 -0500 Subject: [PATCH 056/140] Add currency conversion calculation --- examples/currency_conversion.cpp | 28 ++++++++++++++++++++++++++++ test/Jamfile | 1 + 2 files changed, 29 insertions(+) create mode 100644 examples/currency_conversion.cpp diff --git a/examples/currency_conversion.cpp b/examples/currency_conversion.cpp new file mode 100644 index 00000000..946e45b2 --- /dev/null +++ b/examples/currency_conversion.cpp @@ -0,0 +1,28 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +using namespace boost::decimal; + +auto convert_currency(decimal64 amount, decimal64 exchange_rate) -> decimal64 +{ + return amount * exchange_rate; +} + +int main() +{ + const auto usd_amount = strtod64("1000.50", nullptr); + const auto usd_to_eur_rate = strtod64("0.92", nullptr); + + const decimal64 eur_amount = convert_currency(usd_amount, usd_to_eur_rate); + const decimal64 exact_eur_amount = strtod64("920.46", nullptr); + + std::cout << "USD: " << std::fixed << std::setprecision(2) << usd_amount << "\n"; + std::cout << "EUR: " << std::fixed << std::setprecision(2) << eur_amount << "\n"; + + return !(eur_amount == exact_eur_amount); +} diff --git a/test/Jamfile b/test/Jamfile index 265c6365..bddeec3c 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -151,3 +151,4 @@ run ../examples/charconv.cpp ; run ../examples/literals.cpp ; run ../examples/rounding_mode.cpp ; run ../examples/moving_average.cpp ; +run ../examples/currency_conversion.cpp ; From 7de1e5b0879ca5c1f1a5263820a635796b3d7361 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 14:07:45 -0500 Subject: [PATCH 057/140] Use exact conversion from integer --- examples/currency_conversion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/currency_conversion.cpp b/examples/currency_conversion.cpp index 946e45b2..4617d516 100644 --- a/examples/currency_conversion.cpp +++ b/examples/currency_conversion.cpp @@ -19,7 +19,7 @@ int main() const auto usd_to_eur_rate = strtod64("0.92", nullptr); const decimal64 eur_amount = convert_currency(usd_amount, usd_to_eur_rate); - const decimal64 exact_eur_amount = strtod64("920.46", nullptr); + constexpr decimal64 exact_eur_amount(92046, -2); std::cout << "USD: " << std::fixed << std::setprecision(2) << usd_amount << "\n"; std::cout << "EUR: " << std::fixed << std::setprecision(2) << eur_amount << "\n"; From 539f670b54a318964cc324bc804ac9580f93deba Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 14:09:09 -0500 Subject: [PATCH 058/140] At brief discussion to docs --- doc/decimal/examples.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/decimal/examples.adoc b/doc/decimal/examples.adoc index f0200218..6c8b9b4d 100644 --- a/doc/decimal/examples.adoc +++ b/doc/decimal/examples.adoc @@ -224,3 +224,7 @@ DPD format: 35f00000 In the examples folder there is a file named `moving_average.cpp`. This example shows how to parse historical stock data from file and use it. This serves as a framework for other calculations for securities. + +=== Currency Conversion +In the examples folder there is a file named `currency_conversion.cpp`. +This example shows how to simply convert currencies based off a given exchange rate. From 7d0fed40523f5b5294cf6a1bf5a22e49bea34ec2 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 14:25:11 -0500 Subject: [PATCH 059/140] Fix doc header --- doc/decimal.adoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/decimal.adoc b/doc/decimal.adoc index a954151d..085ee902 100644 --- a/doc/decimal.adoc +++ b/doc/decimal.adoc @@ -4,7 +4,6 @@ Distributed under the Boost Software License, Version 1.0. https://www.boost.org/LICENSE_1_0.txt //// -= Decimal: IEEE 754 Decimal Floating Point Numbers :toc: left :toclevels: 4 :idprefix: @@ -15,6 +14,9 @@ https://www.boost.org/LICENSE_1_0.txt :leveloffset: +1 += Decimal: IEEE 754 Decimal Floating Point Numbers +Matt Borland and Chris Kormanyos + include::decimal/overview.adoc[] include::decimal/api_reference.adoc[] include::decimal/generic_decimal.adoc[] From 01376a857c3550872f8279007ef3aa2522d84aeb Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 15:18:19 -0500 Subject: [PATCH 060/140] Remove old and now unused FMA impls --- include/boost/decimal/detail/cmath/fma.hpp | 293 --------------------- 1 file changed, 293 deletions(-) diff --git a/include/boost/decimal/detail/cmath/fma.hpp b/include/boost/decimal/detail/cmath/fma.hpp index 7efffc4c..4c04b4e7 100644 --- a/include/boost/decimal/detail/cmath/fma.hpp +++ b/include/boost/decimal/detail/cmath/fma.hpp @@ -14,299 +14,6 @@ namespace boost { namespace decimal { -/* -constexpr auto fmad32(decimal32 x, decimal32 y, decimal32 z) noexcept -> decimal32 -{ - // First calculate x * y without rounding - constexpr decimal32 zero {0, 0}; - - const auto res {detail::check_non_finite(x, y)}; - if (res != zero) - { - return res; - } - - auto sig_lhs {x.full_significand()}; - auto exp_lhs {x.biased_exponent()}; - detail::normalize(sig_lhs, exp_lhs); - - auto sig_rhs {y.full_significand()}; - auto exp_rhs {y.biased_exponent()}; - detail::normalize(sig_rhs, exp_rhs); - - auto mul_result {detail::mul_impl(sig_lhs, exp_lhs, x.isneg(), sig_rhs, exp_rhs, y.isneg())}; - const decimal32 dec_result {mul_result.sig, mul_result.exp, mul_result.sign}; - - const auto res_add {detail::check_non_finite(dec_result, z)}; - if (res_add != zero) - { - return res_add; - } - - bool lhs_bigger {dec_result > z}; - if (dec_result.isneg() && z.isneg()) - { - lhs_bigger = !lhs_bigger; - } - bool abs_lhs_bigger {abs(dec_result) > abs(z)}; - - // To avoid the rounding step we promote the constituent pieces to the next higher type - detail::decimal64_components promoted_mul_result {static_cast(mul_result.sig), - mul_result.exp, mul_result.sign}; - - detail::normalize(promoted_mul_result.sig, promoted_mul_result.exp); - - auto sig_z {static_cast(z.full_significand())}; - auto exp_z {z.biased_exponent()}; - detail::normalize(sig_z, exp_z); - detail::decimal64_components z_components {sig_z, exp_z, z.isneg()}; - - if (!lhs_bigger) - { - detail::swap(promoted_mul_result, z_components); - abs_lhs_bigger = !abs_lhs_bigger; - } - - detail::decimal64_components result {}; - - if (!promoted_mul_result.sign && z_components.sign) - { - result = detail::d64_sub_impl(promoted_mul_result.sig, promoted_mul_result.exp, promoted_mul_result.sign, - z_components.sig, z_components.exp, z_components.sign, - abs_lhs_bigger); - } - else - { - result = detail::d64_add_impl(promoted_mul_result.sig, promoted_mul_result.exp, promoted_mul_result.sign, - z_components.sig, z_components.exp, z_components.sign); - } - - return {result.sig, result.exp, result.sign}; -} - -constexpr auto fmad64(decimal64 x, decimal64 y, decimal64 z) noexcept -> decimal64 -{ - // First calculate x * y without rounding - constexpr decimal64 zero {0, 0}; - - const auto res {detail::check_non_finite(x, y)}; - if (res != zero) - { - return res; - } - - auto sig_lhs {x.full_significand()}; - auto exp_lhs {x.biased_exponent()}; - detail::normalize(sig_lhs, exp_lhs); - - auto sig_rhs {y.full_significand()}; - auto exp_rhs {y.biased_exponent()}; - detail::normalize(sig_rhs, exp_rhs); - - auto mul_result {detail::d64_mul_impl(sig_lhs, exp_lhs, x.isneg(), sig_rhs, exp_rhs, y.isneg())}; - const decimal64 dec_result {mul_result.sig, mul_result.exp, mul_result.sign}; - - const auto res_add {detail::check_non_finite(dec_result, z)}; - if (res_add != zero) - { - return res_add; - } - - bool lhs_bigger {dec_result > z}; - if (dec_result.isneg() && z.isneg()) - { - lhs_bigger = !lhs_bigger; - } - bool abs_lhs_bigger {abs(dec_result) > abs(z)}; - - // To avoid the rounding step we promote the constituent pieces to the next higher type - detail::decimal128_components promoted_mul_result {static_cast(mul_result.sig), - mul_result.exp, mul_result.sign}; - - detail::normalize(promoted_mul_result.sig, promoted_mul_result.exp); - - auto sig_z {static_cast(z.full_significand())}; - auto exp_z {z.biased_exponent()}; - detail::normalize(sig_z, exp_z); - detail::decimal128_components z_components {sig_z, exp_z, z.isneg()}; - - if (!lhs_bigger) - { - detail::swap(promoted_mul_result, z_components); - abs_lhs_bigger = !abs_lhs_bigger; - } - - detail::decimal128_components result {}; - - if (!promoted_mul_result.sign && z_components.sign) - { - result = detail::d128_sub_impl( - promoted_mul_result.sig, promoted_mul_result.exp, promoted_mul_result.sign, - z_components.sig, z_components.exp, z_components.sign, - abs_lhs_bigger); - } - else - { - result = detail::d128_add_impl( - promoted_mul_result.sig, promoted_mul_result.exp, promoted_mul_result.sign, - z_components.sig, z_components.exp, z_components.sign); - } - - return {result.sig, result.exp, result.sign}; -} - -constexpr auto fmad128(decimal128 x, decimal128 y, decimal128 z) noexcept -> decimal128 -{ - return x * y + z; -} - -// TODO(mborland): promote to decimal64_fast instead of regular decimal64 once it is available -constexpr auto fmad32f(decimal32_fast x, decimal32_fast y, decimal32_fast z) noexcept -> decimal32_fast -{ - // First calculate x * y without rounding - constexpr decimal32_fast zero {0, 0}; - - const auto res {detail::check_non_finite(x, y)}; - if (res != zero) - { - return res; - } - - auto sig_lhs {x.full_significand()}; - auto exp_lhs {x.biased_exponent()}; - detail::normalize(sig_lhs, exp_lhs); - - auto sig_rhs {y.full_significand()}; - auto exp_rhs {y.biased_exponent()}; - detail::normalize(sig_rhs, exp_rhs); - - auto mul_result {detail::mul_impl(sig_lhs, exp_lhs, x.isneg(), sig_rhs, exp_rhs, y.isneg())}; - const decimal32_fast dec_result {mul_result.sig, mul_result.exp, mul_result.sign}; - - const auto res_add {detail::check_non_finite(dec_result, z)}; - if (res_add != zero) - { - return res_add; - } - - bool lhs_bigger {dec_result > z}; - if (dec_result.isneg() && z.isneg()) - { - lhs_bigger = !lhs_bigger; - } - bool abs_lhs_bigger {abs(dec_result) > abs(z)}; - - // To avoid the rounding step we promote the constituent pieces to the next higher type - detail::decimal64_components promoted_mul_result {static_cast(mul_result.sig), - mul_result.exp, mul_result.sign}; - - detail::normalize(promoted_mul_result.sig, promoted_mul_result.exp); - - auto sig_z {static_cast(z.full_significand())}; - auto exp_z {z.biased_exponent()}; - detail::normalize(sig_z, exp_z); - detail::decimal64_components z_components {sig_z, exp_z, z.isneg()}; - - if (!lhs_bigger) - { - detail::swap(promoted_mul_result, z_components); - abs_lhs_bigger = !abs_lhs_bigger; - } - - detail::decimal64_components result {}; - - if (!promoted_mul_result.sign && z_components.sign) - { - result = detail::d64_sub_impl(promoted_mul_result.sig, promoted_mul_result.exp, promoted_mul_result.sign, - z_components.sig, z_components.exp, z_components.sign, - abs_lhs_bigger); - } - else - { - result = detail::d64_add_impl(promoted_mul_result.sig, promoted_mul_result.exp, promoted_mul_result.sign, - z_components.sig, z_components.exp, z_components.sign); - } - - return {result.sig, result.exp, result.sign}; -} - -constexpr auto fmad64f(decimal64_fast x, decimal64_fast y, decimal64_fast z) noexcept -> decimal64_fast -{ - // First calculate x * y without rounding - constexpr decimal64_fast zero {0, 0}; - - const auto res {detail::check_non_finite(x, y)}; - if (res != zero) - { - return res; - } - - auto sig_lhs {x.full_significand()}; - auto exp_lhs {x.biased_exponent()}; - detail::normalize(sig_lhs, exp_lhs); - - auto sig_rhs {y.full_significand()}; - auto exp_rhs {y.biased_exponent()}; - detail::normalize(sig_rhs, exp_rhs); - - auto mul_result {detail::d64_mul_impl(sig_lhs, exp_lhs, x.isneg(), sig_rhs, exp_rhs, y.isneg())}; - const decimal64_fast dec_result {mul_result.sig, mul_result.exp, mul_result.sign}; - - const auto res_add {detail::check_non_finite(dec_result, z)}; - if (res_add != zero) - { - return res_add; - } - - bool lhs_bigger {dec_result > z}; - if (dec_result.isneg() && z.isneg()) - { - lhs_bigger = !lhs_bigger; - } - bool abs_lhs_bigger {abs(dec_result) > abs(z)}; - - // To avoid the rounding step we promote the constituent pieces to the next higher type - detail::decimal128_components promoted_mul_result {static_cast(mul_result.sig), - mul_result.exp, mul_result.sign}; - - detail::normalize(promoted_mul_result.sig, promoted_mul_result.exp); - - auto sig_z {static_cast(z.full_significand())}; - auto exp_z {z.biased_exponent()}; - detail::normalize(sig_z, exp_z); - detail::decimal128_components z_components {sig_z, exp_z, z.isneg()}; - - if (!lhs_bigger) - { - detail::swap(promoted_mul_result, z_components); - abs_lhs_bigger = !abs_lhs_bigger; - } - - detail::decimal128_components result {}; - - if (!promoted_mul_result.sign && z_components.sign) - { - result = detail::d128_sub_impl( - promoted_mul_result.sig, promoted_mul_result.exp, promoted_mul_result.sign, - z_components.sig, z_components.exp, z_components.sign, - abs_lhs_bigger); - } - else - { - result = detail::d128_add_impl( - promoted_mul_result.sig, promoted_mul_result.exp, promoted_mul_result.sign, - z_components.sig, z_components.exp, z_components.sign); - } - - return {result.sig, result.exp, result.sign}; -} - -constexpr auto fmad128f(decimal128_fast x, decimal128_fast y, decimal128_fast z) noexcept -> decimal128_fast -{ - return x * y + z; -} -*/ - BOOST_DECIMAL_EXPORT constexpr auto fma(decimal32 x, decimal32 y, decimal32 z) noexcept -> decimal32 { return x * y + z; From 8ded45b18e16b3ece403a3aae6c8f85b51426b13 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 15:36:41 -0500 Subject: [PATCH 061/140] Fix module warnings --- modules/decimal.cxx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modules/decimal.cxx b/modules/decimal.cxx index 41977a9b..61e29517 100644 --- a/modules/decimal.cxx +++ b/modules/decimal.cxx @@ -123,7 +123,17 @@ struct numeric_limits; // MSVC wants to be imported but also does not support importing it... #ifdef _MSC_VER +# pragma warning( push ) # pragma warning( disable : 5244 ) +#elif defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Winclude-angled-in-module-purview" #endif #include + +#ifdef _MSC_VER +# pragma warning( pop ) +#elif defined(__clang__) +# pragma clang diagnostic pop +#endif From 0a591daaf5bbb2e50bb66c606fc06d6aa8931aac Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 15:52:52 -0500 Subject: [PATCH 062/140] Define UINT macros --- include/boost/decimal/detail/config.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 21798fe9..07db81d6 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -325,4 +325,9 @@ typedef unsigned __int128 uint128_t; # endif #endif +#ifdef BOOST_DECIMAL_BUILD_MODULE +# define UINT64_C(x) (x ## ULL) +# define UINT32_C(x) (x ## UL) +#endif + #endif // BOOST_DECIMAL_DETAIL_CONFIG_HPP From 5cd77dd773a70c96d34744786b7ccddd91a22765 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Jan 2025 15:57:15 -0500 Subject: [PATCH 063/140] Add missing module header --- include/boost/decimal/detail/config.hpp | 10 ++++++++-- modules/decimal.cxx | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 07db81d6..3dec3b8c 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -325,9 +325,15 @@ typedef unsigned __int128 uint128_t; # endif #endif +// Since we should not be able to pull these in from the STL in module mode define them ourselves +// This is also low risk since they are not supposed to be exported #ifdef BOOST_DECIMAL_BUILD_MODULE -# define UINT64_C(x) (x ## ULL) -# define UINT32_C(x) (x ## UL) +# ifndef UINT64_C +# define UINT64_C(x) (x ## ULL) +# endif +# ifndef UINT32_C +# define UINT32_C(x) (x ## UL) +# endif #endif #endif // BOOST_DECIMAL_DETAIL_CONFIG_HPP diff --git a/modules/decimal.cxx b/modules/decimal.cxx index 61e29517..0031838c 100644 --- a/modules/decimal.cxx +++ b/modules/decimal.cxx @@ -29,6 +29,7 @@ module; #include #include #include +#include // is a C++23 feature that is not everywhere yet #if __has_include() From 3878a48f4cdc7e4f2ae7006bf963b1fd2263f51e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 3 Jan 2025 08:49:54 -0500 Subject: [PATCH 064/140] Add configuration for string_view --- include/boost/decimal/detail/config.hpp | 10 ++++++++++ modules/decimal.cxx | 1 + 2 files changed, 11 insertions(+) diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 3dec3b8c..fe4f36dc 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -323,6 +323,16 @@ typedef unsigned __int128 uint128_t; # define BOOST_DECIMAL_HAS_STD_CHARCONV # endif # endif + +# if __has_include() +# ifndef BOOST_DECIMAL_BUILD_MODULE +# include +# endif +# if __cpp_lib_string_view >= 201606L +# define BOOST_DECIMAL_HAS_STD_STRING_VIEW +# endif +# endif + #endif // Since we should not be able to pull these in from the STL in module mode define them ourselves diff --git a/modules/decimal.cxx b/modules/decimal.cxx index 0031838c..033c745b 100644 --- a/modules/decimal.cxx +++ b/modules/decimal.cxx @@ -30,6 +30,7 @@ module; #include #include #include +#include // is a C++23 feature that is not everywhere yet #if __has_include() From 0511600d06051187d218320f66be685d12b683ee Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 3 Jan 2025 09:02:01 -0500 Subject: [PATCH 065/140] Add from_chars string and string_view interfaces --- include/boost/decimal/charconv.hpp | 83 ++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/include/boost/decimal/charconv.hpp b/include/boost/decimal/charconv.hpp index 21a7a2ce..7e2c1c9a 100644 --- a/include/boost/decimal/charconv.hpp +++ b/include/boost/decimal/charconv.hpp @@ -27,6 +27,10 @@ #if !defined(BOOST_DECIMAL_DISABLE_CLIB) +#ifndef BOOST_DECIMAL_BUILD_MODULE +#include +#endif + namespace boost { namespace decimal { @@ -94,31 +98,103 @@ BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* la return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal32& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal32& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal32_fast& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal32_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal32_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal64& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal64& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal64& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal64_fast& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal64_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal64_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal128& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal128& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal128& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal128_fast& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal128_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal128_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + #ifdef BOOST_DECIMAL_HAS_STD_CHARCONV BOOST_DECIMAL_EXPORT template constexpr auto from_chars(const char* first, const char* last, DecimalType& value, std::chars_format fmt) noexcept @@ -147,6 +223,13 @@ constexpr auto from_chars(const char* first, const char* last, DecimalType& valu return std::from_chars_result {boost_r.ptr, boost_r.ec}; } + +BOOST_DECIMAL_EXPORT template +constexpr auto from_chars(std::string_view str, DecimalType& value, std::chars_format fmt) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::from_chars_result) +{ + return from_chars(str.data(), str.data() + str.size(), value, fmt); +} #endif // --------------------------------------------------------------------------------------------------------------------- From a51aa7fbae04aa90d1a2be84f1f4d88197e4bd8f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 3 Jan 2025 09:02:09 -0500 Subject: [PATCH 066/140] Add new interfaces testing --- test/test_from_chars.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/test_from_chars.cpp b/test/test_from_chars.cpp index 4964a5de..0500a29f 100644 --- a/test/test_from_chars.cpp +++ b/test/test_from_chars.cpp @@ -162,6 +162,7 @@ void test_non_finite_values() const char* snan_str = "nan(snan)"; auto r = from_chars(snan_str, snan_str + std::strlen(snan_str), val); + BOOST_TEST(r); BOOST_TEST(isnan(val)); const char* qnan_str = "nan"; @@ -318,6 +319,17 @@ void test_from_chars_general_std() #endif +template +void test_string_interface() +{ + constexpr T correct_val {42}; + std::string str {"42"}; + T val; + const auto r = from_chars(str, val); + BOOST_TEST(r); + BOOST_TEST_EQ(val, correct_val); +} + int main() { test_from_chars_scientific(); @@ -362,12 +374,25 @@ int main() test_hex_values(); test_hex_values(); + test_string_interface(); + test_string_interface(); + test_string_interface(); + test_string_interface(); + #if !defined(BOOST_DECIMAL_REDUCE_TEST_DEPTH) test_from_chars_scientific(); test_from_chars_fixed(); test_from_chars_general(); test_non_finite_values(); test_hex_values(); + test_string_interface(); + + test_from_chars_scientific(); + test_from_chars_fixed(); + test_from_chars_general(); + test_non_finite_values(); + test_hex_values(); + test_string_interface(); #endif return boost::report_errors(); From b92f11989fe3de83fbe006991ad4d78f3efffa4b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 3 Jan 2025 09:05:36 -0500 Subject: [PATCH 067/140] Add new interfaces to the docs --- doc/decimal/charconv.adoc | 12 ++++++++++++ doc/decimal/config.adoc | 2 ++ 2 files changed, 14 insertions(+) diff --git a/doc/decimal/charconv.adoc b/doc/decimal/charconv.adoc index 10c846ce..2ae86962 100644 --- a/doc/decimal/charconv.adoc +++ b/doc/decimal/charconv.adoc @@ -88,6 +88,18 @@ namespace decimal { template constexpr boost::decimal::from_chars_result from_chars(const char* first, const char* last, DecimalType& value, boost::decimal::chars_format fmt = boost::decimal::chars_format::general) noexcept +#ifdef BOOST_DECIMAL_HAS_STD_STRING_VIEW + +template +constexpr boost::decimal::from_chars_result from_chars(std::string_view str, DecimalType& value, boost::decimal::chars_format fmt = boost::decimal::chars_format::general) noexcept + +#else + +template +constexpr boost::decimal::from_chars_result from_chars(const std::string& str, DecimalType& value, boost::decimal::chars_format fmt = boost::decimal::chars_format::general) noexcept + +#endif + #ifdef BOOST_DECIMAL_HAS_STD_CHARCONV template diff --git a/doc/decimal/config.adoc b/doc/decimal/config.adoc index f578f489..268e91de 100644 --- a/doc/decimal/config.adoc +++ b/doc/decimal/config.adoc @@ -46,3 +46,5 @@ This flag increases the performance of the basis operations (e.g. add, sub, mul, - `BOOST_DECIMAL_HAS_STD_CHARCONV`: This macro is defined if header `` exists and the language standard used is >= C++17 * We only need the structs and enums out of the header so we are not concerned with being overly restrictive about the feature test macros. ** Known compilers that support this lighter requirement are: GCC >= 10, Clang >= 13, and MSVC >= 14.2 + +- `BOOST_DECIMAL_HAS_STD_STRING_VIEW`: This macro is defined if header `` exists and the langauge standard used is >= C++17 From 2cfee86242862d9e9e0d07b47841f37ba5df5549 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 3 Jan 2025 09:13:28 -0500 Subject: [PATCH 068/140] Fix illegal constexpr --- include/boost/decimal/charconv.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/boost/decimal/charconv.hpp b/include/boost/decimal/charconv.hpp index 7e2c1c9a..5fe93836 100644 --- a/include/boost/decimal/charconv.hpp +++ b/include/boost/decimal/charconv.hpp @@ -99,7 +99,7 @@ BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* la } #ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW -BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal32& value, chars_format fmt = chars_format::general) noexcept +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal32& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); } @@ -116,7 +116,7 @@ BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* la } #ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW -BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal32_fast& value, chars_format fmt = chars_format::general) noexcept +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal32_fast& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); } @@ -133,7 +133,7 @@ BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* la } #ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW -BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal64& value, chars_format fmt = chars_format::general) noexcept +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal64& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); } @@ -150,7 +150,7 @@ BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* la } #ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW -BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal64_fast& value, chars_format fmt = chars_format::general) noexcept +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal64_fast& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); } @@ -167,7 +167,7 @@ BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* la } #ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW -BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal128& value, chars_format fmt = chars_format::general) noexcept +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal128& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); } @@ -184,7 +184,7 @@ BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* la } #ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW -BOOST_DECIMAL_EXPORT constexpr auto from_chars(const std::string& str, decimal128_fast& value, chars_format fmt = chars_format::general) noexcept +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal128_fast& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); } From 4a62a7463938e4f4269407e8bab1f359bbe360a1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 3 Jan 2025 15:46:44 -0500 Subject: [PATCH 069/140] Add 32-bit FMA implementation --- include/boost/decimal/detail/cmath/fma.hpp | 88 +++++++++++++++++++++- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/cmath/fma.hpp b/include/boost/decimal/detail/cmath/fma.hpp index 4c04b4e7..e39a8265 100644 --- a/include/boost/decimal/detail/cmath/fma.hpp +++ b/include/boost/decimal/detail/cmath/fma.hpp @@ -9,14 +9,98 @@ #include #include #include +#include #include namespace boost { namespace decimal { +namespace detail { + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + +template +using components_type = std::conditional_t::value, decimal32_components, + std::conditional_t::value, decimal32_fast_components, + std::conditional_t::value, decimal64_components, + std::conditional_t::value, decimal64_fast_components, + std::conditional_t::value, decimal128_components, decimal128_fast_components + >>>>>; + +template +constexpr auto d32_fma_impl(T x, T y, T z) noexcept -> T +{ + using T_components_type = components_type; + using exp_type = typename T::biased_exponent_type; + + // Apply the add + #ifndef BOOST_DECIMAL_FAST_MATH + BOOST_DECIMAL_IF_CONSTEXPR (checked) + { + if (!isfinite(x) || !isfinite(y)) + { + return detail::check_non_finite(x, y); + } + } + #endif + + exp_type exp_lhs {}; + auto sig_lhs = frexp10(x, &exp_lhs); + + exp_type exp_rhs {}; + auto sig_rhs = frexp10(y, &exp_rhs); + + auto first_res = detail::mul_impl(sig_lhs, exp_lhs, x < 0, + sig_rhs, exp_rhs, y < 0); + + // Apply the mul on the carried components + // We still create the result as a decimal type to check for non-finite values and comparisons, + // but we do not use it for the resultant calculation + const T complete_lhs {first_res.sig, first_res.exp, first_res.sign}; + + #ifndef BOOST_DECIMAL_FAST_MATH + BOOST_DECIMAL_IF_CONSTEXPR (checked) + { + if (!isfinite(complete_lhs) || !isfinite(z)) + { + return detail::check_non_finite(complete_lhs, z); + } + } + #endif + + const bool abs_lhs_bigger {abs(complete_lhs) > abs(z)}; + + exp_type exp_z {}; + auto sig_z = frexp10(z, &exp_z); + detail::normalize(first_res.sig, first_res.exp); + + return detail::d32_add_impl(first_res.sig, first_res.exp, first_res.sign, + sig_z, exp_z, z < 0, + abs_lhs_bigger); +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +constexpr auto unchecked_fma(decimal32 x, decimal32 y, decimal32 z) noexcept -> decimal32 +{ + return detail::d32_fma_impl(x, y, z); +} + +constexpr auto unchecked_fma(decimal32_fast x, decimal32_fast y, decimal32_fast z) noexcept -> decimal32_fast +{ + return detail::d32_fma_impl(x, y, z); +} + +} // Namespace detail + BOOST_DECIMAL_EXPORT constexpr auto fma(decimal32 x, decimal32 y, decimal32 z) noexcept -> decimal32 { - return x * y + z; + return detail::d32_fma_impl(x, y, z); } BOOST_DECIMAL_EXPORT constexpr auto fma(decimal64 x, decimal64 y, decimal64 z) noexcept -> decimal64 @@ -31,7 +115,7 @@ BOOST_DECIMAL_EXPORT constexpr auto fma(decimal128 x, decimal128 y, decimal128 z BOOST_DECIMAL_EXPORT constexpr auto fma(decimal32_fast x, decimal32_fast y, decimal32_fast z) noexcept -> decimal32_fast { - return x * y + z; + return detail::d32_fma_impl(x, y, z); } BOOST_DECIMAL_EXPORT constexpr auto fma(decimal64_fast x, decimal64_fast y, decimal64_fast z) noexcept -> decimal64_fast From 16f8082c48b9fb2510ea9ff4979d21c8fb864c93 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 3 Jan 2025 16:03:04 -0500 Subject: [PATCH 070/140] Fix exp_type for frexp10 --- include/boost/decimal/detail/cmath/fma.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/boost/decimal/detail/cmath/fma.hpp b/include/boost/decimal/detail/cmath/fma.hpp index e39a8265..63319a6d 100644 --- a/include/boost/decimal/detail/cmath/fma.hpp +++ b/include/boost/decimal/detail/cmath/fma.hpp @@ -47,14 +47,14 @@ constexpr auto d32_fma_impl(T x, T y, T z) noexcept -> T } #endif - exp_type exp_lhs {}; + int exp_lhs {}; auto sig_lhs = frexp10(x, &exp_lhs); - exp_type exp_rhs {}; + int exp_rhs {}; auto sig_rhs = frexp10(y, &exp_rhs); - auto first_res = detail::mul_impl(sig_lhs, exp_lhs, x < 0, - sig_rhs, exp_rhs, y < 0); + auto first_res = detail::mul_impl(sig_lhs, static_cast(exp_lhs), x < 0, + sig_rhs, static_cast(exp_rhs), y < 0); // Apply the mul on the carried components // We still create the result as a decimal type to check for non-finite values and comparisons, @@ -73,12 +73,12 @@ constexpr auto d32_fma_impl(T x, T y, T z) noexcept -> T const bool abs_lhs_bigger {abs(complete_lhs) > abs(z)}; - exp_type exp_z {}; + int exp_z {}; auto sig_z = frexp10(z, &exp_z); detail::normalize(first_res.sig, first_res.exp); return detail::d32_add_impl(first_res.sig, first_res.exp, first_res.sign, - sig_z, exp_z, z < 0, + sig_z, static_cast(exp_z), z < 0, abs_lhs_bigger); } From a24babcc8d19cc31f99ce406bd09d3d60b2c8ea6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 10:12:09 -0500 Subject: [PATCH 071/140] Fix deprecated whitespace in literal definition --- include/boost/decimal/literals.hpp | 75 +++++++++++++++--------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/include/boost/decimal/literals.hpp b/include/boost/decimal/literals.hpp index 73d55540..7ae4e398 100644 --- a/include/boost/decimal/literals.hpp +++ b/include/boost/decimal/literals.hpp @@ -18,232 +18,233 @@ #include #endif -namespace boost { namespace decimal { +namespace boost { +namespace decimal { -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DF(const char* str) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DF(const char* str) -> decimal32 { decimal32 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(const char* str) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_df(const char* str) -> decimal32 { decimal32 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DF(const char* str, std::size_t len) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DF(const char* str, std::size_t len) -> decimal32 { decimal32 d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(const char* str, std::size_t len) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_df(const char* str, std::size_t len) -> decimal32 { decimal32 d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DF(unsigned long long v) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DF(unsigned long long v) -> decimal32 { return decimal32{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(unsigned long long v) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_df(unsigned long long v) -> decimal32 { return decimal32{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(const char* str) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DFF(const char* str) -> decimal32_fast { decimal32_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(const char* str) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dff(const char* str) -> decimal32_fast { decimal32_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(const char* str, std::size_t len) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DFF(const char* str, std::size_t len) -> decimal32_fast { decimal32_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(const char* str, std::size_t len) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dff(const char* str, std::size_t len) -> decimal32_fast { decimal32_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(unsigned long long v) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DFF(unsigned long long v) -> decimal32_fast { return decimal32_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(unsigned long long v) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dff(unsigned long long v) -> decimal32_fast { return decimal32_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DD(const char* str) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DD(const char* str) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dd(const char* str) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dd(const char* str) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DD(const char* str, std::size_t) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DD(const char* str, std::size_t) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dd(const char* str, std::size_t) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dd(const char* str, std::size_t) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DD(unsigned long long v) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DD(unsigned long long v) -> decimal64 { return decimal64{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dd(unsigned long long v) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dd(unsigned long long v) -> decimal64 { return decimal64{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(const char* str) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DDF(const char* str) -> decimal64_fast { decimal64_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(const char* str) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_ddf(const char* str) -> decimal64_fast { decimal64_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(const char* str, std::size_t len) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DDF(const char* str, std::size_t len) -> decimal64_fast { decimal64_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(const char* str, std::size_t len) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_ddf(const char* str, std::size_t len) -> decimal64_fast { decimal64_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(unsigned long long v) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DDF(unsigned long long v) -> decimal64_fast { return decimal64_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(unsigned long long v) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_ddf(unsigned long long v) -> decimal64_fast { return decimal64_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DL(const char* str) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DL(const char* str) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dl(const char* str) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dl(const char* str) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DL(const char* str, std::size_t) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DL(const char* str, std::size_t) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dl(const char* str, std::size_t) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dl(const char* str, std::size_t) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DL(unsigned long long v) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DL(unsigned long long v) -> decimal128 { return decimal128{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dl(unsigned long long v) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dl(unsigned long long v) -> decimal128 { return decimal128{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(const char* str) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DLF(const char* str) -> decimal128_fast { decimal128_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(const char* str) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dlf(const char* str) -> decimal128_fast { decimal128_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(const char* str, std::size_t len) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DLF(const char* str, std::size_t len) -> decimal128_fast { decimal128_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(const char* str, std::size_t len) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dlf(const char* str, std::size_t len) -> decimal128_fast { decimal128_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(unsigned long long v) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DLF(unsigned long long v) -> decimal128_fast { return decimal128_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(unsigned long long v) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dlf(unsigned long long v) -> decimal128_fast { return decimal128_fast{v}; } From c825582c025037fc71789a0b9064a70f8393d0d1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 10:12:09 -0500 Subject: [PATCH 072/140] Fix deprecated whitespace in literal definition --- include/boost/decimal/literals.hpp | 75 +++++++++++++++--------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/include/boost/decimal/literals.hpp b/include/boost/decimal/literals.hpp index 73d55540..7ae4e398 100644 --- a/include/boost/decimal/literals.hpp +++ b/include/boost/decimal/literals.hpp @@ -18,232 +18,233 @@ #include #endif -namespace boost { namespace decimal { +namespace boost { +namespace decimal { -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DF(const char* str) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DF(const char* str) -> decimal32 { decimal32 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(const char* str) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_df(const char* str) -> decimal32 { decimal32 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DF(const char* str, std::size_t len) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DF(const char* str, std::size_t len) -> decimal32 { decimal32 d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(const char* str, std::size_t len) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_df(const char* str, std::size_t len) -> decimal32 { decimal32 d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DF(unsigned long long v) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DF(unsigned long long v) -> decimal32 { return decimal32{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(unsigned long long v) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_df(unsigned long long v) -> decimal32 { return decimal32{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(const char* str) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DFF(const char* str) -> decimal32_fast { decimal32_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(const char* str) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dff(const char* str) -> decimal32_fast { decimal32_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(const char* str, std::size_t len) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DFF(const char* str, std::size_t len) -> decimal32_fast { decimal32_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(const char* str, std::size_t len) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dff(const char* str, std::size_t len) -> decimal32_fast { decimal32_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(unsigned long long v) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DFF(unsigned long long v) -> decimal32_fast { return decimal32_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(unsigned long long v) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dff(unsigned long long v) -> decimal32_fast { return decimal32_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DD(const char* str) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DD(const char* str) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dd(const char* str) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dd(const char* str) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DD(const char* str, std::size_t) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DD(const char* str, std::size_t) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dd(const char* str, std::size_t) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dd(const char* str, std::size_t) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DD(unsigned long long v) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DD(unsigned long long v) -> decimal64 { return decimal64{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dd(unsigned long long v) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dd(unsigned long long v) -> decimal64 { return decimal64{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(const char* str) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DDF(const char* str) -> decimal64_fast { decimal64_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(const char* str) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_ddf(const char* str) -> decimal64_fast { decimal64_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(const char* str, std::size_t len) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DDF(const char* str, std::size_t len) -> decimal64_fast { decimal64_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(const char* str, std::size_t len) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_ddf(const char* str, std::size_t len) -> decimal64_fast { decimal64_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(unsigned long long v) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DDF(unsigned long long v) -> decimal64_fast { return decimal64_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(unsigned long long v) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_ddf(unsigned long long v) -> decimal64_fast { return decimal64_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DL(const char* str) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DL(const char* str) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dl(const char* str) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dl(const char* str) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DL(const char* str, std::size_t) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DL(const char* str, std::size_t) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dl(const char* str, std::size_t) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dl(const char* str, std::size_t) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DL(unsigned long long v) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DL(unsigned long long v) -> decimal128 { return decimal128{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dl(unsigned long long v) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dl(unsigned long long v) -> decimal128 { return decimal128{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(const char* str) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DLF(const char* str) -> decimal128_fast { decimal128_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(const char* str) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dlf(const char* str) -> decimal128_fast { decimal128_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(const char* str, std::size_t len) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DLF(const char* str, std::size_t len) -> decimal128_fast { decimal128_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(const char* str, std::size_t len) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dlf(const char* str, std::size_t len) -> decimal128_fast { decimal128_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(unsigned long long v) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DLF(unsigned long long v) -> decimal128_fast { return decimal128_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(unsigned long long v) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dlf(unsigned long long v) -> decimal128_fast { return decimal128_fast{v}; } From de0fa3fa5bc7d8f44d689318a76556547252ace0 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 10:45:39 -0500 Subject: [PATCH 073/140] Move components definitions to a different file --- include/boost/decimal/decimal32.hpp | 11 +----- include/boost/decimal/decimal32_fast.hpp | 10 ----- include/boost/decimal/detail/components.hpp | 42 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 20 deletions(-) create mode 100644 include/boost/decimal/detail/components.hpp diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index df4e3629..e2454fbb 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -37,6 +37,7 @@ #include #include #include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE @@ -121,16 +122,6 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t d32_big_combination_field_mask = //BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t d32_construct_exp_mask = UINT32_C(0b0'00000'111111'0000000000'0000000000); //BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t d32_construct_significand_mask = d32_no_combination; -struct decimal32_components -{ - using significand_type = std::uint32_t; - using biased_exponent_type = std::int32_t; - - significand_type sig; - biased_exponent_type exp; - bool sign; -}; - } // namespace detail #if defined(__GNUC__) && __GNUC__ >= 8 diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 2921d1fe..2de21e4e 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -31,16 +31,6 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_inf = std::numeric_limits::max() - 1; BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_snan = std::numeric_limits::max() - 2; -struct decimal32_fast_components -{ - using significand_type = std::uint_fast32_t; - using biased_exponent_type = std::int_fast32_t; - - significand_type sig; - biased_exponent_type exp; - bool sign; -}; - } BOOST_DECIMAL_EXPORT class decimal32_fast final diff --git a/include/boost/decimal/detail/components.hpp b/include/boost/decimal/detail/components.hpp new file mode 100644 index 00000000..5b6738e0 --- /dev/null +++ b/include/boost/decimal/detail/components.hpp @@ -0,0 +1,42 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_DETAIL_COMPONENTS_HPP +#define BOOST_DECIMAL_DETAIL_COMPONENTS_HPP + +#include + +#ifndef BOOST_DECIMAL_BUILD_MODULE +#include +#endif + +namespace boost { +namespace decimal { +namespace detail { + +struct decimal32_components +{ + using significand_type = std::uint32_t; + using biased_exponent_type = std::int32_t; + + significand_type sig; + biased_exponent_type exp; + bool sign; +}; + +struct decimal32_fast_components +{ + using significand_type = std::uint_fast32_t; + using biased_exponent_type = std::int_fast32_t; + + significand_type sig; + biased_exponent_type exp; + bool sign; +}; + +} // namespace detail +} // namespace decimal +} // namespace boost + +#endif // BOOST_DECIMAL_DETAIL_COMPONENTS_HPP From 438605d9ab98001661f08d1f5efb11a04b239ed6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 10:46:09 -0500 Subject: [PATCH 074/140] Update SFINAE paths and remove old impl --- include/boost/decimal/detail/mul_impl.hpp | 46 ++--------------------- 1 file changed, 3 insertions(+), 43 deletions(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 29a698cf..1c3fb8ae 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE #include @@ -26,7 +27,7 @@ namespace detail { template BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, - T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value, ReturnType> + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value, ReturnType> { using mul_type = std::uint_fast64_t; @@ -38,7 +39,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lh template BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, - T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value, ReturnType> + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value, ReturnType> { using mul_type = std::uint_fast64_t; @@ -54,47 +55,6 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lh return {static_cast(res_sig), res_exp, lhs_sign != rhs_sign}; } -template -BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, - T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t, ReturnType> -{ - using mul_type = std::uint_fast64_t; - - #ifdef BOOST_DECIMAL_DEBUG - std::cerr << "sig lhs: " << sig_lhs - << "\nexp lhs: " << exp_lhs - << "\nsig rhs: " << sig_rhs - << "\nexp rhs: " << exp_rhs; - #endif - - bool sign {lhs_sign != rhs_sign}; - - // Once we have the normalized significands and exponents all we have to do is - // multiply the significands and add the exponents - // - // We use a 64 bit resultant significand because the two 23-bit unsigned significands will always fit - - auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; - auto res_exp {lhs_exp + rhs_exp}; - - // We don't need to use the regular binary search tree detail::num_digits(res_sig) - // because we know that res_sig must be [1'000'000^2, 9'999'999^2] which only differ by one order - // of magnitude in their number of digits - const auto sig_dig {res_sig >= UINT64_C(10000000000000) ? 14 : 13}; - constexpr auto max_dig {std::numeric_limits::digits10}; - res_sig /= detail::pow10(static_cast(sig_dig - max_dig)); - res_exp += sig_dig - max_dig; - - const auto res_sig_32 {static_cast(res_sig)}; - - #ifdef BOOST_DECIMAL_DEBUG - std::cerr << "\nres sig: " << res_sig_32 - << "\nres exp: " << res_exp << std::endl; - #endif - - return {res_sig_32, res_exp, sign}; -} - template BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, T rhs_sig, U rhs_exp, bool rhs_sign) noexcept From bfa8a1854c13b1f7b631f2a91eff8295e67e256c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 11:16:08 -0500 Subject: [PATCH 075/140] Ignore warning from multi-precision in test --- test/test_big_uints.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test_big_uints.cpp b/test/test_big_uints.cpp index 99029e4e..69831483 100644 --- a/test/test_big_uints.cpp +++ b/test/test_big_uints.cpp @@ -30,6 +30,11 @@ int main() # pragma clang diagnostic ignored "-Wsign-conversion" # pragma clang diagnostic ignored "-Wfloat-equal" # pragma clang diagnostic ignored "-Wdeprecated-declarations" + +# if __clang_major__ >= 20 +# pragma clang diagnostic ignored "-Wdeprecated-literal-operator" +# endif + #elif defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wold-style-cast" From 30c0fbad3ee7b832c41ac89b59cdc689dbb56b09 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 11:22:24 -0500 Subject: [PATCH 076/140] Fix narrowing --- include/boost/decimal/detail/mul_impl.hpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 1c3fb8ae..58b013ef 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -25,21 +25,10 @@ namespace detail { // 1) Returns a decimal type and lets the constructor handle with shrinking the significand // 2) Returns a struct of the constituent components (used with FMAs) -template -BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, - T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value, ReturnType> -{ - using mul_type = std::uint_fast64_t; - - const auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; - const auto res_exp {lhs_exp + rhs_exp}; - - return {res_sig, res_exp, lhs_sign != rhs_sign}; -} template BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, - T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value, ReturnType> + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> ReturnType { using mul_type = std::uint_fast64_t; From 170edaa7af3245a030a1450eab6904b6767cda17 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 11:38:12 -0500 Subject: [PATCH 077/140] Add clang18 and 19 to fuzzing runs --- .github/workflows/fuzz.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 4487018f..7b39766c 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -86,6 +86,26 @@ jobs: - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" source_keys: - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-18 + cxxstd: "14,17,20,23" + os: ubuntu-24.04 + install: + - clang-18 + sources: + - "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-18 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-19 + cxxstd: "14,17,20,23" + os: ubuntu-24.04 + install: + - clang-19 + sources: + - "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" timeout-minutes: 60 From 9ddfbc3670c134e60d344c078e494c765dfa85a9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 11:45:05 -0500 Subject: [PATCH 078/140] Add string and string view interface fuzzing --- fuzzing/fuzz_from_chars_float.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/fuzzing/fuzz_from_chars_float.cpp b/fuzzing/fuzz_from_chars_float.cpp index 68ab0342..8153cb34 100644 --- a/fuzzing/fuzz_from_chars_float.cpp +++ b/fuzzing/fuzz_from_chars_float.cpp @@ -26,6 +26,36 @@ extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size boost::decimal::decimal128 ld_val; boost::decimal::from_chars(c_data, c_data + size, ld_val, format); } + + // Now with strings + const auto c_data_str = std::string(c_data); + for (const auto format : formats) + { + boost::decimal::decimal32 f_val; + boost::decimal::from_chars(c_data_str, f_val, format); + + boost::decimal::decimal64 val; + boost::decimal::from_chars(c_data_str, val, format); + + boost::decimal::decimal128 ld_val; + boost::decimal::from_chars(c_data_str, ld_val, format); + } + + // And string views as applicable + #ifdef BOOST_DECIMAL_HAS_STD_STRING_VIEW + const auto c_data_str_view = std::string_view(c_data_str); + for (const auto format : formats) + { + boost::decimal::decimal32 f_val; + boost::decimal::from_chars(c_data_str_view, f_val, format); + + boost::decimal::decimal64 val; + boost::decimal::from_chars(c_data_str_view, val, format); + + boost::decimal::decimal128 ld_val; + boost::decimal::from_chars(c_data_str_view, ld_val, format); + } + #endif } catch(...) { From 934596235c8f23271a1f8d4ce402bb8c03547abc Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 11:45:49 -0500 Subject: [PATCH 079/140] Add crash file --- .../crash-da39a3ee5e6b4b0d3255bfef95601890afd80709 | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 fuzzing/old_crashes/fuzz_from_chars_float/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709 diff --git a/fuzzing/old_crashes/fuzz_from_chars_float/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709 b/fuzzing/old_crashes/fuzz_from_chars_float/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709 new file mode 100644 index 00000000..e69de29b From 8218b96d46037b5355a5b6b9915ea50595062802 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 10:12:09 -0500 Subject: [PATCH 080/140] Fix deprecated whitespace in literal definition --- include/boost/decimal/literals.hpp | 75 +++++++++++++++--------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/include/boost/decimal/literals.hpp b/include/boost/decimal/literals.hpp index 73d55540..7ae4e398 100644 --- a/include/boost/decimal/literals.hpp +++ b/include/boost/decimal/literals.hpp @@ -18,232 +18,233 @@ #include #endif -namespace boost { namespace decimal { +namespace boost { +namespace decimal { -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DF(const char* str) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DF(const char* str) -> decimal32 { decimal32 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(const char* str) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_df(const char* str) -> decimal32 { decimal32 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DF(const char* str, std::size_t len) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DF(const char* str, std::size_t len) -> decimal32 { decimal32 d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(const char* str, std::size_t len) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_df(const char* str, std::size_t len) -> decimal32 { decimal32 d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DF(unsigned long long v) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DF(unsigned long long v) -> decimal32 { return decimal32{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _df(unsigned long long v) -> decimal32 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_df(unsigned long long v) -> decimal32 { return decimal32{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(const char* str) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DFF(const char* str) -> decimal32_fast { decimal32_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(const char* str) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dff(const char* str) -> decimal32_fast { decimal32_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(const char* str, std::size_t len) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DFF(const char* str, std::size_t len) -> decimal32_fast { decimal32_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(const char* str, std::size_t len) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dff(const char* str, std::size_t len) -> decimal32_fast { decimal32_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DFF(unsigned long long v) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DFF(unsigned long long v) -> decimal32_fast { return decimal32_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dff(unsigned long long v) -> decimal32_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dff(unsigned long long v) -> decimal32_fast { return decimal32_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DD(const char* str) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DD(const char* str) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dd(const char* str) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dd(const char* str) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DD(const char* str, std::size_t) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DD(const char* str, std::size_t) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dd(const char* str, std::size_t) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dd(const char* str, std::size_t) -> decimal64 { decimal64 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DD(unsigned long long v) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DD(unsigned long long v) -> decimal64 { return decimal64{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dd(unsigned long long v) -> decimal64 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dd(unsigned long long v) -> decimal64 { return decimal64{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(const char* str) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DDF(const char* str) -> decimal64_fast { decimal64_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(const char* str) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_ddf(const char* str) -> decimal64_fast { decimal64_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(const char* str, std::size_t len) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DDF(const char* str, std::size_t len) -> decimal64_fast { decimal64_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(const char* str, std::size_t len) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_ddf(const char* str, std::size_t len) -> decimal64_fast { decimal64_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DDF(unsigned long long v) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DDF(unsigned long long v) -> decimal64_fast { return decimal64_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _ddf(unsigned long long v) -> decimal64_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_ddf(unsigned long long v) -> decimal64_fast { return decimal64_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DL(const char* str) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DL(const char* str) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dl(const char* str) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dl(const char* str) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DL(const char* str, std::size_t) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DL(const char* str, std::size_t) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dl(const char* str, std::size_t) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dl(const char* str, std::size_t) -> decimal128 { decimal128 d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DL(unsigned long long v) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DL(unsigned long long v) -> decimal128 { return decimal128{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dl(unsigned long long v) -> decimal128 +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dl(unsigned long long v) -> decimal128 { return decimal128{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(const char* str) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DLF(const char* str) -> decimal128_fast { decimal128_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(const char* str) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dlf(const char* str) -> decimal128_fast { decimal128_fast d; from_chars(str, str + detail::strlen(str), d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(const char* str, std::size_t len) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DLF(const char* str, std::size_t len) -> decimal128_fast { decimal128_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(const char* str, std::size_t len) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dlf(const char* str, std::size_t len) -> decimal128_fast { decimal128_fast d; from_chars(str, str + len, d); return d; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _DLF(unsigned long long v) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_DLF(unsigned long long v) -> decimal128_fast { return decimal128_fast{v}; } -BOOST_DECIMAL_EXPORT constexpr auto operator "" _dlf(unsigned long long v) -> decimal128_fast +BOOST_DECIMAL_EXPORT constexpr auto operator ""_dlf(unsigned long long v) -> decimal128_fast { return decimal128_fast{v}; } From 2b5ce43f93f758f0056547b4f2a807114b48244d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 11:57:14 -0500 Subject: [PATCH 081/140] Test the null string and add length in fuzz file --- fuzzing/fuzz_from_chars_float.cpp | 2 +- test/test_from_chars.cpp | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/fuzzing/fuzz_from_chars_float.cpp b/fuzzing/fuzz_from_chars_float.cpp index 8153cb34..bcb8e26d 100644 --- a/fuzzing/fuzz_from_chars_float.cpp +++ b/fuzzing/fuzz_from_chars_float.cpp @@ -28,7 +28,7 @@ extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size } // Now with strings - const auto c_data_str = std::string(c_data); + const auto c_data_str = std::string(c_data, size); for (const auto format : formats) { boost::decimal::decimal32 f_val; diff --git a/test/test_from_chars.cpp b/test/test_from_chars.cpp index 0500a29f..cc0a8ec0 100644 --- a/test/test_from_chars.cpp +++ b/test/test_from_chars.cpp @@ -325,9 +325,20 @@ void test_string_interface() constexpr T correct_val {42}; std::string str {"42"}; T val; - const auto r = from_chars(str, val); + auto r = from_chars(str, val); BOOST_TEST(r); BOOST_TEST_EQ(val, correct_val); + + // Empty string + std::string empty; + r = from_chars(empty, val); + BOOST_TEST(r.ec == std::errc::invalid_argument); + + #ifdef BOOST_DECIMAL_HAS_STD_STRING_VIEW + std::string_view empty_view = std::string_view(empty); + r = from_chars(empty_view, val); + BOOST_TEST(r.ec == std::errc::invalid_argument); + #endif } int main() From 16c12353b03a7ea945a4e27f54cd41e310196199 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 12:58:45 -0500 Subject: [PATCH 082/140] Move where_file for examples --- examples/moving_average.cpp | 96 +----------------------------- examples/where_file.hpp | 113 ++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 95 deletions(-) create mode 100644 examples/where_file.hpp diff --git a/examples/moving_average.cpp b/examples/moving_average.cpp index 3ac45ca8..6561514b 100644 --- a/examples/moving_average.cpp +++ b/examples/moving_average.cpp @@ -2,7 +2,7 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt - +#include "where_file.hpp" #include #include #include @@ -13,100 +13,6 @@ using namespace boost::decimal; -auto where_file(const std::string& test_vectors_filename) -> std::string -{ - // Try to open the file in each of the known relative paths - // in order to find out where it is located. - - // Boost-root - std::string test_vectors_filename_relative = "libs/decimal/examples/" + test_vectors_filename; - - std::ifstream in_01(test_vectors_filename_relative.c_str()); - - const bool file_01_is_open { in_01.is_open() }; - - - if(file_01_is_open) - { - in_01.close(); - } - else - { - // Local test directory or IDE - test_vectors_filename_relative = "../examples/" + test_vectors_filename; - - std::ifstream in_02(test_vectors_filename_relative.c_str()); - - const bool file_02_is_open { in_02.is_open() }; - - if(file_02_is_open) - { - in_02.close(); - } - else - { - // test/cover - test_vectors_filename_relative = "../../examples/" + test_vectors_filename; - - std::ifstream in_03(test_vectors_filename_relative.c_str()); - - const bool file_03_is_open { in_03.is_open() }; - - if(file_03_is_open) - { - in_03.close(); - } - else - { - // CMake builds - test_vectors_filename_relative = "../../../../libs/decimal/examples/" + test_vectors_filename; - - std::ifstream in_04(test_vectors_filename_relative.c_str()); - - const bool file_04_is_open { in_04.is_open() }; - - if(file_04_is_open) - { - in_04.close(); - } - else - { - // Try to open the file from the absolute path. - test_vectors_filename_relative = test_vectors_filename; - - std::ifstream in_05(test_vectors_filename_relative.c_str()); - - const bool file_05_is_open { in_05.is_open() }; - - if(file_05_is_open) - { - in_05.close(); - } - else - { - // Clion Cmake builds - test_vectors_filename_relative = "../../../libs/decimal/examples/" + test_vectors_filename; - - std::ifstream in_06(test_vectors_filename_relative.c_str()); - - const bool file_06_is_open { in_06.is_open() }; - if (file_06_is_open) - { - in_06.close(); - } - else - { - test_vectors_filename_relative = ""; - } - } - } - } - } - } - - return test_vectors_filename_relative; -} - struct daily_data { std::string date; diff --git a/examples/where_file.hpp b/examples/where_file.hpp new file mode 100644 index 00000000..60ab551a --- /dev/null +++ b/examples/where_file.hpp @@ -0,0 +1,113 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_EXAMPLE_WHERE_FILE_HPP +#define BOOST_DECIMAL_EXAMPLE_WHERE_FILE_HPP + +#include +#include +#include +#include + +namespace boost { +namespace decimal { + +auto where_file(const std::string& test_vectors_filename) -> std::string +{ + // Try to open the file in each of the known relative paths + // in order to find out where it is located. + + // Boost-root + std::string test_vectors_filename_relative = "libs/decimal/examples/" + test_vectors_filename; + + std::ifstream in_01(test_vectors_filename_relative.c_str()); + + const bool file_01_is_open { in_01.is_open() }; + + + if(file_01_is_open) + { + in_01.close(); + } + else + { + // Local test directory or IDE + test_vectors_filename_relative = "../examples/" + test_vectors_filename; + + std::ifstream in_02(test_vectors_filename_relative.c_str()); + + const bool file_02_is_open { in_02.is_open() }; + + if(file_02_is_open) + { + in_02.close(); + } + else + { + // test/cover + test_vectors_filename_relative = "../../examples/" + test_vectors_filename; + + std::ifstream in_03(test_vectors_filename_relative.c_str()); + + const bool file_03_is_open { in_03.is_open() }; + + if(file_03_is_open) + { + in_03.close(); + } + else + { + // CMake builds + test_vectors_filename_relative = "../../../../libs/decimal/examples/" + test_vectors_filename; + + std::ifstream in_04(test_vectors_filename_relative.c_str()); + + const bool file_04_is_open { in_04.is_open() }; + + if(file_04_is_open) + { + in_04.close(); + } + else + { + // Try to open the file from the absolute path. + test_vectors_filename_relative = test_vectors_filename; + + std::ifstream in_05(test_vectors_filename_relative.c_str()); + + const bool file_05_is_open { in_05.is_open() }; + + if(file_05_is_open) + { + in_05.close(); + } + else + { + // Clion Cmake builds + test_vectors_filename_relative = "../../../libs/decimal/examples/" + test_vectors_filename; + + std::ifstream in_06(test_vectors_filename_relative.c_str()); + + const bool file_06_is_open { in_06.is_open() }; + if (file_06_is_open) + { + in_06.close(); + } + else + { + test_vectors_filename_relative = ""; + } + } + } + } + } + } + + return test_vectors_filename_relative; +} + +} // namespace decimal +} // namespace boost + +#endif //BOOST_DECIMAL_EXAMPLE_WHERE_FILE_HPP From 5ded2233fcc759883bbee3f4ee60591fcbfb4055 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 13:33:49 -0500 Subject: [PATCH 083/140] Add example using boost.math.univariate statistics --- examples/moving_average.cpp | 6 ++- examples/statistics.cpp | 97 +++++++++++++++++++++++++++++++++++++ test/Jamfile | 1 + 3 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 examples/statistics.cpp diff --git a/examples/moving_average.cpp b/examples/moving_average.cpp index 6561514b..4e9a6d97 100644 --- a/examples/moving_average.cpp +++ b/examples/moving_average.cpp @@ -63,7 +63,8 @@ int main() std::getline(file, line); // Read data - while (std::getline(file, line)) { + while (std::getline(file, line)) + { stock_data.push_back(parse_csv_line(line)); } @@ -76,7 +77,8 @@ int main() decimal64 sum(0); // Calculate sum for the window - for (size_t j = 0; j < window_size; ++j) { + for (size_t j = 0; j < window_size; ++j) + { sum += stock_data[i - j].close; } diff --git a/examples/statistics.cpp b/examples/statistics.cpp new file mode 100644 index 00000000..252861a1 --- /dev/null +++ b/examples/statistics.cpp @@ -0,0 +1,97 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include "where_file.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::decimal; + +struct daily_data +{ + std::string date; + decimal64 open; + decimal64 high; + decimal64 low; + decimal64 close; + decimal64 volume; +}; + +// Function to split a CSV line into daily_data +auto parse_csv_line(const std::string& line) -> daily_data +{ + std::stringstream ss(line); + std::string token; + daily_data data; + + // Parse each column + std::getline(ss, data.date, ','); + std::getline(ss, token, ','); + from_chars(token.c_str(), token.c_str() + token.size(), data.open); + + std::getline(ss, token, ','); + from_chars(token.c_str(), token.c_str() + token.size(), data.high); + + std::getline(ss, token, ','); + from_chars(token.c_str(), token.c_str() + token.size(), data.low); + + std::getline(ss, token, ','); + from_chars(token.c_str(), token.c_str() + token.size(), data.close); + + std::getline(ss, token, ','); + from_chars(token.c_str(), token.c_str() + token.size(), data.volume); + + return data; +} + +int main() +{ + std::vector stock_data; + + // Open and read the CSV file + std::ifstream file(where_file("AAPL.csv")); + std::string line; + + // Skip header line + std::getline(file, line); + + // Read data + while (std::getline(file, line)) + { + stock_data.push_back(parse_csv_line(line)); + } + + // Get the closing prices for the entire year + std::vector closing_prices; + for (const auto& day : stock_data) + { + closing_prices.emplace_back(day.close); + } + + const auto mean_closing_price = boost::math::statistics::mean(closing_prices); + const auto median_closing_price = boost::math::statistics::median(closing_prices); + const auto variance_closing_price = boost::math::statistics::variance(closing_prices); + const auto std_dev_closing_price = sqrt(variance_closing_price); + + // 2-Sigma Bollinger Bands + const auto upper_band = mean_closing_price + 2 * std_dev_closing_price; + const auto lower_band = mean_closing_price - 2 * std_dev_closing_price; + + std::cout << std::fixed << std::setprecision(2) + << " Mean Closing Price: " << mean_closing_price << '\n' + << " Standard Deviation: " << std_dev_closing_price << '\n' + << "Upper Bollinger Band: " << upper_band << '\n' + << "Lower Bollinger Band: " << lower_band << std::endl; + + // Mean = 207.21 + // Median = 214.27 + return mean_closing_price > median_closing_price; +} + diff --git a/test/Jamfile b/test/Jamfile index bddeec3c..c7b1bd08 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -152,3 +152,4 @@ run ../examples/literals.cpp ; run ../examples/rounding_mode.cpp ; run ../examples/moving_average.cpp ; run ../examples/currency_conversion.cpp ; +run ../examples/statistics.cpp ; From 0b2d4257ebf16b70c4ebfb59b859c316b2dc6413 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 13:37:23 -0500 Subject: [PATCH 084/140] Add to docs --- doc/decimal/examples.adoc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/decimal/examples.adoc b/doc/decimal/examples.adoc index 6c8b9b4d..a224018b 100644 --- a/doc/decimal/examples.adoc +++ b/doc/decimal/examples.adoc @@ -228,3 +228,11 @@ This serves as a framework for other calculations for securities. === Currency Conversion In the examples folder there is a file named `currency_conversion.cpp`. This example shows how to simply convert currencies based off a given exchange rate. + +== Boost.Math Integration + +=== Bollinger Bands + +In the examples folder there is a file named `statistics.cpp`. +This example demonstrates how to parse a file, and then leverage Boost.Math to compute statistics of that data set culminating with the values of the Bollinger Bands. +This example could be extended with the simple moving average to create full bands based on the period of the moving average you would like. From b3fcd920dfb9d653a09280a98ba65a95d345a075 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 13:58:01 -0500 Subject: [PATCH 085/140] Ignore warnings from math --- examples/statistics.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/examples/statistics.cpp b/examples/statistics.cpp index 252861a1..d3ed8572 100644 --- a/examples/statistics.cpp +++ b/examples/statistics.cpp @@ -4,7 +4,6 @@ #include "where_file.hpp" #include -#include #include #include #include @@ -12,6 +11,23 @@ #include #include +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wfloat-equal" +# pragma clang diagnostic ignored "-Wsign-conversion" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +#include + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + using namespace boost::decimal; struct daily_data From 7ddf1371f87c1e8b8f54d9dbdffbfa8a8fc89274 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 13:59:40 -0500 Subject: [PATCH 086/140] Re-activate MSVC 14.3 and Clang-CL testing --- .github/workflows/ci.yml | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a079dac6..c31348ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -467,28 +467,26 @@ jobs: cxxstd: "14,17,20,latest" addrmd: "32" os: windows-2019 - # B2 does not work with MSVC 17.10. Once it's updated we can re-enable these tests - # Still covered in drone - #- toolset: msvc-14.3 - # cxxstd: "14,17,20,latest" - # addrmd: "32" - # os: windows-2022 + - toolset: msvc-14.3 + cxxstd: "14,17,20,latest" + addrmd: "32" + os: windows-2022 - toolset: msvc-14.2 cxxstd: "14,17,20,latest" addrmd: "64" os: windows-2019 - #- toolset: msvc-14.3 - # cxxstd: "14,17,20,latest" - # addrmd: "64" - # os: windows-2022 - #- toolset: clang-win - # cxxstd: "14,17,latest" - # addrmd: "32" - # os: windows-2022 - #- toolset: clang-win - # cxxstd: "14,17,latest" - # addrmd: "64" - # os: windows-2022 + - toolset: msvc-14.3 + cxxstd: "14,17,20,latest" + addrmd: "64" + os: windows-2022 + - toolset: clang-win + cxxstd: "14,17,latest" + addrmd: "32" + os: windows-2022 + - toolset: clang-win + cxxstd: "14,17,latest" + addrmd: "64" + os: windows-2022 - toolset: gcc cxxstd: "03,11,14,17,2a" addrmd: "64" From d800d97e7452ffc374b34b622d7517e05508b83d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 14:15:17 -0500 Subject: [PATCH 087/140] Add additional intel language standards --- .github/workflows/ci.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c31348ff..75972227 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -743,7 +743,7 @@ jobs: fail-fast: false matrix: compiler: [ intel ] - standard: [ c++20 ] + standard: [ 14, 17, 20, 23 ] steps: - uses: actions/checkout@v4 with: @@ -791,7 +791,12 @@ jobs: run: | cd ../boost-root mkdir __build__ && cd __build__ - cmake -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON .. + cmake -DCMAKE_C_COMPILER=icx \ + -DCMAKE_CXX_COMPILER=icpx \ + -DCMAKE_CXX_STANDARD=${{ matrix.standard }} \ + -DCMAKE_CXX_STANDARD_REQUIRED=ON \ + -DBOOST_INCLUDE_LIBRARIES=$LIBRARY \ + -DBUILD_TESTING=ON .. - name: Build tests run: | From 699539c9ea52c8512bfdf09a8f11f3cb92fb40eb Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 14:21:19 -0500 Subject: [PATCH 088/140] Ignore random continue line --- test/random_decimal128_math.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/random_decimal128_math.cpp b/test/random_decimal128_math.cpp index 29d45976..ba53beaa 100644 --- a/test/random_decimal128_math.cpp +++ b/test/random_decimal128_math.cpp @@ -252,7 +252,7 @@ void random_multiplication(T lower, T upper) if (val1 * val2 == 0) { // Integers don't have signed 0 but decimal does - continue; + continue; // LCOV_EXCL_LINE } if (!BOOST_TEST_EQ(res_int, val1 * val2)) From 583c9d930ae84c3ccb3afcfd4d8781eb863894cd Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 14:22:02 -0500 Subject: [PATCH 089/140] Exclude weird missing bracket in test --- test/compare_dec128_and_fast.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/compare_dec128_and_fast.cpp b/test/compare_dec128_and_fast.cpp index d07d1b06..cda559ad 100644 --- a/test/compare_dec128_and_fast.cpp +++ b/test/compare_dec128_and_fast.cpp @@ -74,7 +74,7 @@ void test_add() std::cerr << strm.str() << std::endl; // LCOV_EXCL_STOP - } + } // LCOV_EXCL_LINE } std::uniform_real_distribution small_vals(0.0, 1.0); @@ -109,7 +109,7 @@ void test_add() std::cerr << strm.str() << std::endl; // LCOV_EXCL_STOP - } + } // LCOV_EXCL_LINE } } @@ -147,7 +147,7 @@ void test_sub() std::cerr << strm.str() << std::endl; // LCOV_EXCL_STOP - } + } // LCOV_EXCL_LINE } std::uniform_real_distribution small_vals(0.0, 1.0); @@ -182,7 +182,7 @@ void test_sub() std::cerr << strm.str() << std::endl; // LCOV_EXCL_STOP - } + } // LCOV_EXCL_LINE } } From 0e0a7d9e465694b2ed3ab360e976e021e6f2d1f2 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 14:29:52 -0500 Subject: [PATCH 090/140] Force run-time evaluation --- test/test_to_chars.cpp | 80 ++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/test/test_to_chars.cpp b/test/test_to_chars.cpp index c9b2ee4e..a66f102e 100644 --- a/test/test_to_chars.cpp +++ b/test/test_to_chars.cpp @@ -468,52 +468,54 @@ void test_buffer_overflow() template void zero_test() { + std::uniform_real_distribution dist; + constexpr T val {0, 0}; // General should always be the same for (int precision = 0; precision < 50; ++precision) { - test_value(val, "0.0e+00", chars_format::general, precision); + test_value(val * T{dist(rng)}, "0.0e+00", chars_format::general, precision); } - test_value(val, "0e+00", chars_format::scientific, 0); - test_value(val, "0.0e+00", chars_format::scientific, 1); - test_value(val, "0.00e+00", chars_format::scientific, 2); - test_value(val, "0.000e+00", chars_format::scientific, 3); - test_value(val, "0.0000e+00", chars_format::scientific, 4); - test_value(val, "0.00000e+00", chars_format::scientific, 5); - test_value(val, "0.000000e+00", chars_format::scientific, 6); - test_value(val, "0.0000000e+00", chars_format::scientific, 7); - test_value(val, "0.00000000e+00", chars_format::scientific, 8); - test_value(val, "0.000000000e+00", chars_format::scientific, 9); - test_value(val, "0.0000000000e+00", chars_format::scientific, 10); - test_value(val, "0.00000000000000000000000000000000000000000000000000e+00", chars_format::scientific, 50); - - test_value(val, "0p+00", chars_format::hex, 0); - test_value(val, "0.0p+00", chars_format::hex, 1); - test_value(val, "0.00p+00", chars_format::hex, 2); - test_value(val, "0.000p+00", chars_format::hex, 3); - test_value(val, "0.0000p+00", chars_format::hex, 4); - test_value(val, "0.00000p+00", chars_format::hex, 5); - test_value(val, "0.000000p+00", chars_format::hex, 6); - test_value(val, "0.0000000p+00", chars_format::hex, 7); - test_value(val, "0.00000000p+00", chars_format::hex, 8); - test_value(val, "0.000000000p+00", chars_format::hex, 9); - test_value(val, "0.0000000000p+00", chars_format::hex, 10); - test_value(val, "0.00000000000000000000000000000000000000000000000000p+00", chars_format::hex, 50); - - test_value(val, "0", chars_format::fixed, 0); - test_value(val, "0.0", chars_format::fixed, 1); - test_value(val, "0.00", chars_format::fixed, 2); - test_value(val, "0.000", chars_format::fixed, 3); - test_value(val, "0.0000", chars_format::fixed, 4); - test_value(val, "0.00000", chars_format::fixed, 5); - test_value(val, "0.000000", chars_format::fixed, 6); - test_value(val, "0.0000000", chars_format::fixed, 7); - test_value(val, "0.00000000", chars_format::fixed, 8); - test_value(val, "0.000000000", chars_format::fixed, 9); - test_value(val, "0.0000000000", chars_format::fixed, 10); - test_value(val, "0.00000000000000000000000000000000000000000000000000", chars_format::fixed, 50); + test_value(val * T{dist(rng)}, "0e+00", chars_format::scientific, 0); + test_value(val * T{dist(rng)}, "0.0e+00", chars_format::scientific, 1); + test_value(val * T{dist(rng)}, "0.00e+00", chars_format::scientific, 2); + test_value(val * T{dist(rng)}, "0.000e+00", chars_format::scientific, 3); + test_value(val * T{dist(rng)}, "0.0000e+00", chars_format::scientific, 4); + test_value(val * T{dist(rng)}, "0.00000e+00", chars_format::scientific, 5); + test_value(val * T{dist(rng)}, "0.000000e+00", chars_format::scientific, 6); + test_value(val * T{dist(rng)}, "0.0000000e+00", chars_format::scientific, 7); + test_value(val * T{dist(rng)}, "0.00000000e+00", chars_format::scientific, 8); + test_value(val * T{dist(rng)}, "0.000000000e+00", chars_format::scientific, 9); + test_value(val * T{dist(rng)}, "0.0000000000e+00", chars_format::scientific, 10); + test_value(val * T{dist(rng)}, "0.00000000000000000000000000000000000000000000000000e+00", chars_format::scientific, 50); + + test_value(val * T{dist(rng)}, "0p+00", chars_format::hex, 0); + test_value(val * T{dist(rng)}, "0.0p+00", chars_format::hex, 1); + test_value(val * T{dist(rng)}, "0.00p+00", chars_format::hex, 2); + test_value(val * T{dist(rng)}, "0.000p+00", chars_format::hex, 3); + test_value(val * T{dist(rng)}, "0.0000p+00", chars_format::hex, 4); + test_value(val * T{dist(rng)}, "0.00000p+00", chars_format::hex, 5); + test_value(val * T{dist(rng)}, "0.000000p+00", chars_format::hex, 6); + test_value(val * T{dist(rng)}, "0.0000000p+00", chars_format::hex, 7); + test_value(val * T{dist(rng)}, "0.00000000p+00", chars_format::hex, 8); + test_value(val * T{dist(rng)}, "0.000000000p+00", chars_format::hex, 9); + test_value(val * T{dist(rng)}, "0.0000000000p+00", chars_format::hex, 10); + test_value(val * T{dist(rng)}, "0.00000000000000000000000000000000000000000000000000p+00", chars_format::hex, 50); + + test_value(val * T{dist(rng)}, "0", chars_format::fixed, 0); + test_value(val * T{dist(rng)}, "0.0", chars_format::fixed, 1); + test_value(val * T{dist(rng)}, "0.00", chars_format::fixed, 2); + test_value(val * T{dist(rng)}, "0.000", chars_format::fixed, 3); + test_value(val * T{dist(rng)}, "0.0000", chars_format::fixed, 4); + test_value(val * T{dist(rng)}, "0.00000", chars_format::fixed, 5); + test_value(val * T{dist(rng)}, "0.000000", chars_format::fixed, 6); + test_value(val * T{dist(rng)}, "0.0000000", chars_format::fixed, 7); + test_value(val * T{dist(rng)}, "0.00000000", chars_format::fixed, 8); + test_value(val * T{dist(rng)}, "0.000000000", chars_format::fixed, 9); + test_value(val * T{dist(rng)}, "0.0000000000", chars_format::fixed, 10); + test_value(val * T{dist(rng)}, "0.00000000000000000000000000000000000000000000000000", chars_format::fixed, 50); } // See: https://github.com/cppalliance/decimal/issues/434 From dfa63469da2500ef01f6624ba2fa699352e1eb8b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 14:31:34 -0500 Subject: [PATCH 091/140] Exclude unlikely path line --- include/boost/decimal/detail/io.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/detail/io.hpp b/include/boost/decimal/detail/io.hpp index e1e4ab9b..1689ade9 100644 --- a/include/boost/decimal/detail/io.hpp +++ b/include/boost/decimal/detail/io.hpp @@ -127,7 +127,7 @@ auto operator<<(std::basic_ostream& os, const DecimalType& d) if (BOOST_DECIMAL_UNLIKELY(!r)) { - errno = static_cast(r.ec); + errno = static_cast(r.ec); // LCOV_EXCL_LINE } *r.ptr = '\0'; From 7953d5b6e558a7691100078f8cc2a946afd96d82 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 14:37:45 -0500 Subject: [PATCH 092/140] Ignore additional GCC warnings --- examples/statistics.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/statistics.cpp b/examples/statistics.cpp index d3ed8572..af17dc69 100644 --- a/examples/statistics.cpp +++ b/examples/statistics.cpp @@ -17,6 +17,7 @@ # pragma clang diagnostic ignored "-Wsign-conversion" #elif defined(__GNUC__) # pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wfloat-equal" # pragma GCC diagnostic ignored "-Wsign-conversion" #endif From fd1f881cb86f1957444f4bc50d57d1f05028ce01 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 14:38:41 -0500 Subject: [PATCH 093/140] Use from_chars string inteface --- examples/statistics.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/statistics.cpp b/examples/statistics.cpp index af17dc69..2239cb29 100644 --- a/examples/statistics.cpp +++ b/examples/statistics.cpp @@ -51,19 +51,19 @@ auto parse_csv_line(const std::string& line) -> daily_data // Parse each column std::getline(ss, data.date, ','); std::getline(ss, token, ','); - from_chars(token.c_str(), token.c_str() + token.size(), data.open); + from_chars(token, data.open); std::getline(ss, token, ','); - from_chars(token.c_str(), token.c_str() + token.size(), data.high); + from_chars(token, data.high); std::getline(ss, token, ','); - from_chars(token.c_str(), token.c_str() + token.size(), data.low); + from_chars(token, data.low); std::getline(ss, token, ','); - from_chars(token.c_str(), token.c_str() + token.size(), data.close); + from_chars(token, data.close); std::getline(ss, token, ','); - from_chars(token.c_str(), token.c_str() + token.size(), data.volume); + from_chars(token, data.volume); return data; } From 906a4f4175849c7d9e7b69543af3f200622d3ac9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 16:56:24 -0500 Subject: [PATCH 094/140] Add test cases for 777 --- test/test_to_chars.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/test_to_chars.cpp b/test/test_to_chars.cpp index c9b2ee4e..88594ccf 100644 --- a/test/test_to_chars.cpp +++ b/test/test_to_chars.cpp @@ -750,6 +750,18 @@ void test_434_hex() test_value(test_one_and_quarter, "7.d0000000000000000000000000000000000000000000000000p-01", chars_format::hex, 50); } +template +void test_777() +{ + constexpr T value1 = T {21, 6, true}; + constexpr T value2 = T {211, 6, true}; + constexpr T value3 = T {2111, 6, true}; + + test_value(value1, "-21000000", chars_format::fixed, 0); + test_value(value2, "-211000000", chars_format::fixed, 0); + test_value(value3, "-2111000000", chars_format::fixed, 0); +} + int main() { test_non_finite_values(); @@ -853,6 +865,13 @@ int main() test_general_format_std(); #endif + test_777(); + test_777(); + test_777(); + test_777(); + test_777(); + test_777(); + return boost::report_errors(); } From a22e092755b606644fd2d849aea21c81ef8b2ec0 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 16:59:44 -0500 Subject: [PATCH 095/140] Remove decimal point if no trailing values --- include/boost/decimal/charconv.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/charconv.hpp b/include/boost/decimal/charconv.hpp index 5fe93836..63790110 100644 --- a/include/boost/decimal/charconv.hpp +++ b/include/boost/decimal/charconv.hpp @@ -602,7 +602,7 @@ BOOST_DECIMAL_CONSTEXPR auto to_chars_fixed_impl(char* first, char* last, const } // Bounds check again - if (precision == 0) + if (precision == 0 && !append_trailing_zeros && !append_leading_zeros) { return {r.ptr, std::errc()}; } @@ -691,6 +691,11 @@ BOOST_DECIMAL_CONSTEXPR auto to_chars_fixed_impl(char* first, char* last, const boost::decimal::detail::memset(r.ptr, '0', zeros_inserted); r.ptr += zeros_inserted; + + if (*(r.ptr - 1) == '.') + { + --r.ptr; + } } return {r.ptr, std::errc()}; From 8fe3c09097f0f8455063cf4f3a78d14fe4c69d55 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 17:19:04 -0500 Subject: [PATCH 096/140] Make sure to pass template argument to fenv_round --- include/boost/decimal/charconv.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/charconv.hpp b/include/boost/decimal/charconv.hpp index 63790110..cc17272c 100644 --- a/include/boost/decimal/charconv.hpp +++ b/include/boost/decimal/charconv.hpp @@ -535,7 +535,7 @@ BOOST_DECIMAL_CONSTEXPR auto to_chars_fixed_impl(char* first, char* last, const if (num_dig == precision + 1) { --num_dig; - exponent += fenv_round(significand); + exponent += fenv_round(significand); } } else if (num_dig < precision && fmt != chars_format::general) From f6c18539e447af3a9996a4c15f4ec5b92acb9017 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 13 Dec 2023 10:47:13 +0100 Subject: [PATCH 097/140] Add format specialization for all types --- include/boost/decimal/format.hpp | 133 +++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 include/boost/decimal/format.hpp diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp new file mode 100644 index 00000000..4e8ed3a6 --- /dev/null +++ b/include/boost/decimal/format.hpp @@ -0,0 +1,133 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_FORMAT_HPP +#define BOOST_DECIMAL_FORMAT_HPP + +#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) && __has_include() && !defined(BOOST_DECIMAL_DISABLE_CLIB) + +#include +#include +#include +#include +#include +#include +#include +#include + +// See for general impl +// https://en.cppreference.com/w/cpp/utility/format/formatter + +namespace boost::decimal::detail { + +template +constexpr auto parse_impl(ParseContext& ctx) +{ + auto it {ctx.begin()}; + int precision = 5; + + if (it == ctx.end()) + { + return std::make_tuple(precision, it); + } + + if (*it == '.') + { + ++it; + precision = 0; + while (*it >= '0' && *it <= '9') + { + precision = precision * 10 + *it; + ++it; + } + + if (*it != 'f') + { + throw std::format_error("Invalid format"); + } + ++it; + } + + if (*it != '}') + { + throw std::format_error("Invalid format"); + } + + return std::make_tuple(precision, it); +}; +}; + +template <> +struct std::formatter +{ + int precision {}; + + template + constexpr auto parse(ParseContext& ctx) + { + auto res {boost::decimal::detail::parse_impl(ctx)}; + precision = std::get<0>(res); + return std::get<1>(res); + } + + template + auto format(const boost::decimal::decimal32& v, FormatContext& ctx) + { + std::ostringstream out; + out << std::setprecision(precision) << v; + + return std::ranges::copy(std::move(out).str(), ctx.out()).out; + } +}; + +template <> +struct std::formatter +{ + int precision; + + template + constexpr auto parse(ParseContext& ctx) + { + auto res {boost::decimal::detail::parse_impl(ctx)}; + precision = std::get<0>(res); + return std::get<1>(res); + } + + template + auto format(const boost::decimal::decimal32& v, FormatContext& ctx) + { + std::ostringstream out; + out << std::setprecision(precision) << v; + + return std::ranges::copy(std::move(out).str(), ctx.out()).out; + } +}; + +template <> +struct std::formatter +{ + int precision; + + template + constexpr auto parse(ParseContext& ctx) + { + auto res {boost::decimal::detail::parse_impl(ctx)}; + precision = std::get<0>(res); + return std::get<1>(res); + } + + template + auto format(const boost::decimal::decimal32& v, FormatContext& ctx) + { + std::ostringstream out; + out << std::setprecision(precision) << v; + + return std::ranges::copy(std::move(out).str(), ctx.out()).out; + } +}; + + +#endif + +#endif //BOOST_DECIMAL_FORMAT_HPP From da20e86bc07abc110253ee73815bac24813d5c3a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 13 Dec 2023 10:47:22 +0100 Subject: [PATCH 098/140] Add test set --- include/boost/decimal.hpp | 1 + test/Jamfile | 1 + test/test_format.cpp | 59 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 test/test_format.cpp diff --git a/include/boost/decimal.hpp b/include/boost/decimal.hpp index b878eb03..6152402a 100644 --- a/include/boost/decimal.hpp +++ b/include/boost/decimal.hpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/test/Jamfile b/test/Jamfile index c7b1bd08..f25a2452 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -111,6 +111,7 @@ run test_fast_math.cpp ; run test_fenv.cpp ; run test_fixed_width_trunc.cpp ; run test_float_conversion.cpp ; +run test_format.cpp ; run-fail test_fprintf.cpp ; run test_frexp_ldexp.cpp ; run test_from_chars.cpp /boost/charconv//boost_charconv ; diff --git a/test/test_format.cpp b/test/test_format.cpp new file mode 100644 index 00000000..ef496a66 --- /dev/null +++ b/test/test_format.cpp @@ -0,0 +1,59 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +using namespace boost::decimal; + +#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) && __has_include() && !defined(BOOST_DECIMAL_DISABLE_CLIB) + +#include + +template +void test() +{ +/* + BOOST_TEST_EQ(std::format("{}", T{1}), "1"); + BOOST_TEST_EQ(std::format("{}", T{10}), "1e+01"); + BOOST_TEST_EQ(std::format("{}", T{100}), "1e+02"); + BOOST_TEST_EQ(std::format("{}", T{1000}), "1e+03"); + BOOST_TEST_EQ(std::format("{}", T{10000}), "1e+04"); + BOOST_TEST_EQ(std::format("{}", T{210000}), "2.1e+05"); + BOOST_TEST_EQ(std::format("{}", T{2100000}), "2.1e+06"); + BOOST_TEST_EQ(std::format("{}", T{21, 6, true}), "-2.1e+07"); + BOOST_TEST_EQ(std::format("{}", T{211, 6, true}), "-2.11e+08"); + BOOST_TEST_EQ(std::format("{}", T{2111, 6, true}), "-2.111e+09"); + + BOOST_TEST_EQ(std::format("{}", std::numeric_limits::infinity()), "inf"); + BOOST_TEST_EQ(std::format("{}", -std::numeric_limits::infinity()), "-inf"); + BOOST_TEST_EQ(std::format("{}", std::numeric_limits::quiet_NaN()), "nan"); + BOOST_TEST_EQ(std::format("{}", -std::numeric_limits::quiet_NaN()), "-nan(ind)"); + BOOST_TEST_EQ(std::format("{}", std::numeric_limits::signaling_NaN()), "nan(snan)"); + BOOST_TEST_EQ(std::format("{}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); + */ + + constexpr const char* fmt_string = "{}"; + + BOOST_TEST_EQ(std::format(fmt_string, 1.0), "1"); + BOOST_TEST_EQ(std::format(fmt_string, T{1}), "1"); +} + +int main() +{ + test(); + //test(); + //test(); + + return boost::report_errors(); +} + +#else + +int main() +{ + return 0; +} + +#endif From 3ffbdf25df1f873684d6b5c475d3fde4c079f878 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 15 Mar 2024 11:12:50 +0100 Subject: [PATCH 099/140] Get trivial example working on GCC-13 --- include/boost/decimal/format.hpp | 89 ++++++++++---------------------- test/test_format.cpp | 5 +- 2 files changed, 27 insertions(+), 67 deletions(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 4e8ed3a6..d10c0d96 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -1,4 +1,4 @@ -// Copyright 2023 Matt Borland +// Copyright 2023 - 2024 Matt Borland // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -10,14 +10,20 @@ #include #include #include +#include +#include #include #include #include #include #include -// See for general impl -// https://en.cppreference.com/w/cpp/utility/format/formatter +// Default :g +// Fixed :f +// Scientific :3 +// Hex :a +// +// Capital letter for any of the above leads to all characters being uppercase namespace boost::decimal::detail { @@ -25,11 +31,12 @@ template constexpr auto parse_impl(ParseContext& ctx) { auto it {ctx.begin()}; - int precision = 5; + int precision = 6; + boost::decimal::chars_format fmt = boost::decimal::chars_format::general; if (it == ctx.end()) { - return std::make_tuple(precision, it); + return std::make_tuple(precision, fmt, it); } if (*it == '.') @@ -54,80 +61,36 @@ constexpr auto parse_impl(ParseContext& ctx) throw std::format_error("Invalid format"); } - return std::make_tuple(precision, it); + return std::make_tuple(precision, fmt, it); }; }; template <> struct std::formatter -{ - int precision {}; - - template - constexpr auto parse(ParseContext& ctx) - { - auto res {boost::decimal::detail::parse_impl(ctx)}; - precision = std::get<0>(res); - return std::get<1>(res); - } - - template - auto format(const boost::decimal::decimal32& v, FormatContext& ctx) - { - std::ostringstream out; - out << std::setprecision(precision) << v; - - return std::ranges::copy(std::move(out).str(), ctx.out()).out; - } -}; - -template <> -struct std::formatter { int precision; + boost::decimal::chars_format fmt; - template - constexpr auto parse(ParseContext& ctx) + constexpr auto parse(const std::basic_format_parse_context& context) { - auto res {boost::decimal::detail::parse_impl(ctx)}; + auto res {boost::decimal::detail::parse_impl(context)}; precision = std::get<0>(res); - return std::get<1>(res); + fmt = std::get<1>(res); + return std::get<2>(res); } - template - auto format(const boost::decimal::decimal32& v, FormatContext& ctx) + template + auto format(const boost::decimal::decimal32& v, std::basic_format_context& context) const { - std::ostringstream out; - out << std::setprecision(precision) << v; - - return std::ranges::copy(std::move(out).str(), ctx.out()).out; + auto&& out = context.out(); + char buffer[128U]; + const auto r = to_chars(buffer, buffer + sizeof(buffer), v, fmt, precision); + *r.ptr = '\0'; + out = std::copy(buffer, r.ptr, out); + return out; } }; -template <> -struct std::formatter -{ - int precision; - - template - constexpr auto parse(ParseContext& ctx) - { - auto res {boost::decimal::detail::parse_impl(ctx)}; - precision = std::get<0>(res); - return std::get<1>(res); - } - - template - auto format(const boost::decimal::decimal32& v, FormatContext& ctx) - { - std::ostringstream out; - out << std::setprecision(precision) << v; - - return std::ranges::copy(std::move(out).str(), ctx.out()).out; - } -}; - - #endif #endif //BOOST_DECIMAL_FORMAT_HPP diff --git a/test/test_format.cpp b/test/test_format.cpp index ef496a66..f793f529 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -34,10 +34,7 @@ void test() BOOST_TEST_EQ(std::format("{}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); */ - constexpr const char* fmt_string = "{}"; - - BOOST_TEST_EQ(std::format(fmt_string, 1.0), "1"); - BOOST_TEST_EQ(std::format(fmt_string, T{1}), "1"); + BOOST_TEST_EQ(std::format("{}", T{1}), "1"); } int main() From 09c230b0378f0796510db0ba67aa0573af2330ce Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 15 Mar 2024 11:41:22 +0100 Subject: [PATCH 100/140] Fix macro logic --- include/boost/decimal/format.hpp | 2 +- test/test_format.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index d10c0d96..500c5c38 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -5,7 +5,7 @@ #ifndef BOOST_DECIMAL_FORMAT_HPP #define BOOST_DECIMAL_FORMAT_HPP -#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) && __has_include() && !defined(BOOST_DECIMAL_DISABLE_CLIB) +#if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && __has_include() && !defined(BOOST_DECIMAL_DISABLE_CLIB) #include #include diff --git a/test/test_format.cpp b/test/test_format.cpp index f793f529..b2b6c963 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -7,7 +7,7 @@ using namespace boost::decimal; -#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) && __has_include() && !defined(BOOST_DECIMAL_DISABLE_CLIB) +#if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && __has_include() && !defined(BOOST_DECIMAL_DISABLE_CLIB) #include From 60ab8c32479d34490448fc0179a383c881c0da5f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 15 Mar 2024 12:07:34 +0100 Subject: [PATCH 101/140] Add significantly more support to parser --- include/boost/decimal/format.hpp | 78 ++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 500c5c38..4879fb5f 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -17,6 +17,7 @@ #include #include #include +#include // Default :g // Fixed :f @@ -31,12 +32,26 @@ template constexpr auto parse_impl(ParseContext& ctx) { auto it {ctx.begin()}; + ++it; int precision = 6; boost::decimal::chars_format fmt = boost::decimal::chars_format::general; + bool is_upper = false; + int padding_digits = 0; if (it == ctx.end()) { - return std::make_tuple(precision, fmt, it); + return std::make_tuple(precision, fmt, is_upper, padding_digits, it); + } + + while (*it >= '0' && *it <= '9') + { + padding_digits = padding_digits * 10 + *it; + ++it; + } + + if (*it == ':') + { + ++it; } if (*it == '.') @@ -49,9 +64,37 @@ constexpr auto parse_impl(ParseContext& ctx) ++it; } - if (*it != 'f') + switch (*it) { - throw std::format_error("Invalid format"); + case 'G': + is_upper = true; + [[fallthrough]]; + case 'g': + fmt = chars_format::general; + break; + + case 'F': + [[fallthrough]]; + case 'f': + fmt = chars_format::fixed; + break; + + case 'E': + is_upper = true; + [[fallthrough]]; + case 'e': + fmt = chars_format::scientific; + break; + + case 'A': + is_upper = true; + [[fallthrough]]; + case 'a': + fmt = chars_format::hex; + break; + + default: + throw std::format_error("Invalid format"); } ++it; } @@ -61,22 +104,29 @@ constexpr auto parse_impl(ParseContext& ctx) throw std::format_error("Invalid format"); } - return std::make_tuple(precision, fmt, it); -}; + return std::make_tuple(precision, fmt, is_upper, padding_digits, it); }; +} //namespace boost::decimal::detail + template <> struct std::formatter { int precision; boost::decimal::chars_format fmt; + bool is_upper; + int padding_digits; constexpr auto parse(const std::basic_format_parse_context& context) { - auto res {boost::decimal::detail::parse_impl(context)}; + const auto res {boost::decimal::detail::parse_impl(context)}; + precision = std::get<0>(res); fmt = std::get<1>(res); - return std::get<2>(res); + is_upper = std::get<2>(res); + padding_digits = std::get<3>(res); + + return std::get<4>(res); } template @@ -86,7 +136,19 @@ struct std::formatter char buffer[128U]; const auto r = to_chars(buffer, buffer + sizeof(buffer), v, fmt, precision); *r.ptr = '\0'; - out = std::copy(buffer, r.ptr, out); + std::string s(buffer); + + if (is_upper) + { + std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::toupper(c); }); + } + + if (s.size() < static_cast(padding_digits)) + { + s.insert(s.begin(), static_cast(padding_digits) - s.size(), '0'); + } + + out = std::copy(s.begin(), s.end(), out); return out; } }; From 75af309a6575f95335d72ca797ab1d79e765384a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 15 Mar 2024 12:08:16 +0100 Subject: [PATCH 102/140] Fix up tests --- test/test_format.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/test/test_format.cpp b/test/test_format.cpp index b2b6c963..77ab9238 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -12,16 +12,15 @@ using namespace boost::decimal; #include template -void test() +void test_general() { -/* BOOST_TEST_EQ(std::format("{}", T{1}), "1"); - BOOST_TEST_EQ(std::format("{}", T{10}), "1e+01"); - BOOST_TEST_EQ(std::format("{}", T{100}), "1e+02"); - BOOST_TEST_EQ(std::format("{}", T{1000}), "1e+03"); - BOOST_TEST_EQ(std::format("{}", T{10000}), "1e+04"); - BOOST_TEST_EQ(std::format("{}", T{210000}), "2.1e+05"); - BOOST_TEST_EQ(std::format("{}", T{2100000}), "2.1e+06"); + BOOST_TEST_EQ(std::format("{}", T{10}), "10"); + BOOST_TEST_EQ(std::format("{}", T{100}), "100"); + BOOST_TEST_EQ(std::format("{}", T{1000}), "1000"); + BOOST_TEST_EQ(std::format("{}", T{10000}), "10000"); + BOOST_TEST_EQ(std::format("{}", T{210000}), "210000"); + BOOST_TEST_EQ(std::format("{}", T{2100000}), "2100000"); BOOST_TEST_EQ(std::format("{}", T{21, 6, true}), "-2.1e+07"); BOOST_TEST_EQ(std::format("{}", T{211, 6, true}), "-2.11e+08"); BOOST_TEST_EQ(std::format("{}", T{2111, 6, true}), "-2.111e+09"); @@ -32,14 +31,12 @@ void test() BOOST_TEST_EQ(std::format("{}", -std::numeric_limits::quiet_NaN()), "-nan(ind)"); BOOST_TEST_EQ(std::format("{}", std::numeric_limits::signaling_NaN()), "nan(snan)"); BOOST_TEST_EQ(std::format("{}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); - */ - - BOOST_TEST_EQ(std::format("{}", T{1}), "1"); } int main() { - test(); + test_general(); + //test(); //test(); From 6353000d17d5daf7e1067a644ef58834c38c8ea2 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 15 Mar 2024 12:12:56 +0100 Subject: [PATCH 103/140] Add general format specifier to tests --- test/test_format.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test_format.cpp b/test/test_format.cpp index 77ab9238..5ced6450 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -31,6 +31,24 @@ void test_general() BOOST_TEST_EQ(std::format("{}", -std::numeric_limits::quiet_NaN()), "-nan(ind)"); BOOST_TEST_EQ(std::format("{}", std::numeric_limits::signaling_NaN()), "nan(snan)"); BOOST_TEST_EQ(std::format("{}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); + + BOOST_TEST_EQ(std::format("{:g}", T{1}), "1"); + BOOST_TEST_EQ(std::format("{:g}", T{10}), "10"); + BOOST_TEST_EQ(std::format("{:g}", T{100}), "100"); + BOOST_TEST_EQ(std::format("{:g}", T{1000}), "1000"); + BOOST_TEST_EQ(std::format("{:g}", T{10000}), "10000"); + BOOST_TEST_EQ(std::format("{:g}", T{210000}), "210000"); + BOOST_TEST_EQ(std::format("{:g}", T{2100000}), "2100000"); + BOOST_TEST_EQ(std::format("{:g}", T{21, 6, true}), "-2.1e+07"); + BOOST_TEST_EQ(std::format("{:g}", T{211, 6, true}), "-2.11e+08"); + BOOST_TEST_EQ(std::format("{:g}", T{2111, 6, true}), "-2.111e+09"); + + BOOST_TEST_EQ(std::format("{:g}", std::numeric_limits::infinity()), "inf"); + BOOST_TEST_EQ(std::format("{:g}", -std::numeric_limits::infinity()), "-inf"); + BOOST_TEST_EQ(std::format("{:g}", std::numeric_limits::quiet_NaN()), "nan"); + BOOST_TEST_EQ(std::format("{:g}", -std::numeric_limits::quiet_NaN()), "-nan(ind)"); + BOOST_TEST_EQ(std::format("{:g}", std::numeric_limits::signaling_NaN()), "nan(snan)"); + BOOST_TEST_EQ(std::format("{:g}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); } int main() From b514162470c2d84e4509699cded234566e804ab1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 25 Mar 2024 08:51:15 +0100 Subject: [PATCH 104/140] Fix variable shadowing --- include/boost/decimal/format.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 4879fb5f..d2f446a4 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -33,14 +33,14 @@ constexpr auto parse_impl(ParseContext& ctx) { auto it {ctx.begin()}; ++it; - int precision = 6; + int ctx_precision = 6; boost::decimal::chars_format fmt = boost::decimal::chars_format::general; bool is_upper = false; int padding_digits = 0; if (it == ctx.end()) { - return std::make_tuple(precision, fmt, is_upper, padding_digits, it); + return std::make_tuple(ctx_precision, fmt, is_upper, padding_digits, it); } while (*it >= '0' && *it <= '9') @@ -57,10 +57,10 @@ constexpr auto parse_impl(ParseContext& ctx) if (*it == '.') { ++it; - precision = 0; + ctx_precision = 0; while (*it >= '0' && *it <= '9') { - precision = precision * 10 + *it; + ctx_precision = ctx_precision * 10 + *it; ++it; } @@ -104,7 +104,7 @@ constexpr auto parse_impl(ParseContext& ctx) throw std::format_error("Invalid format"); } - return std::make_tuple(precision, fmt, is_upper, padding_digits, it); + return std::make_tuple(ctx_precision, fmt, is_upper, padding_digits, it); }; } //namespace boost::decimal::detail @@ -112,7 +112,7 @@ constexpr auto parse_impl(ParseContext& ctx) template <> struct std::formatter { - int precision; + int ctx_precision; boost::decimal::chars_format fmt; bool is_upper; int padding_digits; @@ -121,7 +121,7 @@ struct std::formatter { const auto res {boost::decimal::detail::parse_impl(context)}; - precision = std::get<0>(res); + ctx_precision = std::get<0>(res); fmt = std::get<1>(res); is_upper = std::get<2>(res); padding_digits = std::get<3>(res); @@ -134,7 +134,7 @@ struct std::formatter { auto&& out = context.out(); char buffer[128U]; - const auto r = to_chars(buffer, buffer + sizeof(buffer), v, fmt, precision); + const auto r = to_chars(buffer, buffer + sizeof(buffer), v, fmt, ctx_precision); *r.ptr = '\0'; std::string s(buffer); From f68f331f863b6b6a321645503a08513fd80b6f3b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 25 Mar 2024 09:04:36 +0100 Subject: [PATCH 105/140] Fix availability guards --- include/boost/decimal/format.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index d2f446a4..a1ffcc62 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -5,7 +5,9 @@ #ifndef BOOST_DECIMAL_FORMAT_HPP #define BOOST_DECIMAL_FORMAT_HPP -#if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && __has_include() && !defined(BOOST_DECIMAL_DISABLE_CLIB) +// Many compilers seem to have with completly broken support so narrow down our support range +#if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && !defined(BOOST_DECIMAL_DISABLE_CLIB) && \ + ((defined(__GNUC__) && __GNUC__ >= 13) || (defined(__clang__) && __clang_major__ >= 17) || (defined(_MSC_VER) && _MSC_VER >= 1930)) #include #include From f2b58caed06f15fb3466a9b525a2d7209235a5a8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 14:56:44 -0500 Subject: [PATCH 106/140] Fixes and passing test with gcc-14 --- include/boost/decimal/format.hpp | 64 ++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index a1ffcc62..990c887b 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -31,7 +31,7 @@ namespace boost::decimal::detail { template -constexpr auto parse_impl(ParseContext& ctx) +constexpr auto parse_impl(ParseContext &ctx) { auto it {ctx.begin()}; ++it; @@ -45,27 +45,32 @@ constexpr auto parse_impl(ParseContext& ctx) return std::make_tuple(ctx_precision, fmt, is_upper, padding_digits, it); } - while (*it >= '0' && *it <= '9') + while (it != ctx.end() && *it >= '0' && *it <= '9') { - padding_digits = padding_digits * 10 + *it; + padding_digits = padding_digits * 10 + (*it - '0'); ++it; } - if (*it == ':') + if (it != ctx.end() && *it == ':') { ++it; } - if (*it == '.') + if (it != ctx.end() && *it == '.') { ++it; ctx_precision = 0; - while (*it >= '0' && *it <= '9') + while (it != ctx.end() && *it >= '0' && *it <= '9') { - ctx_precision = ctx_precision * 10 + *it; + ctx_precision = ctx_precision * 10 + (*it - '0'); ++it; } + if (it == ctx.end()) + { + throw std::format_error("Unexpected end of format string"); + } + switch (*it) { case 'G': @@ -101,27 +106,34 @@ constexpr auto parse_impl(ParseContext& ctx) ++it; } - if (*it != '}') + if (it == ctx.end() || *it != '}') { throw std::format_error("Invalid format"); } return std::make_tuple(ctx_precision, fmt, is_upper, padding_digits, it); -}; +} + +} // Namespace boost::decimal::detail -} //namespace boost::decimal::detail +namespace std { template <> -struct std::formatter -{ +struct formatter { + constexpr formatter() : ctx_precision(6), + fmt(boost::decimal::chars_format::general), + is_upper(false), + padding_digits(0) + {} + int ctx_precision; boost::decimal::chars_format fmt; bool is_upper; int padding_digits; - constexpr auto parse(const std::basic_format_parse_context& context) + constexpr auto parse(format_parse_context &ctx) { - const auto res {boost::decimal::detail::parse_impl(context)}; + const auto res {boost::decimal::detail::parse_impl(ctx)}; ctx_precision = std::get<0>(res); fmt = std::get<1>(res); @@ -131,18 +143,21 @@ struct std::formatter return std::get<4>(res); } - template - auto format(const boost::decimal::decimal32& v, std::basic_format_context& context) const + template + auto format(const boost::decimal::decimal32 &v, FormatContext &ctx) const { - auto&& out = context.out(); - char buffer[128U]; - const auto r = to_chars(buffer, buffer + sizeof(buffer), v, fmt, ctx_precision); - *r.ptr = '\0'; - std::string s(buffer); + auto out = ctx.out(); + std::array buffer {}; + const auto r = to_chars(buffer.data(), buffer.data() + buffer.size(), v, fmt, ctx_precision); + + std::string_view sv(buffer.data(), static_cast(r.ptr - buffer.data())); + std::string s(sv); if (is_upper) { - std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::toupper(c); }); + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) + { return std::toupper(c); }); } if (s.size() < static_cast(padding_digits)) @@ -150,11 +165,12 @@ struct std::formatter s.insert(s.begin(), static_cast(padding_digits) - s.size(), '0'); } - out = std::copy(s.begin(), s.end(), out); - return out; + return std::copy(s.begin(), s.end(), out); } }; +} // Namespace std + #endif #endif //BOOST_DECIMAL_FORMAT_HPP From ae4b9829a6aa8bf4062bd169c16f547f64bbd4d4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 15:05:40 -0500 Subject: [PATCH 107/140] Simplify support detection --- include/boost/decimal/format.hpp | 4 +++- test/test_format.cpp | 7 +------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 990c887b..5d3d79ba 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -7,7 +7,9 @@ // Many compilers seem to have with completly broken support so narrow down our support range #if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && !defined(BOOST_DECIMAL_DISABLE_CLIB) && \ - ((defined(__GNUC__) && __GNUC__ >= 13) || (defined(__clang__) && __clang_major__ >= 17) || (defined(_MSC_VER) && _MSC_VER >= 1930)) + ((defined(__GNUC__) && __GNUC__ >= 13) || (defined(__clang__) && __clang_major__ > 19) || (defined(_MSC_VER) && _MSC_VER >= 1930)) + +#define BOOST_CRYPT_HAS_FORMAT_SUPPORT #include #include diff --git a/test/test_format.cpp b/test/test_format.cpp index 5ced6450..eb2fb2d5 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -7,9 +7,7 @@ using namespace boost::decimal; -#if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && __has_include() && !defined(BOOST_DECIMAL_DISABLE_CLIB) - -#include +#ifdef BOOST_CRYPT_HAS_FORMAT_SUPPORT template void test_general() @@ -55,9 +53,6 @@ int main() { test_general(); - //test(); - //test(); - return boost::report_errors(); } From 73cb8b5a28f61621493cf110553ed9076db88da4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 15:27:48 -0500 Subject: [PATCH 108/140] Add decimal64 support --- include/boost/decimal/format.hpp | 51 ++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 5d3d79ba..44986309 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -171,6 +171,57 @@ struct formatter { } }; +template <> +struct formatter { + constexpr formatter() : ctx_precision(6), + fmt(boost::decimal::chars_format::general), + is_upper(false), + padding_digits(0) + {} + + int ctx_precision; + boost::decimal::chars_format fmt; + bool is_upper; + int padding_digits; + + constexpr auto parse(format_parse_context &ctx) + { + const auto res {boost::decimal::detail::parse_impl(ctx)}; + + ctx_precision = std::get<0>(res); + fmt = std::get<1>(res); + is_upper = std::get<2>(res); + padding_digits = std::get<3>(res); + + return std::get<4>(res); + } + + template + auto format(const boost::decimal::decimal64& v, FormatContext &ctx) const + { + auto out = ctx.out(); + std::array buffer {}; + const auto r = to_chars(buffer.data(), buffer.data() + buffer.size(), v, fmt, ctx_precision); + + std::string_view sv(buffer.data(), static_cast(r.ptr - buffer.data())); + std::string s(sv); + + if (is_upper) + { + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) + { return std::toupper(c); }); + } + + if (s.size() < static_cast(padding_digits)) + { + s.insert(s.begin(), static_cast(padding_digits) - s.size(), '0'); + } + + return std::copy(s.begin(), s.end(), out); + } +}; + } // Namespace std #endif From 001aa5ba3102107cb8d81e00b4368ee4f42433f9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 15:27:56 -0500 Subject: [PATCH 109/140] adjust testing for decimal64 --- test/test_format.cpp | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/test/test_format.cpp b/test/test_format.cpp index eb2fb2d5..63cda034 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -4,6 +4,7 @@ #include #include +#include using namespace boost::decimal; @@ -19,9 +20,19 @@ void test_general() BOOST_TEST_EQ(std::format("{}", T{10000}), "10000"); BOOST_TEST_EQ(std::format("{}", T{210000}), "210000"); BOOST_TEST_EQ(std::format("{}", T{2100000}), "2100000"); - BOOST_TEST_EQ(std::format("{}", T{21, 6, true}), "-2.1e+07"); - BOOST_TEST_EQ(std::format("{}", T{211, 6, true}), "-2.11e+08"); - BOOST_TEST_EQ(std::format("{}", T{2111, 6, true}), "-2.111e+09"); + + if constexpr (std::numeric_limits::digits10 <= 7) + { + BOOST_TEST_EQ(std::format("{}", T {21, 6}), "2.1e+07"); + BOOST_TEST_EQ(std::format("{}", T {211, 6}), "2.11e+08"); + BOOST_TEST_EQ(std::format("{}", T {2111, 6}), "2.111e+09"); + } + else + { + BOOST_TEST_EQ(std::format("{}", T {21, 6}), "21000000"); + BOOST_TEST_EQ(std::format("{}", T {211, 6}), "211000000"); + BOOST_TEST_EQ(std::format("{}", T {2111, 6}), "2111000000"); + } BOOST_TEST_EQ(std::format("{}", std::numeric_limits::infinity()), "inf"); BOOST_TEST_EQ(std::format("{}", -std::numeric_limits::infinity()), "-inf"); @@ -37,9 +48,19 @@ void test_general() BOOST_TEST_EQ(std::format("{:g}", T{10000}), "10000"); BOOST_TEST_EQ(std::format("{:g}", T{210000}), "210000"); BOOST_TEST_EQ(std::format("{:g}", T{2100000}), "2100000"); - BOOST_TEST_EQ(std::format("{:g}", T{21, 6, true}), "-2.1e+07"); - BOOST_TEST_EQ(std::format("{:g}", T{211, 6, true}), "-2.11e+08"); - BOOST_TEST_EQ(std::format("{:g}", T{2111, 6, true}), "-2.111e+09"); + + if constexpr (std::numeric_limits::digits10 <= 7) + { + BOOST_TEST_EQ(std::format("{:g}", T {21, 6, true}), "-2.1e+07"); + BOOST_TEST_EQ(std::format("{:g}", T {211, 6, true}), "-2.11e+08"); + BOOST_TEST_EQ(std::format("{:g}", T {2111, 6, true}), "-2.111e+09"); + } + else + { + BOOST_TEST_EQ(std::format("{:g}", T {21, 6, true}), "-21000000"); + BOOST_TEST_EQ(std::format("{:g}", T {211, 6, true}), "-211000000"); + BOOST_TEST_EQ(std::format("{:g}", T {2111, 6, true}), "-2111000000"); + } BOOST_TEST_EQ(std::format("{:g}", std::numeric_limits::infinity()), "inf"); BOOST_TEST_EQ(std::format("{:g}", -std::numeric_limits::infinity()), "-inf"); @@ -52,6 +73,7 @@ void test_general() int main() { test_general(); + test_general(); return boost::report_errors(); } From e0ce9a6aee5324c6ae6076095925692f72476c87 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 15:46:00 -0500 Subject: [PATCH 110/140] Disable tests that fail on clang --- include/boost/decimal/format.hpp | 2 +- test/test_format.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 44986309..38fbbad5 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -7,7 +7,7 @@ // Many compilers seem to have with completly broken support so narrow down our support range #if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && !defined(BOOST_DECIMAL_DISABLE_CLIB) && \ - ((defined(__GNUC__) && __GNUC__ >= 13) || (defined(__clang__) && __clang_major__ > 19) || (defined(_MSC_VER) && _MSC_VER >= 1930)) + ((defined(__GNUC__) && __GNUC__ >= 13) || (defined(__clang__) && __clang_major__ >= 17) || (defined(_MSC_VER) && _MSC_VER >= 1930)) #define BOOST_CRYPT_HAS_FORMAT_SUPPORT diff --git a/test/test_format.cpp b/test/test_format.cpp index 63cda034..d8ca4e4c 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -13,6 +13,9 @@ using namespace boost::decimal; template void test_general() { + // For unknown reasons Clang does not like this empty bracket and throws compiler errors + #ifndef __clang__ + BOOST_TEST_EQ(std::format("{}", T{1}), "1"); BOOST_TEST_EQ(std::format("{}", T{10}), "10"); BOOST_TEST_EQ(std::format("{}", T{100}), "100"); @@ -41,6 +44,8 @@ void test_general() BOOST_TEST_EQ(std::format("{}", std::numeric_limits::signaling_NaN()), "nan(snan)"); BOOST_TEST_EQ(std::format("{}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); + #endif // defined(__clang__) + BOOST_TEST_EQ(std::format("{:g}", T{1}), "1"); BOOST_TEST_EQ(std::format("{:g}", T{10}), "10"); BOOST_TEST_EQ(std::format("{:g}", T{100}), "100"); From d6364b51fa7a61d7907e72c3345f533d46bfe502 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 15:54:01 -0500 Subject: [PATCH 111/140] Make a decimal concept template formatter --- include/boost/decimal/format.hpp | 65 +++----------------------------- 1 file changed, 6 insertions(+), 59 deletions(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 38fbbad5..7aa9abd2 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -11,9 +11,6 @@ #define BOOST_CRYPT_HAS_FORMAT_SUPPORT -#include -#include -#include #include #include #include @@ -25,7 +22,7 @@ // Default :g // Fixed :f -// Scientific :3 +// Scientific :e // Hex :a // // Capital letter for any of the above leads to all characters being uppercase @@ -120,59 +117,9 @@ constexpr auto parse_impl(ParseContext &ctx) namespace std { -template <> -struct formatter { - constexpr formatter() : ctx_precision(6), - fmt(boost::decimal::chars_format::general), - is_upper(false), - padding_digits(0) - {} - - int ctx_precision; - boost::decimal::chars_format fmt; - bool is_upper; - int padding_digits; - - constexpr auto parse(format_parse_context &ctx) - { - const auto res {boost::decimal::detail::parse_impl(ctx)}; - - ctx_precision = std::get<0>(res); - fmt = std::get<1>(res); - is_upper = std::get<2>(res); - padding_digits = std::get<3>(res); - - return std::get<4>(res); - } - - template - auto format(const boost::decimal::decimal32 &v, FormatContext &ctx) const - { - auto out = ctx.out(); - std::array buffer {}; - const auto r = to_chars(buffer.data(), buffer.data() + buffer.size(), v, fmt, ctx_precision); - - std::string_view sv(buffer.data(), static_cast(r.ptr - buffer.data())); - std::string s(sv); - - if (is_upper) - { - std::transform(s.begin(), s.end(), s.begin(), - [](unsigned char c) - { return std::toupper(c); }); - } - - if (s.size() < static_cast(padding_digits)) - { - s.insert(s.begin(), static_cast(padding_digits) - s.size(), '0'); - } - - return std::copy(s.begin(), s.end(), out); - } -}; - -template <> -struct formatter { +template +struct formatter +{ constexpr formatter() : ctx_precision(6), fmt(boost::decimal::chars_format::general), is_upper(false), @@ -197,11 +144,11 @@ struct formatter { } template - auto format(const boost::decimal::decimal64& v, FormatContext &ctx) const + auto format(const T &v, FormatContext &ctx) const { auto out = ctx.out(); std::array buffer {}; - const auto r = to_chars(buffer.data(), buffer.data() + buffer.size(), v, fmt, ctx_precision); + const auto r = boost::decimal::to_chars(buffer.data(), buffer.data() + buffer.size(), v, fmt, ctx_precision); std::string_view sv(buffer.data(), static_cast(r.ptr - buffer.data())); std::string s(sv); From 61221941d9c772aa5979873d208d195b248e9fd4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 15:54:13 -0500 Subject: [PATCH 112/140] Add testing of additional types --- test/test_format.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_format.cpp b/test/test_format.cpp index d8ca4e4c..25cfbef5 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -78,7 +78,11 @@ void test_general() int main() { test_general(); + test_general(); test_general(); + test_general(); + test_general(); + test_general(); return boost::report_errors(); } From 3ae8bdf1f3259b1a412740fecb3e40310f33f56e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 16:26:07 -0500 Subject: [PATCH 113/140] Begin adding fixed format tests --- test/test_format.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_format.cpp b/test/test_format.cpp index 25cfbef5..d87f0d97 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -75,6 +75,14 @@ void test_general() BOOST_TEST_EQ(std::format("{:g}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); } +template +void test_fixed() +{ + BOOST_TEST_EQ(std::format("{:f}", T {21, 6, true}), "-21000000.000000"); + BOOST_TEST_EQ(std::format("{:f}", T {211, 6, true}), "-211000000.000000"); + BOOST_TEST_EQ(std::format("{:f}", T {2111, 6, true}), "-2111000000.000000"); +} + int main() { test_general(); @@ -84,6 +92,13 @@ int main() test_general(); test_general(); + test_fixed(); + test_fixed(); + test_fixed(); + test_fixed(); + test_fixed(); + test_fixed(); + return boost::report_errors(); } From 1de7dbc617ceea8abcbb1044efe712367a56337b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 16:26:31 -0500 Subject: [PATCH 114/140] Begin simplified parser with better understanding of the context --- include/boost/decimal/format.hpp | 52 ++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 7aa9abd2..667c9288 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -29,6 +29,7 @@ namespace boost::decimal::detail { +/* template constexpr auto parse_impl(ParseContext &ctx) { @@ -112,6 +113,57 @@ constexpr auto parse_impl(ParseContext &ctx) return std::make_tuple(ctx_precision, fmt, is_upper, padding_digits, it); } +*/ + +template +constexpr auto parse_impl(ParseContext &ctx) +{ + auto it {ctx.begin()}; + int ctx_precision = 6; + boost::decimal::chars_format fmt = boost::decimal::chars_format::general; + bool is_upper = false; + int padding_digits = 0; + + if (*it != '}') + { + switch (*it) + { + case 'G': + is_upper = true; + [[fallthrough]]; + case 'g': + fmt = chars_format::general; + break; + + case 'F': + [[fallthrough]]; + case 'f': + fmt = chars_format::fixed; + break; + + case 'E': + is_upper = true; + [[fallthrough]]; + case 'e': + fmt = chars_format::scientific; + break; + + case 'A': + is_upper = true; + [[fallthrough]]; + case 'a': + fmt = chars_format::hex; + break; + + default: + throw std::format_error("Invalid format"); + } + } + + ++it; + + return std::make_tuple(ctx_precision, fmt, is_upper, padding_digits, it); +} } // Namespace boost::decimal::detail From 5fbe238fa800551ea18a8ce248cbc2771bcf31f9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 16:59:03 -0500 Subject: [PATCH 115/140] Add parsing of precision argument --- include/boost/decimal/format.hpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 667c9288..2a458901 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -124,7 +124,20 @@ constexpr auto parse_impl(ParseContext &ctx) bool is_upper = false; int padding_digits = 0; - if (*it != '}') + // If there is a . then we need to capture the precision argument + if (*it == '.') + { + ++it; + ctx_precision = 0; + while (it != ctx.end() && *it >= '0' && *it <= '9') + { + ctx_precision = ctx_precision * 10 + (*it - '0'); + ++it; + } + } + + // Lastly we capture the format to include if it's upper case + if (it != ctx.end() && *it != '}') { switch (*it) { From 0b3d4e1af23876f0845e2a7112acb69105e7d86b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Jan 2025 16:59:19 -0500 Subject: [PATCH 116/140] Add fixed format tests with precision argument --- test/test_format.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_format.cpp b/test/test_format.cpp index d87f0d97..ed2f7d6e 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -81,6 +81,10 @@ void test_fixed() BOOST_TEST_EQ(std::format("{:f}", T {21, 6, true}), "-21000000.000000"); BOOST_TEST_EQ(std::format("{:f}", T {211, 6, true}), "-211000000.000000"); BOOST_TEST_EQ(std::format("{:f}", T {2111, 6, true}), "-2111000000.000000"); + + BOOST_TEST_EQ(std::format("{:.0f}", T {21, 6, true}), std::string{"-21000000"}); + BOOST_TEST_EQ(std::format("{:.0f}", T {211, 6, true}), std::string{"-211000000"}); + BOOST_TEST_EQ(std::format("{:.0f}", T {2111, 6, true}), std::string{"-2111000000"}); } int main() From 6a18d6fe046aca4a103267ec34164f6005222496 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 09:26:10 -0500 Subject: [PATCH 117/140] Add clang 18 and 19 --- .github/workflows/ci.yml | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75972227..3be989b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -226,18 +226,26 @@ jobs: - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" source_keys: - "https://apt.llvm.org/llvm-snapshot.gpg.key" - - name: UBSAN - toolset: clang - compiler: clang++-14 + - toolset: clang + compiler: clang++-18 cxxstd: "03,11,14,17,20,2b" - cxxflags: -stdlib=libc++ - linkflags: -stdlib=libc++ - ubsan: 1 - os: ubuntu-22.04 + os: ubuntu-24.04 install: - - clang-14 - - libc++-14-dev - - libc++abi-14-dev + - clang-18 + sources: + - "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-18 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-19 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-24.04 + install: + - clang-19 + sources: + - "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" - toolset: clang cxxstd: "03,11,14,17,20,2b" From 007e5cca713c4a933d5d92ee5bcac6c813620afd Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 09:31:50 -0500 Subject: [PATCH 118/140] Suppress warnings --- examples/statistics.cpp | 3 +++ include/boost/decimal/format.hpp | 2 +- test/test_format.cpp | 6 ++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/statistics.cpp b/examples/statistics.cpp index 2239cb29..86949e14 100644 --- a/examples/statistics.cpp +++ b/examples/statistics.cpp @@ -11,10 +11,13 @@ #include #include +// Warning suppression for boost.math #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wfloat-equal" # pragma clang diagnostic ignored "-Wsign-conversion" +# pragma clang diagnostic ignored "-Wundef" +# pragma clang diagnostic ignored "-Wstring-conversion" #elif defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wfloat-equal" diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 2a458901..43dd5df3 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -7,7 +7,7 @@ // Many compilers seem to have with completly broken support so narrow down our support range #if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && !defined(BOOST_DECIMAL_DISABLE_CLIB) && \ - ((defined(__GNUC__) && __GNUC__ >= 13) || (defined(__clang__) && __clang_major__ >= 17) || (defined(_MSC_VER) && _MSC_VER >= 1930)) + ((defined(__GNUC__) && __GNUC__ >= 13) || (defined(__clang__) && __clang_major__ > 17) || (defined(_MSC_VER) && _MSC_VER >= 1930)) #define BOOST_CRYPT_HAS_FORMAT_SUPPORT diff --git a/test/test_format.cpp b/test/test_format.cpp index ed2f7d6e..bcaa8d3c 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -2,6 +2,12 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt +// MSVC 14.3 has a conversion error in so we need to try and supress that everywhere +#ifdef _MSC_VER +# pragma warning(push) +# pragma wanning(disable : 4244) +#endif + #include #include #include From 6ec3f63bbc316145bfb7c218ab4924c05f580abe Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 09:41:37 -0500 Subject: [PATCH 119/140] Add additional fixed and non-finite tests --- test/test_format.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/test_format.cpp b/test/test_format.cpp index bcaa8d3c..e2cc535a 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -91,6 +91,18 @@ void test_fixed() BOOST_TEST_EQ(std::format("{:.0f}", T {21, 6, true}), std::string{"-21000000"}); BOOST_TEST_EQ(std::format("{:.0f}", T {211, 6, true}), std::string{"-211000000"}); BOOST_TEST_EQ(std::format("{:.0f}", T {2111, 6, true}), std::string{"-2111000000"}); + + BOOST_TEST_EQ(std::format("{:.1f}", T {21, 6, true}), std::string{"-21000000.0"}); + BOOST_TEST_EQ(std::format("{:.1f}", T {211, 6, true}), std::string{"-211000000.0"}); + BOOST_TEST_EQ(std::format("{:.1f}", T {2111, 6, true}), std::string{"-2111000000.0"}); + + BOOST_TEST_EQ(std::format("{:.0f}", T {0}), "0"); + BOOST_TEST_EQ(std::format("{:f}", std::numeric_limits::infinity()), "inf"); + BOOST_TEST_EQ(std::format("{:f}", -std::numeric_limits::infinity()), "-inf"); + BOOST_TEST_EQ(std::format("{:f}", std::numeric_limits::quiet_NaN()), "nan"); + BOOST_TEST_EQ(std::format("{:f}", -std::numeric_limits::quiet_NaN()), "-nan(ind)"); + BOOST_TEST_EQ(std::format("{:f}", std::numeric_limits::signaling_NaN()), "nan(snan)"); + BOOST_TEST_EQ(std::format("{:f}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); } int main() From 81a3d47f8f11b45a6c9060b507fdaf5a588c763d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 10:32:23 -0500 Subject: [PATCH 120/140] Add appropriate handling for a padding character --- include/boost/decimal/format.hpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 43dd5df3..32f78c85 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -124,6 +124,13 @@ constexpr auto parse_impl(ParseContext &ctx) bool is_upper = false; int padding_digits = 0; + // Check for a padding character + while (it != ctx.end() && *it >= '0' && *it <= '9') + { + padding_digits = padding_digits * 10 + (*it - '0'); + ++it; + } + // If there is a . then we need to capture the precision argument if (*it == '.') { @@ -227,7 +234,7 @@ struct formatter if (s.size() < static_cast(padding_digits)) { - s.insert(s.begin(), static_cast(padding_digits) - s.size(), '0'); + s.insert(s.begin(), static_cast(padding_digits) - s.size(), ' '); } return std::copy(s.begin(), s.end(), out); From 7981f6f0eb10ba70a388754b4769732f325a4e63 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 10:32:32 -0500 Subject: [PATCH 121/140] Add scientific and padding tests --- test/test_format.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/test_format.cpp b/test/test_format.cpp index e2cc535a..a5357295 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -105,6 +105,30 @@ void test_fixed() BOOST_TEST_EQ(std::format("{:f}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); } +template +void test_scientific() +{ + BOOST_TEST_EQ(std::format("{:e}", T {21, 6, true}), "-2.100000e+07"); + BOOST_TEST_EQ(std::format("{:e}", T {211, 6, true}), "-2.110000e+08"); + BOOST_TEST_EQ(std::format("{:e}", T {2111, 6, true}), "-2.111000e+09"); + + BOOST_TEST_EQ(std::format("{:E}", T {21, 6, true}), "-2.100000E+07"); + BOOST_TEST_EQ(std::format("{:E}", T {211, 6, true}), "-2.110000E+08"); + BOOST_TEST_EQ(std::format("{:E}", T {2111, 6, true}), "-2.111000E+09"); + + BOOST_TEST_EQ(std::format("{:.0E}", T {0}), "0E+00"); + BOOST_TEST_EQ(std::format("{:e}", std::numeric_limits::infinity()), "inf"); + BOOST_TEST_EQ(std::format("{:e}", -std::numeric_limits::infinity()), "-inf"); + BOOST_TEST_EQ(std::format("{:e}", std::numeric_limits::quiet_NaN()), "nan"); + BOOST_TEST_EQ(std::format("{:e}", -std::numeric_limits::quiet_NaN()), "-nan(ind)"); + BOOST_TEST_EQ(std::format("{:e}", std::numeric_limits::signaling_NaN()), "nan(snan)"); + BOOST_TEST_EQ(std::format("{:e}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); + + // Padding to the front + BOOST_TEST_EQ(std::format("{:10.1E}", T {0}), " 0.0E+00"); + BOOST_TEST_EQ(std::format("{:10.3E}", T {0}), " 0.000E+00"); +} + int main() { test_general(); @@ -121,6 +145,13 @@ int main() test_fixed(); test_fixed(); + test_scientific(); + test_scientific(); + test_scientific(); + test_scientific(); + test_scientific(); + test_scientific(); + return boost::report_errors(); } From 45f016d33f4dcf9d3fb1156b5673d817ab777ed3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 10:33:51 -0500 Subject: [PATCH 122/140] Remove old impl --- include/boost/decimal/format.hpp | 88 +------------------------------- 1 file changed, 1 insertion(+), 87 deletions(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 32f78c85..9315a274 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -29,92 +29,6 @@ namespace boost::decimal::detail { -/* -template -constexpr auto parse_impl(ParseContext &ctx) -{ - auto it {ctx.begin()}; - ++it; - int ctx_precision = 6; - boost::decimal::chars_format fmt = boost::decimal::chars_format::general; - bool is_upper = false; - int padding_digits = 0; - - if (it == ctx.end()) - { - return std::make_tuple(ctx_precision, fmt, is_upper, padding_digits, it); - } - - while (it != ctx.end() && *it >= '0' && *it <= '9') - { - padding_digits = padding_digits * 10 + (*it - '0'); - ++it; - } - - if (it != ctx.end() && *it == ':') - { - ++it; - } - - if (it != ctx.end() && *it == '.') - { - ++it; - ctx_precision = 0; - while (it != ctx.end() && *it >= '0' && *it <= '9') - { - ctx_precision = ctx_precision * 10 + (*it - '0'); - ++it; - } - - if (it == ctx.end()) - { - throw std::format_error("Unexpected end of format string"); - } - - switch (*it) - { - case 'G': - is_upper = true; - [[fallthrough]]; - case 'g': - fmt = chars_format::general; - break; - - case 'F': - [[fallthrough]]; - case 'f': - fmt = chars_format::fixed; - break; - - case 'E': - is_upper = true; - [[fallthrough]]; - case 'e': - fmt = chars_format::scientific; - break; - - case 'A': - is_upper = true; - [[fallthrough]]; - case 'a': - fmt = chars_format::hex; - break; - - default: - throw std::format_error("Invalid format"); - } - ++it; - } - - if (it == ctx.end() || *it != '}') - { - throw std::format_error("Invalid format"); - } - - return std::make_tuple(ctx_precision, fmt, is_upper, padding_digits, it); -} -*/ - template constexpr auto parse_impl(ParseContext &ctx) { @@ -176,7 +90,7 @@ constexpr auto parse_impl(ParseContext &ctx) break; default: - throw std::format_error("Invalid format"); + throw std::format_error("Invalid format specifier"); } } From 2533965e281fcc86729a2381ca9b3d6f40aa3a75 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 10:42:20 -0500 Subject: [PATCH 123/140] Add simple hex formatting --- test/test_format.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/test_format.cpp b/test/test_format.cpp index a5357295..8980d62c 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -129,6 +129,19 @@ void test_scientific() BOOST_TEST_EQ(std::format("{:10.3E}", T {0}), " 0.000E+00"); } +template +void test_hex() +{ + BOOST_TEST_EQ(std::format("{:.0a}", T {0}), "0p+00"); + BOOST_TEST_EQ(std::format("{:.3A}", T {0}), "0.000P+00"); + BOOST_TEST_EQ(std::format("{:a}", std::numeric_limits::infinity()), "inf"); + BOOST_TEST_EQ(std::format("{:a}", -std::numeric_limits::infinity()), "-inf"); + BOOST_TEST_EQ(std::format("{:a}", std::numeric_limits::quiet_NaN()), "nan"); + BOOST_TEST_EQ(std::format("{:a}", -std::numeric_limits::quiet_NaN()), "-nan(ind)"); + BOOST_TEST_EQ(std::format("{:a}", std::numeric_limits::signaling_NaN()), "nan(snan)"); + BOOST_TEST_EQ(std::format("{:a}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); +} + int main() { test_general(); @@ -152,6 +165,13 @@ int main() test_scientific(); test_scientific(); + test_hex(); + test_hex(); + test_hex(); + test_hex(); + test_hex(); + test_hex(); + return boost::report_errors(); } From 787e5dd6e2a9b65712d3b77edb5e9653f87afe64 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 11:06:23 -0500 Subject: [PATCH 124/140] Add format to docs --- doc/decimal.adoc | 1 + doc/decimal/format.adoc | 63 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 doc/decimal/format.adoc diff --git a/doc/decimal.adoc b/doc/decimal.adoc index 085ee902..b5e0dd5c 100644 --- a/doc/decimal.adoc +++ b/doc/decimal.adoc @@ -33,6 +33,7 @@ include::decimal/numbers.adoc[] include::decimal/cmath.adoc[] include::decimal/cstdlib.adoc[] include::decimal/charconv.adoc[] +include::decimal/format.adoc[] include::decimal/cfenv.adoc[] include::decimal/cfloat.adoc[] include::decimal/cstdio.adoc[] diff --git a/doc/decimal/format.adoc b/doc/decimal/format.adoc new file mode 100644 index 00000000..087d1cfa --- /dev/null +++ b/doc/decimal/format.adoc @@ -0,0 +1,63 @@ +//// +Copyright 2025 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#format] += format support +:idprefix: format_ + +== + +Format is supported when using C++20 and a compiler with appropriate support: GCC >= 13, Clang >= 18, MSVC >= 19.30 + +=== Type Modifiers + +The following type modifiers are the same as those used by built-in floating point values: + +- "g" or "G" for general format +- "e" or "E" for scientific format +- "f" for fixed format +- "a" or "A" for hex format + +Example usage for scientific format would be: `{:e}` + +NOTE: The uppercase format will return with all applicable values in uppercase (e.g. 3.14E+02 vs 3.14e+02) + +=== Precision Modifiers + +Precision can be specified in the same way as built-in floating point values. +For example a scientific format with 3 digits or precision would be: `{:.3e}` + +=== Padding Modifiers + +If you want all values to be printed with a fixed width padding is allowed before the precision modifier. +For example with `{:10.3e}`: + +- 3.14 -> " 3.140e+00" +- 3.141 -> " 3.141e+00" + +Note the space at the front of these string to keep with width at 10 characters + +=== Examples + +The example is padding modifiers can be done like so + +[source, c++] +---- +#include +#include +#include + +int main() +{ + constexpr boost::decimal::decimal64 val1 {314, -2}; + constexpr boost::decimal::decimal32 val2 {3141, -3}; + + std::cout << std::format("{:10.3e}", val1) << '\n'; + std::cout << std::format("{:10.3e}", val2) << std::endl; + + return 0; +} +---- From ff910130f4a8e413c32977abc8521c6e93589134 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 11:13:56 -0500 Subject: [PATCH 125/140] Add format example --- examples/format.cpp | 31 +++++++++++++++++++++++++++++++ test/Jamfile | 1 + 2 files changed, 32 insertions(+) create mode 100644 examples/format.cpp diff --git a/examples/format.cpp b/examples/format.cpp new file mode 100644 index 00000000..14e34dd7 --- /dev/null +++ b/examples/format.cpp @@ -0,0 +1,31 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +#ifdef BOOST_CRYPT_HAS_FORMAT_SUPPORT + +#include + +int main() +{ + constexpr boost::decimal::decimal64 val1 {314, -2}; + constexpr boost::decimal::decimal32 val2 {3141, -3}; + + std::cout << std::format("{:10.3e}", val1) << '\n'; + std::cout << std::format("{:10.3e}", val2) << std::endl; + + return 0; +} + +#else + +int main() +{ + std::cout << " is unsupported" << std::endl; + return 0; +} + +#endif diff --git a/test/Jamfile b/test/Jamfile index f25a2452..d67baeb4 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -154,3 +154,4 @@ run ../examples/rounding_mode.cpp ; run ../examples/moving_average.cpp ; run ../examples/currency_conversion.cpp ; run ../examples/statistics.cpp ; +run ../examples/format.cpp ; From ea3cc7596519a3fa1cb133cfa789a0488449d5ff Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 11:15:44 -0500 Subject: [PATCH 126/140] Fix typo for MSVC --- test/test_format.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_format.cpp b/test/test_format.cpp index 8980d62c..f3a1ca77 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -5,7 +5,7 @@ // MSVC 14.3 has a conversion error in so we need to try and supress that everywhere #ifdef _MSC_VER # pragma warning(push) -# pragma wanning(disable : 4244) +# pragma warning(disable : 4244) #endif #include From b5d30920d8116f8df3692ef4bcf785cbb851aee4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 11:32:26 -0500 Subject: [PATCH 127/140] Improve coverage --- include/boost/decimal/format.hpp | 3 ++- test/test_format.cpp | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 9315a274..21b97d04 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -88,9 +88,10 @@ constexpr auto parse_impl(ParseContext &ctx) case 'a': fmt = chars_format::hex; break; - + // LCOV_EXCL_START default: throw std::format_error("Invalid format specifier"); + // LCOV_EXCL_STOP } } diff --git a/test/test_format.cpp b/test/test_format.cpp index f3a1ca77..b4cc9710 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -65,6 +65,9 @@ void test_general() BOOST_TEST_EQ(std::format("{:g}", T {21, 6, true}), "-2.1e+07"); BOOST_TEST_EQ(std::format("{:g}", T {211, 6, true}), "-2.11e+08"); BOOST_TEST_EQ(std::format("{:g}", T {2111, 6, true}), "-2.111e+09"); + BOOST_TEST_EQ(std::format("{:G}", T {21, 6, true}), "-2.1E+07"); + BOOST_TEST_EQ(std::format("{:G}", T {211, 6, true}), "-2.11E+08"); + BOOST_TEST_EQ(std::format("{:G}", T {2111, 6, true}), "-2.111E+09"); } else { From 56554afb5bfdc2b4cba1ce3a05f7b9ebdff804a0 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 11:49:24 -0500 Subject: [PATCH 128/140] Ignore internal MSVC warning --- examples/format.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/format.cpp b/examples/format.cpp index 14e34dd7..da14a682 100644 --- a/examples/format.cpp +++ b/examples/format.cpp @@ -2,6 +2,12 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt +// MSVC 14.3 has a conversion error in so we need to try and supress that everywhere +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4244) +#endif + #include #include From 37a0c245211ae711342c93c78643b45ece56154f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 12:58:55 -0500 Subject: [PATCH 129/140] Update build requirements --- doc/decimal/format.adoc | 2 +- include/boost/decimal/format.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/decimal/format.adoc b/doc/decimal/format.adoc index 087d1cfa..038fa719 100644 --- a/doc/decimal/format.adoc +++ b/doc/decimal/format.adoc @@ -10,7 +10,7 @@ https://www.boost.org/LICENSE_1_0.txt == -Format is supported when using C++20 and a compiler with appropriate support: GCC >= 13, Clang >= 18, MSVC >= 19.30 +Format is supported when using C++20 and a compiler with appropriate support: GCC >= 13, Clang >= 18, MSVC >= 19.40 === Type Modifiers diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 21b97d04..b7246692 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -7,7 +7,7 @@ // Many compilers seem to have with completly broken support so narrow down our support range #if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && !defined(BOOST_DECIMAL_DISABLE_CLIB) && \ - ((defined(__GNUC__) && __GNUC__ >= 13) || (defined(__clang__) && __clang_major__ > 17) || (defined(_MSC_VER) && _MSC_VER >= 1930)) + ((defined(__GNUC__) && __GNUC__ >= 13) || (defined(__clang__) && __clang_major__ >= 18) || (defined(_MSC_VER) && _MSC_VER >= 1940)) #define BOOST_CRYPT_HAS_FORMAT_SUPPORT From 3f992fa5283486fea114194958b3f16c5b0a05e2 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 13:34:36 -0500 Subject: [PATCH 130/140] Add security policy --- SECURITY.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..eb11c03e --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +If you believe you have found a security critical bug, please **DO NOT** open a regular issue and instead follow the reporting steps below. +For all regular bugs (e.g. incorrect results) please feel free to open an issue on the github page. + +## Reporting a Vulnerability + +Please email your security bugs to matt at mattborland dot com. +I will respond same day, or next business day (I am located in the Eastern US time zone) and work with you to diagnose and fix the issue. +My public key is listed below so that you can securely email me: + +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xjMEX2wgdBYJKwYBBAHaRw8BAQdAUHOh0KpbZCszhdvKztWj4C6FR1ozMBQE +waBi3m2PJHLNK21hdHRAbWF0dGJvcmxhbmQuY29tIDxtYXR0QG1hdHRib3Js +YW5kLmNvbT7CjwQQFgoAIAUCX2wgdAYLCQcIAwIEFQgKAgQWAgEAAhkBAhsD +Ah4BACEJEFmBWlVCFaWlFiEEwTgurTcoHwbdSbIsWYFaVUIVpaVWuwEA77rm +OA4TB6Xxe6q8gI42bEICMhMyZKSMcakz39/djYkBAMJOG+IGQC/d0n3dsl10 +Kg/oxX88kFO1oPKn4/XW+ToBzjgEX2wgdBIKKwYBBAGXVQEFAQEHQOsmo6wR +UuXRAvFIiqmQkzYrPyvKYKna2z4ZtmnTQMkMAwEIB8J4BBgWCAAJBQJfbCB0 +AhsMACEJEFmBWlVCFaWlFiEEwTgurTcoHwbdSbIsWYFaVUIVpaWUJwEA5G0c +ZRnG5WGNErI+y90iQrTv02i4Ivhv7twoFcLD/zwA/jKypw+vehE99mEj1/uI +EkoDFlNzQZqNldbjRcPyI5UH +=462S +-----END PGP PUBLIC KEY BLOCK----- +``` From a6ebf5019323bc052bb9975c6a13fba1427b92c7 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 13:56:11 -0500 Subject: [PATCH 131/140] Add 64-bit FMA --- include/boost/decimal/detail/cmath/fma.hpp | 66 +++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/cmath/fma.hpp b/include/boost/decimal/detail/cmath/fma.hpp index 63319a6d..a752fa26 100644 --- a/include/boost/decimal/detail/cmath/fma.hpp +++ b/include/boost/decimal/detail/cmath/fma.hpp @@ -82,6 +82,58 @@ constexpr auto d32_fma_impl(T x, T y, T z) noexcept -> T abs_lhs_bigger); } +template +constexpr auto d64_fma_impl(T x, T y, T z) noexcept -> T +{ + using T_components_type = components_type; + using exp_type = typename T::biased_exponent_type; + + // Apply the add + #ifndef BOOST_DECIMAL_FAST_MATH + BOOST_DECIMAL_IF_CONSTEXPR (checked) + { + if (!isfinite(x) || !isfinite(y)) + { + return detail::check_non_finite(x, y); + } + } + #endif + + int exp_lhs {}; + auto sig_lhs = frexp10(x, &exp_lhs); + + int exp_rhs {}; + auto sig_rhs = frexp10(y, &exp_rhs); + + auto first_res = detail::d64_mul_impl(sig_lhs, static_cast(exp_lhs), x < 0, + sig_rhs, static_cast(exp_rhs), y < 0); + + // Apply the mul on the carried components + // We still create the result as a decimal type to check for non-finite values and comparisons, + // but we do not use it for the resultant calculation + const T complete_lhs {first_res.sig, first_res.exp, first_res.sign}; + + #ifndef BOOST_DECIMAL_FAST_MATH + BOOST_DECIMAL_IF_CONSTEXPR (checked) + { + if (!isfinite(complete_lhs) || !isfinite(z)) + { + return detail::check_non_finite(complete_lhs, z); + } + } + #endif + + const bool abs_lhs_bigger {abs(complete_lhs) > abs(z)}; + + int exp_z {}; + auto sig_z = frexp10(z, &exp_z); + detail::normalize(first_res.sig, first_res.exp); + + return detail::d64_add_impl(first_res.sig, first_res.exp, first_res.sign, + sig_z, static_cast(exp_z), z < 0, + abs_lhs_bigger); +} + #ifdef _MSC_VER #pragma warning(pop) #endif @@ -96,6 +148,16 @@ constexpr auto unchecked_fma(decimal32_fast x, decimal32_fast y, decimal32_fast return detail::d32_fma_impl(x, y, z); } +constexpr auto unchecked_fma(decimal64 x, decimal64 y, decimal64 z) noexcept -> decimal64 +{ + return detail::d64_fma_impl(x, y, z); +} + +constexpr auto unchecked_fma(decimal64_fast x, decimal64_fast y, decimal64_fast z) noexcept -> decimal64_fast +{ + return detail::d64_fma_impl(x, y, z); +} + } // Namespace detail BOOST_DECIMAL_EXPORT constexpr auto fma(decimal32 x, decimal32 y, decimal32 z) noexcept -> decimal32 @@ -105,7 +167,7 @@ BOOST_DECIMAL_EXPORT constexpr auto fma(decimal32 x, decimal32 y, decimal32 z) n BOOST_DECIMAL_EXPORT constexpr auto fma(decimal64 x, decimal64 y, decimal64 z) noexcept -> decimal64 { - return x * y + z; + return detail::d64_fma_impl(x, y, z); } BOOST_DECIMAL_EXPORT constexpr auto fma(decimal128 x, decimal128 y, decimal128 z) noexcept -> decimal128 @@ -120,7 +182,7 @@ BOOST_DECIMAL_EXPORT constexpr auto fma(decimal32_fast x, decimal32_fast y, deci BOOST_DECIMAL_EXPORT constexpr auto fma(decimal64_fast x, decimal64_fast y, decimal64_fast z) noexcept -> decimal64_fast { - return x * y + z; + return detail::d64_fma_impl(x, y, z); } BOOST_DECIMAL_EXPORT constexpr auto fma(decimal128_fast x, decimal128_fast y, decimal128_fast z) noexcept -> decimal128_fast From f0e3e4d3e3872eef9a5ed0b6a9a1bbd2ea626d6d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 14:01:54 -0500 Subject: [PATCH 132/140] Add 128-bit framework --- include/boost/decimal/detail/cmath/fma.hpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/cmath/fma.hpp b/include/boost/decimal/detail/cmath/fma.hpp index a752fa26..dd785598 100644 --- a/include/boost/decimal/detail/cmath/fma.hpp +++ b/include/boost/decimal/detail/cmath/fma.hpp @@ -134,6 +134,12 @@ constexpr auto d64_fma_impl(T x, T y, T z) noexcept -> T abs_lhs_bigger); } +template +constexpr auto d128_fma_impl(T x, T y, T z) noexcept -> T +{ + return x * y + z; +} + #ifdef _MSC_VER #pragma warning(pop) #endif @@ -158,6 +164,16 @@ constexpr auto unchecked_fma(decimal64_fast x, decimal64_fast y, decimal64_fast return detail::d64_fma_impl(x, y, z); } +constexpr auto unchecked_fma(decimal128 x, decimal128 y, decimal128 z) noexcept -> decimal128 +{ + return detail::d128_fma_impl(x, y, z); +} + +constexpr auto unchecked_fma(decimal128_fast x, decimal128_fast y, decimal128_fast z) noexcept -> decimal128_fast +{ + return detail::d128_fma_impl(x, y, z); +} + } // Namespace detail BOOST_DECIMAL_EXPORT constexpr auto fma(decimal32 x, decimal32 y, decimal32 z) noexcept -> decimal32 @@ -172,7 +188,7 @@ BOOST_DECIMAL_EXPORT constexpr auto fma(decimal64 x, decimal64 y, decimal64 z) n BOOST_DECIMAL_EXPORT constexpr auto fma(decimal128 x, decimal128 y, decimal128 z) noexcept -> decimal128 { - return x * y + z; + return detail::d128_fma_impl(x, y, z); } BOOST_DECIMAL_EXPORT constexpr auto fma(decimal32_fast x, decimal32_fast y, decimal32_fast z) noexcept -> decimal32_fast @@ -187,7 +203,7 @@ BOOST_DECIMAL_EXPORT constexpr auto fma(decimal64_fast x, decimal64_fast y, deci BOOST_DECIMAL_EXPORT constexpr auto fma(decimal128_fast x, decimal128_fast y, decimal128_fast z) noexcept -> decimal128_fast { - return x * y + z; + return detail::d128_fma_impl(x, y, z); } } //namespace decimal From 9dc4e7e2d2d0b4bcc45f0f07ce8af80974078d9c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 14:03:45 -0500 Subject: [PATCH 133/140] Use unchecked fma to speed up spec fun --- include/boost/decimal/detail/cmath/impl/remez_series_result.hpp | 2 +- .../boost/decimal/detail/cmath/impl/taylor_series_result.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/cmath/impl/remez_series_result.hpp b/include/boost/decimal/detail/cmath/impl/remez_series_result.hpp index 5ba74062..9acadf88 100644 --- a/include/boost/decimal/detail/cmath/impl/remez_series_result.hpp +++ b/include/boost/decimal/detail/cmath/impl/remez_series_result.hpp @@ -20,7 +20,7 @@ constexpr auto remez_series_result(T x, const Array &coeffs) noexcept result = coeffs[0]; for (std::size_t i {1}; i < coeffs.size(); ++i) { - result = fma(result, x, coeffs[i]); + result = unchecked_fma(result, x, coeffs[i]); } return result; diff --git a/include/boost/decimal/detail/cmath/impl/taylor_series_result.hpp b/include/boost/decimal/detail/cmath/impl/taylor_series_result.hpp index 53ad2b7a..984dabc7 100644 --- a/include/boost/decimal/detail/cmath/impl/taylor_series_result.hpp +++ b/include/boost/decimal/detail/cmath/impl/taylor_series_result.hpp @@ -21,7 +21,7 @@ constexpr auto taylor_series_result(T x, const Array &coeffs) noexcept for (std::size_t i = N - 1; i-- > 0;) { - result = fma(result, x, coeffs[i]); + result = unchecked_fma(result, x, coeffs[i]); } return result; From 20306367a28b70d6afedf5f3ced5e833ef779a1b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 15:16:34 -0500 Subject: [PATCH 134/140] Breakup long running test --- .drone.jsonnet | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index 3ef10a0a..be4054e8 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -202,9 +202,16 @@ local windows_pipeline(name, image, environment, arch = "amd64") = ), linux_pipeline( - "Linux 24.04 GCC 13 GNU 32/64", + "Linux 24.04 GCC 13 GNU 32", "cppalliance/droneubuntu2404:1", - { TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14,17,20,23', ADDRMD: '32,64', CXXFLAGS: "-fexcess-precision=fast", CXXSTDDIALECT: "gnu" }, + { TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14,17,20,23', ADDRMD: '32', CXXFLAGS: "-fexcess-precision=fast", CXXSTDDIALECT: "gnu" }, + "g++-13-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 13 GNU 64", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14,17,20,23', ADDRMD: '64', CXXFLAGS: "-fexcess-precision=fast", CXXSTDDIALECT: "gnu" }, "g++-13-multilib", ), From c61f8fb9f324db1f24eebb38eab29b830a24b7a6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 15:33:26 -0500 Subject: [PATCH 135/140] Fix copy paste error for MSVC --- modules/decimal.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/decimal.cxx b/modules/decimal.cxx index 033c745b..5b0eaa59 100644 --- a/modules/decimal.cxx +++ b/modules/decimal.cxx @@ -102,21 +102,21 @@ struct numeric_limits; template <> #ifdef _MSC_VER -class numeric_limits; +class numeric_limits; #else struct numeric_limits; #endif template <> #ifdef _MSC_VER -class numeric_limits; +class numeric_limits; #else struct numeric_limits; #endif template <> #ifdef _MSC_VER -class numeric_limits; +class numeric_limits; #else struct numeric_limits; #endif From 06c2a2657f44b3f5eda745c4fd2edb223f3408da Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 Jan 2025 16:31:23 -0500 Subject: [PATCH 136/140] Fix macro naming for format --- examples/format.cpp | 2 +- include/boost/decimal/format.hpp | 2 +- test/test_format.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/format.cpp b/examples/format.cpp index da14a682..6a7f7f7f 100644 --- a/examples/format.cpp +++ b/examples/format.cpp @@ -11,7 +11,7 @@ #include #include -#ifdef BOOST_CRYPT_HAS_FORMAT_SUPPORT +#ifdef BOOST_DECIMAL_HAS_FORMAT_SUPPORT #include diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index b7246692..3ec1eea1 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -9,7 +9,7 @@ #if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && !defined(BOOST_DECIMAL_DISABLE_CLIB) && \ ((defined(__GNUC__) && __GNUC__ >= 13) || (defined(__clang__) && __clang_major__ >= 18) || (defined(_MSC_VER) && _MSC_VER >= 1940)) -#define BOOST_CRYPT_HAS_FORMAT_SUPPORT +#define BOOST_DECIMAL_HAS_FORMAT_SUPPORT #include #include diff --git a/test/test_format.cpp b/test/test_format.cpp index b4cc9710..3fc19cd9 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -14,7 +14,7 @@ using namespace boost::decimal; -#ifdef BOOST_CRYPT_HAS_FORMAT_SUPPORT +#ifdef BOOST_DECIMAL_HAS_FORMAT_SUPPORT template void test_general() From c4ce792504c10e7710af957e7933f0fcc1961ee4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 Jan 2025 08:50:27 -0500 Subject: [PATCH 137/140] Add uppercase non-finite values testing --- test/test_format.cpp | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/test/test_format.cpp b/test/test_format.cpp index 3fc19cd9..ad78a99c 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -16,7 +16,7 @@ using namespace boost::decimal; #ifdef BOOST_DECIMAL_HAS_FORMAT_SUPPORT -template +template void test_general() { // For unknown reasons Clang does not like this empty bracket and throws compiler errors @@ -82,6 +82,13 @@ void test_general() BOOST_TEST_EQ(std::format("{:g}", -std::numeric_limits::quiet_NaN()), "-nan(ind)"); BOOST_TEST_EQ(std::format("{:g}", std::numeric_limits::signaling_NaN()), "nan(snan)"); BOOST_TEST_EQ(std::format("{:g}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); + + BOOST_TEST_EQ(std::format("{:G}", std::numeric_limits::infinity()), "INF"); + BOOST_TEST_EQ(std::format("{:G}", -std::numeric_limits::infinity()), "-INF"); + BOOST_TEST_EQ(std::format("{:G}", std::numeric_limits::quiet_NaN()), "NAN"); + BOOST_TEST_EQ(std::format("{:G}", -std::numeric_limits::quiet_NaN()), "-NAN(IND)"); + BOOST_TEST_EQ(std::format("{:G}", std::numeric_limits::signaling_NaN()), "NAN(SNAN)"); + BOOST_TEST_EQ(std::format("{:G}", -std::numeric_limits::signaling_NaN()), "-NAN(SNAN)"); } template @@ -106,6 +113,13 @@ void test_fixed() BOOST_TEST_EQ(std::format("{:f}", -std::numeric_limits::quiet_NaN()), "-nan(ind)"); BOOST_TEST_EQ(std::format("{:f}", std::numeric_limits::signaling_NaN()), "nan(snan)"); BOOST_TEST_EQ(std::format("{:f}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); + + BOOST_TEST_EQ(std::format("{:F}", std::numeric_limits::infinity()), "INF"); + BOOST_TEST_EQ(std::format("{:F}", -std::numeric_limits::infinity()), "-INF"); + BOOST_TEST_EQ(std::format("{:F}", std::numeric_limits::quiet_NaN()), "NAN"); + BOOST_TEST_EQ(std::format("{:F}", -std::numeric_limits::quiet_NaN()), "-NAN(IND)"); + BOOST_TEST_EQ(std::format("{:F}", std::numeric_limits::signaling_NaN()), "NAN(SNAN)"); + BOOST_TEST_EQ(std::format("{:F}", -std::numeric_limits::signaling_NaN()), "-NAN(SNAN)"); } template @@ -127,6 +141,13 @@ void test_scientific() BOOST_TEST_EQ(std::format("{:e}", std::numeric_limits::signaling_NaN()), "nan(snan)"); BOOST_TEST_EQ(std::format("{:e}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); + BOOST_TEST_EQ(std::format("{:E}", std::numeric_limits::infinity()), "INF"); + BOOST_TEST_EQ(std::format("{:E}", -std::numeric_limits::infinity()), "-INF"); + BOOST_TEST_EQ(std::format("{:E}", std::numeric_limits::quiet_NaN()), "NAN"); + BOOST_TEST_EQ(std::format("{:E}", -std::numeric_limits::quiet_NaN()), "-NAN(IND)"); + BOOST_TEST_EQ(std::format("{:E}", std::numeric_limits::signaling_NaN()), "NAN(SNAN)"); + BOOST_TEST_EQ(std::format("{:E}", -std::numeric_limits::signaling_NaN()), "-NAN(SNAN)"); + // Padding to the front BOOST_TEST_EQ(std::format("{:10.1E}", T {0}), " 0.0E+00"); BOOST_TEST_EQ(std::format("{:10.3E}", T {0}), " 0.000E+00"); @@ -143,6 +164,13 @@ void test_hex() BOOST_TEST_EQ(std::format("{:a}", -std::numeric_limits::quiet_NaN()), "-nan(ind)"); BOOST_TEST_EQ(std::format("{:a}", std::numeric_limits::signaling_NaN()), "nan(snan)"); BOOST_TEST_EQ(std::format("{:a}", -std::numeric_limits::signaling_NaN()), "-nan(snan)"); + + BOOST_TEST_EQ(std::format("{:A}", std::numeric_limits::infinity()), "INF"); + BOOST_TEST_EQ(std::format("{:A}", -std::numeric_limits::infinity()), "-INF"); + BOOST_TEST_EQ(std::format("{:A}", std::numeric_limits::quiet_NaN()), "NAN"); + BOOST_TEST_EQ(std::format("{:A}", -std::numeric_limits::quiet_NaN()), "-NAN(IND)"); + BOOST_TEST_EQ(std::format("{:A}", std::numeric_limits::signaling_NaN()), "NAN(SNAN)"); + BOOST_TEST_EQ(std::format("{:A}", -std::numeric_limits::signaling_NaN()), "-NAN(SNAN)"); } int main() From 6a17cd5fe907a74e4dc78dd3dece54ada7557583 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 Jan 2025 08:50:39 -0500 Subject: [PATCH 138/140] Fix :F capitalization --- include/boost/decimal/format.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index 3ec1eea1..b9739eb5 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -70,6 +70,7 @@ constexpr auto parse_impl(ParseContext &ctx) break; case 'F': + is_upper = true; [[fallthrough]]; case 'f': fmt = chars_format::fixed; From 38d91c44bffaf42dc5d1b4fe042a20141f3f807e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 Jan 2025 08:55:14 -0500 Subject: [PATCH 139/140] Move warning suppression --- examples/format.cpp | 6 ------ include/boost/decimal/format.hpp | 9 +++++++++ test/test_format.cpp | 6 ------ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/examples/format.cpp b/examples/format.cpp index 6a7f7f7f..0d69040a 100644 --- a/examples/format.cpp +++ b/examples/format.cpp @@ -2,12 +2,6 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -// MSVC 14.3 has a conversion error in so we need to try and supress that everywhere -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4244) -#endif - #include #include diff --git a/include/boost/decimal/format.hpp b/include/boost/decimal/format.hpp index b9739eb5..6ecd2306 100644 --- a/include/boost/decimal/format.hpp +++ b/include/boost/decimal/format.hpp @@ -143,9 +143,18 @@ struct formatter if (is_upper) { + #ifdef _MSC_VER + # pragma warning(push) + # pragma warning(disable : 4244) + #endif + std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::toupper(c); }); + + #ifdef _MSC_VER + # pragma warning(pop) + #endif } if (s.size() < static_cast(padding_digits)) diff --git a/test/test_format.cpp b/test/test_format.cpp index ad78a99c..2cde83a5 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -2,12 +2,6 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -// MSVC 14.3 has a conversion error in so we need to try and supress that everywhere -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4244) -#endif - #include #include #include From 7df9c215bd3c4cece3f5e8cdc215c952b48f3ea2 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 Jan 2025 09:02:11 -0500 Subject: [PATCH 140/140] Fix quantexp return type in docs --- doc/decimal/cmath.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/decimal/cmath.adoc b/doc/decimal/cmath.adoc index 5fef1661..b874fb8c 100644 --- a/doc/decimal/cmath.adoc +++ b/doc/decimal/cmath.adoc @@ -406,9 +406,9 @@ If exactly one operand is infinity or exactly one operand is NaN, they do not ha template constexpr int quantexp(Decimal x) noexcept; -constexpr bool quantexp32(decimal32 x) noexcept; -constexpr bool quantexp64(decimal64 x) noexcept; -constexpr bool quantexp128(decimal128 x) noexcept; +constexpr int quantexp32(decimal32 x) noexcept; +constexpr int quantexp64(decimal64 x) noexcept; +constexpr int quantexp128(decimal128 x) noexcept; ---- Effects: if x is finite, returns its quantum exponent.