diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index df4e36291..e2454fbb4 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 2921d1feb..2de21e4eb 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/cmath/fma.hpp b/include/boost/decimal/detail/cmath/fma.hpp index 4c04b4e7e..63319a6d1 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 + + int exp_lhs {}; + auto sig_lhs = frexp10(x, &exp_lhs); + + int exp_rhs {}; + auto sig_rhs = frexp10(y, &exp_rhs); + + 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, + // 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::d32_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 + +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 diff --git a/include/boost/decimal/detail/components.hpp b/include/boost/decimal/detail/components.hpp new file mode 100644 index 000000000..5b6738e0f --- /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 diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 29a698cfc..58b013ef1 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 @@ -24,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, 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, ReturnType> + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> ReturnType { using mul_type = std::uint_fast64_t; @@ -54,47 +44,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 diff --git a/include/boost/decimal/literals.hpp b/include/boost/decimal/literals.hpp index 73d55540f..7ae4e3987 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}; } diff --git a/test/test_big_uints.cpp b/test/test_big_uints.cpp index 99029e4ec..698314837 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"