From b53d18370dd7b1ca2a09c9ed2ad5942ea6e544f6 Mon Sep 17 00:00:00 2001 From: ckormanyos Date: Mon, 6 Jan 2025 09:05:54 +0100 Subject: [PATCH 1/4] Syntax and temporary verification code --- .../boost/multiprecision/cpp_double_fp.hpp | 41 ++++++++----------- test/test_pow.cpp | 1 + 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/include/boost/multiprecision/cpp_double_fp.hpp b/include/boost/multiprecision/cpp_double_fp.hpp index b8e1ccb80..2f9c9b96b 100644 --- a/include/boost/multiprecision/cpp_double_fp.hpp +++ b/include/boost/multiprecision/cpp_double_fp.hpp @@ -195,8 +195,7 @@ class cpp_double_fp_backend // TBD: Did we justify this static assertion during the GSoC? // Does anyone remember what the meaning of the number 77 is? - static_assert(((my_max_exponent - my_digits) >= 77), - "Error: floating-point constituent does not have wide enough exponent range"); + static_assert(((my_max_exponent - my_digits) >= 77), "Error: floating-point constituent does not have wide enough exponent range"); // Default constructor. constexpr cpp_double_fp_backend() noexcept { } @@ -316,7 +315,7 @@ class cpp_double_fp_backend // Assignment operator from another kind of cpp_double_fp_backend<> object. template ::value + typename ::std::enable_if<( cpp_df_qf_detail::is_floating_point::value && (!std::is_same::value))>::type const* = nullptr> constexpr cpp_double_fp_backend& operator=(const cpp_double_fp_backend& other) { @@ -352,9 +351,9 @@ class cpp_double_fp_backend const std::string str_to_hash { str(cpp_double_fp_backend::my_digits10, std::ios::scientific) }; - auto result = static_cast(UINT8_C(0)); + std::size_t result { UINT8_C(0) }; - for (auto i = static_cast(UINT8_C(0)); i < str_to_hash.length(); ++i) + for (std::size_t i = std::size_t { UINT8_C(0) }; i < str_to_hash.length(); ++i) { boost::multiprecision::detail::hash_combine(result, str_to_hash.at(i)); } @@ -363,20 +362,11 @@ class cpp_double_fp_backend } // Methods - constexpr bool isneg_unchecked() const noexcept - { - return (data.first < 0); - } + constexpr bool isneg_unchecked() const noexcept { return (data.first < 0); } - constexpr bool iszero_unchecked() const noexcept - { - return (data.first == float_type { 0.0F }); - } + constexpr bool iszero_unchecked() const noexcept { return (data.first == float_type { 0.0F }); } - constexpr bool is_one() const noexcept - { - return ((data.first == float_type { 1.0F }) && (data.second == float_type { 0.0F })); - } + constexpr bool is_one() const noexcept { return ((data.second == float_type { 0.0F }) && (data.first == float_type { 1.0F })); } constexpr void negate() { @@ -818,14 +808,17 @@ class cpp_double_fp_backend constexpr cpp_double_fp_backend& operator++() { return *this += cpp_double_fp_backend(float_type(1.0F)); } constexpr cpp_double_fp_backend& operator--() { return *this -= cpp_double_fp_backend(float_type(1.0F)); } + // Unare minus operator. constexpr cpp_double_fp_backend operator-() const { cpp_double_fp_backend v(*this); + v.negate(); + return v; } - // Helper functions + // Helper functions. constexpr static cpp_double_fp_backend pown(const cpp_double_fp_backend& x, int p) { using local_float_type = cpp_double_fp_backend; @@ -879,7 +872,7 @@ class cpp_double_fp_backend { if (this != &other) { - const rep_type tmp = data; + const rep_type tmp { data }; data = other.data; @@ -889,7 +882,7 @@ class cpp_double_fp_backend constexpr void swap(cpp_double_fp_backend&& other) noexcept { - const rep_type tmp = data; + const rep_type tmp { static_cast(data) }; data = other.data; @@ -1493,13 +1486,13 @@ constexpr void eval_exp(cpp_double_fp_backend& result, const if (fpc == FP_ZERO) { - result = double_float_type(1); + result = double_float_type { 1.0F }; } else if (fpc != FP_NORMAL) { if (fpc == FP_INFINITE) { - result = (x.isneg_unchecked() ? double_float_type(0) : double_float_type::my_value_inf()); + result = (x.isneg_unchecked() ? double_float_type { 0.0F } : double_float_type::my_value_inf()); } else if (fpc == FP_NAN) { @@ -1599,7 +1592,7 @@ constexpr void eval_exp(cpp_double_fp_backend& result, const const double_float_type n840(840); const double_float_type n42(42); - const double_float_type r2 = r * r; + const double_float_type r2 { r * r }; result = double_float_type(1U) + ((n84 * r) * (n7920 + r2 * (n240 + r2))) / (n665280 + r * (-n332640 + r * (n75600 + r * (-n10080 + r * (n840 + (-n42 + r) * r))))); @@ -1754,7 +1747,7 @@ constexpr void eval_exp(cpp_double_fp_backend& result, const const double_float_type n2520(2520U); const double_float_type n72(72U); - const double_float_type r2 = r * r; + const double_float_type r2 { r * r }; const double_float_type top = (n144 * r) * (n3603600 + r2 * (n120120 + r2 * (n770 + r2))); const double_float_type bot = (n518918400 + r * (-n259459200 + r * (n60540480 + r * (-n8648640 + r * (n831600 + r * (-n55440 + r * (n2520 + r * (-n72 + r)))))))); diff --git a/test/test_pow.cpp b/test/test_pow.cpp index ba3aa4460..79916f83f 100644 --- a/test/test_pow.cpp +++ b/test/test_pow.cpp @@ -883,6 +883,7 @@ int main() test(); test(); #if defined(BOOST_HAS_FLOAT128) + #warning compiliation is here which is good as expected test(); #endif } From 47af435cf4b6c3b7e5fa86e04d3cf5a169d63891 Mon Sep 17 00:00:00 2001 From: ckormanyos Date: Mon, 6 Jan 2025 10:07:52 +0100 Subject: [PATCH 2/4] Add and modify df_gnu jobs for C++14/20 --- .github/workflows/multiprecision.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/multiprecision.yml b/.github/workflows/multiprecision.yml index 3d5bb0993..74c14a456 100644 --- a/.github/workflows/multiprecision.yml +++ b/.github/workflows/multiprecision.yml @@ -151,7 +151,7 @@ jobs: strategy: fail-fast: false matrix: - compiler: [ g++ ] + standard: [ gnu++14, gnu++20 ] suite: [ functions_df_gnu ] steps: - uses: actions/checkout@v4 @@ -191,7 +191,7 @@ jobs: run: ./b2 headers working-directory: ../boost-root - name: Generate user config - run: 'echo "using $TOOLSET : : ${{ matrix.compiler }} : -std=gnu++14 ;" > ~/user-config.jam' + run: 'echo "using $TOOLSET : : g++ : -std=${{ matrix.standard }} ;" > ~/user-config.jam' working-directory: ../boost-root - name: Config Info run: ../../../b2 print_config_info print_math_info toolset=$TOOLSET From 6646c47feaaf0fedd59103b1995e32a2a01e2e0b Mon Sep 17 00:00:00 2001 From: ckormanyos Date: Mon, 6 Jan 2025 10:43:08 +0100 Subject: [PATCH 3/4] Repair YAML typo in CI --- .github/workflows/multiprecision.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/multiprecision.yml b/.github/workflows/multiprecision.yml index 74c14a456..e41150d9c 100644 --- a/.github/workflows/multiprecision.yml +++ b/.github/workflows/multiprecision.yml @@ -158,7 +158,7 @@ jobs: with: fetch-depth: '0' - name: Set TOOLSET - run: echo ${{ matrix.compiler }} | awk '/^g/ { print "TOOLSET=gcc" } /^clang/ { print "TOOLSET=clang" }' >> $GITHUB_ENV + run: echo g++ | awk '/^g/ { print "TOOLSET=gcc" } /^clang/ { print "TOOLSET=clang" }' >> $GITHUB_ENV - name: Add repository continue-on-error: true id: addrepo @@ -234,7 +234,7 @@ jobs: if: steps.retry1.outcome=='failure' run: sudo apt-add-repository -y "ppa:ubuntu-toolchain-r/test" - name: Install packages - run: sudo apt install g++-10 g++-11 clang-10 clang-11 libgmp-dev libmpfr-dev libtommath-dev libeigen3-dev libmpfi-dev libmpc-dev + run: sudo apt install g++-9 g++-10 g++-11 clang-10 clang-11 libgmp-dev libmpfr-dev libtommath-dev libeigen3-dev libmpfi-dev libmpc-dev - name: Checkout main boost run: git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root - name: Update tools/boostdep From efcaaeecc4ea8a7f5394487b7bb3e5b5886ee93f Mon Sep 17 00:00:00 2001 From: ckormanyos Date: Mon, 6 Jan 2025 12:13:57 +0100 Subject: [PATCH 4/4] Optimize edge-case checks add/sub/mul/div --- .../boost/multiprecision/cpp_double_fp.hpp | 263 +++++++++--------- test/test_pow.cpp | 1 - 2 files changed, 136 insertions(+), 128 deletions(-) diff --git a/include/boost/multiprecision/cpp_double_fp.hpp b/include/boost/multiprecision/cpp_double_fp.hpp index 2f9c9b96b..e6b68fb08 100644 --- a/include/boost/multiprecision/cpp_double_fp.hpp +++ b/include/boost/multiprecision/cpp_double_fp.hpp @@ -405,43 +405,45 @@ class cpp_double_fp_backend constexpr cpp_double_fp_backend& operator+=(const cpp_double_fp_backend& v) { - const auto fpc_u = eval_fpclassify(*this); - const auto fpc_v = eval_fpclassify(v); - - const auto isnan_u = (fpc_u == FP_NAN); + const int fpc_u { eval_fpclassify(*this) }; + const int fpc_v { eval_fpclassify(v) }; - if (isnan_u) + if ((fpc_u != FP_NORMAL) || (fpc_v != FP_NORMAL)) { - return *this; - } - - const auto isinf_u = (fpc_u == FP_INFINITE); - const auto isinf_v = (fpc_v == FP_INFINITE); + // Handle special cases like zero, inf and NaN. - if (isinf_u) - { - if (isinf_v && (isneg_unchecked() != v.isneg_unchecked())) + if (fpc_u == FP_NAN) { - *this = cpp_double_fp_backend::my_value_nan(); + return *this; } - return *this; - } - - const auto iszero_u = ((fpc_u == FP_ZERO) || (fpc_u == FP_SUBNORMAL)); - const auto isnan_v = (fpc_v == FP_NAN); + const bool isinf_v { (fpc_v == FP_INFINITE) }; - if (iszero_u || (isnan_v || isinf_v)) - { - if (iszero_u) + if (fpc_u == FP_INFINITE) { - data.first = float_type { 0.0F }; - data.second = float_type { 0.0F }; + if (isinf_v && (isneg_unchecked() != v.isneg_unchecked())) + { + *this = cpp_double_fp_backend::my_value_nan(); + } + + return *this; } - const auto iszero_v = ((fpc_v == FP_ZERO) || (fpc_v == FP_SUBNORMAL)); + const bool iszero_u { ((fpc_u == FP_ZERO) || (fpc_u == FP_SUBNORMAL)) }; + const bool isnan_v { (fpc_v == FP_NAN) }; + + if (iszero_u || (isnan_v || isinf_v)) + { + if (iszero_u) + { + data.first = float_type { 0.0F }; + data.second = float_type { 0.0F }; + } + + const bool iszero_v { ((fpc_v == FP_ZERO) || (fpc_v == FP_SUBNORMAL)) }; - return ((!iszero_v) ? operator=(v) : *this); + return ((!iszero_v) ? operator=(v) : *this); + } } const float_type xlo { data.second }; @@ -459,42 +461,45 @@ class cpp_double_fp_backend constexpr cpp_double_fp_backend& operator-=(const cpp_double_fp_backend& v) { - const auto fpc_u = eval_fpclassify(*this); - const auto fpc_v = eval_fpclassify(v); - - const auto isnan_u = (fpc_u == FP_NAN); + const int fpc_u { eval_fpclassify(*this) }; + const int fpc_v { eval_fpclassify(v) }; - if (isnan_u) + if ((fpc_u != FP_NORMAL) || (fpc_v != FP_NORMAL)) { - return *this; - } + // Handle special cases like zero, inf and NaN. - const auto isinf_u = (fpc_u == FP_INFINITE); - const auto isinf_v = (fpc_v == FP_INFINITE); - - if (isinf_u) - { - if (isinf_v && (isneg_unchecked() == v.isneg_unchecked())) + if (fpc_u == FP_NAN) { - *this = cpp_double_fp_backend::my_value_nan(); + return *this; } - return *this; - } - const auto iszero_u = ((fpc_u == FP_ZERO) || (fpc_u == FP_SUBNORMAL)); - const auto isnan_v = (fpc_v == FP_NAN); + const bool isinf_v { (fpc_v == FP_INFINITE) }; - if (iszero_u || (isnan_v || isinf_v)) - { - if (iszero_u) + if (fpc_u == FP_INFINITE) { - data.first = float_type { 0.0F }; - data.second = float_type { 0.0F }; + if (isinf_v && (isneg_unchecked() == v.isneg_unchecked())) + { + *this = cpp_double_fp_backend::my_value_nan(); + } + + return *this; } - const auto iszero_v = ((fpc_v == FP_ZERO) || (fpc_v == FP_SUBNORMAL)); + const bool iszero_u { ((fpc_u == FP_ZERO) || (fpc_u == FP_SUBNORMAL)) }; + const bool isnan_v { (fpc_v == FP_NAN) }; + + if (iszero_u || (isnan_v || isinf_v)) + { + if (iszero_u) + { + data.first = float_type { 0.0F }; + data.second = float_type { 0.0F }; + } + + const bool iszero_v { ((fpc_v == FP_ZERO) || (fpc_v == FP_SUBNORMAL)) }; - return ((!iszero_v) ? operator=(-v) : *this); + return ((!iszero_v) ? operator=(-v) : *this); + } } if (this == &v) @@ -525,42 +530,43 @@ class cpp_double_fp_backend const int fpc_u { eval_fpclassify(*this) }; const int fpc_v { eval_fpclassify(v) }; - // Handle special cases like zero, inf and NaN. - const bool isinf_u { (fpc_u == FP_INFINITE) }; - const bool isinf_v { (fpc_v == FP_INFINITE) }; - const bool isnan_u { (fpc_u == FP_NAN) }; - const bool isnan_v { (fpc_v == FP_NAN) }; - const bool iszero_u { (fpc_u == FP_ZERO) }; - const bool iszero_v { (fpc_v == FP_ZERO) }; - - if ((isnan_u || isnan_v) || (isinf_u && iszero_v) || (isinf_v && iszero_u)) + if ((fpc_u != FP_NORMAL) || (fpc_v != FP_NORMAL)) { - return operator=( cpp_double_fp_backend::my_value_nan()); - } + // Handle special cases like zero, inf and NaN. + const bool isinf_u { (fpc_u == FP_INFINITE) }; + const bool isinf_v { (fpc_v == FP_INFINITE) }; + const bool iszero_u { (fpc_u == FP_ZERO) }; + const bool iszero_v { (fpc_v == FP_ZERO) }; - if (isinf_u || isinf_v) - { - const bool b_neg { (isneg_unchecked() != v.isneg_unchecked()) }; - - *this = cpp_double_fp_backend::my_value_inf(); - - if (b_neg) + if (((fpc_u == FP_NAN) || (fpc_v == FP_NAN)) || (isinf_u && iszero_v) || (isinf_v && iszero_u)) { - negate(); + return operator=( cpp_double_fp_backend::my_value_nan()); } - return *this; - } + if (isinf_u || isinf_v) + { + const bool b_neg { (isneg_unchecked() != v.isneg_unchecked()) }; - if (iszero_u || iszero_v) - { - const bool b_neg { (isneg_unchecked() != v.isneg_unchecked()) }; + *this = cpp_double_fp_backend::my_value_inf(); - operator=(cpp_double_fp_backend(0)); + if (b_neg) + { + negate(); + } - if (b_neg) { negate(); } + return *this; + } - return *this; + if (iszero_u || iszero_v) + { + const bool b_neg { (isneg_unchecked() != v.isneg_unchecked()) }; + + operator=(cpp_double_fp_backend(0)); + + if (b_neg) { negate(); } + + return *this; + } } // The multiplication algorithm has been taken from Victor Shoup, @@ -642,76 +648,79 @@ class cpp_double_fp_backend constexpr cpp_double_fp_backend& operator/=(const cpp_double_fp_backend& v) { - // Handle special cases like zero, inf and NaN. const int fpc_u { eval_fpclassify(*this) }; const int fpc_v { eval_fpclassify(v) }; - const bool isnan_u { (fpc_u == FP_NAN) }; - const bool isnan_v { (fpc_v == FP_NAN) }; - - if (isnan_u || isnan_v) - { - return operator=(cpp_double_fp_backend::my_value_nan()); - } - - const bool iszero_u { (fpc_u == FP_ZERO) }; - const bool iszero_v { (fpc_v == FP_ZERO) }; - - if (this == &v) + if ((fpc_u != FP_NORMAL) || (fpc_v != FP_NORMAL)) { - data.first = float_type { 1.0F }; - data.second = float_type { 0.0F }; - - return *this; - } + // Handle special cases like zero, inf and NaN. + const bool isnan_u { (fpc_u == FP_NAN) }; + const bool isnan_v { (fpc_v == FP_NAN) }; - if (iszero_u) - { - if (iszero_v) + if (isnan_u || isnan_v) { return operator=(cpp_double_fp_backend::my_value_nan()); } - else - { - return operator=(cpp_double_fp_backend(0)); - } - } - // Handle more special cases like zero, inf and NaN. - if (iszero_v) - { - const bool b_neg = isneg_unchecked(); + const bool iszero_u { (fpc_u == FP_ZERO) }; + const bool iszero_v { (fpc_v == FP_ZERO) }; - *this = cpp_double_fp_backend::my_value_inf(); + if (this == &v) + { + data.first = float_type { 1.0F }; + data.second = float_type { 0.0F }; - if (b_neg) + return *this; + } + + if (iszero_u) { - negate(); + if (iszero_v) + { + return operator=(cpp_double_fp_backend::my_value_nan()); + } + else + { + return operator=(cpp_double_fp_backend(0)); + } } - return *this; - } + // Handle more special cases like zero, inf and NaN. + if (iszero_v) + { + const bool b_neg = isneg_unchecked(); - const bool isinf_v { (fpc_v == FP_INFINITE) }; - const bool isinf_u { (fpc_u == FP_INFINITE) }; + *this = cpp_double_fp_backend::my_value_inf(); - if (isinf_u) - { - if (isinf_v) - { - return operator=(cpp_double_fp_backend::my_value_nan()); + if (b_neg) + { + negate(); + } + + return *this; } - else + + const bool isinf_v { (fpc_v == FP_INFINITE) }; + const bool isinf_u { (fpc_u == FP_INFINITE) }; + + if (isinf_u) { - const bool b_neg { isneg_unchecked() }; + if (isinf_v) + { + return operator=(cpp_double_fp_backend::my_value_nan()); + } + else + { + const bool b_neg { isneg_unchecked() }; - return operator=((!b_neg) ? cpp_double_fp_backend::my_value_inf() : -cpp_double_fp_backend::my_value_inf()); + return operator=((!b_neg) ? cpp_double_fp_backend::my_value_inf() : -cpp_double_fp_backend::my_value_inf()); + } } - } - if (isinf_v) - { - return operator=(cpp_double_fp_backend(0)); + if (isinf_v) + { + return operator=(cpp_double_fp_backend(0)); + } } // The division algorithm has been taken from Victor Shoup, diff --git a/test/test_pow.cpp b/test/test_pow.cpp index 79916f83f..ba3aa4460 100644 --- a/test/test_pow.cpp +++ b/test/test_pow.cpp @@ -883,7 +883,6 @@ int main() test(); test(); #if defined(BOOST_HAS_FLOAT128) - #warning compiliation is here which is good as expected test(); #endif }