From 0341b9be9547d327de0a32f57224d6fa83122e9c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 24 Apr 2024 08:25:53 +0200 Subject: [PATCH 1/6] Improve reliability of codecov upload --- .github/workflows/codecov.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 5c2a6ebb2..815d7627f 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -186,3 +186,15 @@ jobs: - name: Upload coverage if: matrix.coverage run: ci/codecov.sh "upload" + env: + BOOST_CI_CODECOV_IO_UPLOAD: skip + + - name: Upload coverage + if: matrix.coverage + uses: codecov/codecov-action@v4 + with: + disable_search: true + file: coverage.info + name: Github Actions + token: ${{secrets.CODECOV_TOKEN}} + verbose: true From 6cd292e368e7d83639ab266c55573d26dee32d24 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 24 Apr 2024 08:28:27 +0200 Subject: [PATCH 2/6] Split coverage into multiple runs like boost.math --- .github/workflows/codecov.yml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 815d7627f..77adb985e 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -40,9 +40,23 @@ jobs: matrix: include: - { name: Collect coverage 1, coverage: yes, - compiler: gcc-12, cxxstd: '20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '64', suite: 'github_ci_block_1' } + compiler: gcc-12, cxxstd: '20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '64', suite: 'arithmetic_tests' } - { name: Collect coverage 2, coverage: yes, - compiler: gcc-12, cxxstd: '20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '64', suite: 'github_ci_block_2' } + compiler: gcc-12, cxxstd: '20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '64', suite: 'cpp_int_tests' } + - { name: Collect coverage 3, coverage: yes, + compiler: gcc-12, cxxstd: '20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '64', suite: 'functions_and_limits' } + - { name: Collect coverage 4, coverage: yes, + compiler: gcc-12, cxxstd: '20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '64', suite: 'conversions' } + - { name: Collect coverage 5, coverage: yes, + compiler: gcc-12, cxxstd: '20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '64', suite: 'performance' } + - { name: Collect coverage 6, coverage: yes, + compiler: gcc-12, cxxstd: '20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '64', suite: 'misc' } + - { name: Collect coverage 7, coverage: yes, + compiler: gcc-12, cxxstd: '20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '64', suite: 'compile_fail' } + - { name: Collect coverage 8, coverage: yes, + compiler: gcc-12, cxxstd: '20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '64', suite: 'examples' } + - { name: Collect coverage 9, coverage: yes, + compiler: gcc-12, cxxstd: '20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '64', suite: 'concepts' } #timeout-minutes: 120 runs-on: ${{matrix.os}} From ea786494db78efdf178cbe36810f3326156e3347 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Fri, 3 May 2024 15:08:05 +0800 Subject: [PATCH 3/6] make sure eval_convert_to() do not terminate with super large number this change is a follow-up of d51f2e9dbb. it intends to address the exception thrown in a noexcept functon. a minimal reproducer looks like ```c++ int main() { std::string s = "32767456456456456456545678943512357658768763546575675"; boost::multiprecision::cpp_int num(s); std::cout << num.convert_to() << std::endl; } ``` since boost 1.79, the code above terminates like ``` Program returned: 139 Program stderr terminate called after throwing an instance of 'boost::wrapexcept' what(): Error in function float_next(float): Argument must be finite, but got inf Program terminated with signal: SIGSEGV ``` because `float_next_imp()` throws 'boost::wrapexcept' if the number is NAN of INF. and `eval_convert_to()` is marked as `noexcept(boost::multiprecision::detail::is_arithmetic::value && std::numeric_limits::has_infinity)`, but only `overflow_error` is ignored in the policy passed to `float_next()`. so, in this change, `std::domain_error` is ignored as well, so that ``num.convert_to()` returns a NaN in this case. Refs #553 Signed-off-by: Kefu Chai --- include/boost/multiprecision/cpp_int/misc.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/boost/multiprecision/cpp_int/misc.hpp b/include/boost/multiprecision/cpp_int/misc.hpp index cdae2f757..a8a764003 100644 --- a/include/boost/multiprecision/cpp_int/misc.hpp +++ b/include/boost/multiprecision/cpp_int/misc.hpp @@ -184,7 +184,9 @@ eval_convert_to(R* result, const cpp_int_backend inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value && !is_trivial_cpp_int >::value, void>::type -eval_convert_to(R* result, const cpp_int_backend& backend) noexcept(boost::multiprecision::detail::is_arithmetic::value && std::numeric_limits::has_infinity) +eval_convert_to(R* result, const cpp_int_backend& backend) noexcept(boost::multiprecision::detail::is_arithmetic::value && + (std::numeric_limits::has_infinity || + std::numeric_limits::has_quiet_NaN)) { BOOST_MP_FLOAT128_USING using std::ldexp; if (eval_is_zero(backend)) @@ -244,10 +246,11 @@ eval_convert_to(R* result, const cpp_int_backend(bits)) || eval_bit_test(backend, static_cast(bits + 1))) { #ifdef BOOST_MP_MATH_AVAILABLE - BOOST_IF_CONSTEXPR(std::numeric_limits::has_infinity) + BOOST_IF_CONSTEXPR(std::numeric_limits::has_infinity || std::numeric_limits::has_quiet_NaN) { // Must NOT throw: - *result = boost::math::float_next(*result, boost::math::policies::make_policy(boost::math::policies::overflow_error())); + *result = boost::math::float_next(*result, boost::math::policies::make_policy(boost::math::policies::overflow_error(), + boost::math::policies::domain_error())); } else { From f9fdcc2b31a01c8e8dc6253339ef223d349a43a2 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Sat, 15 Jun 2024 16:05:42 +0100 Subject: [PATCH 4/6] Correct sinc implementations to match latest Boost.Math. --- .../multiprecision/detail/default_ops.hpp | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/include/boost/multiprecision/detail/default_ops.hpp b/include/boost/multiprecision/detail/default_ops.hpp index 57ca234f7..bd0240aba 100644 --- a/include/boost/multiprecision/detail/default_ops.hpp +++ b/include/boost/multiprecision/detail/default_ops.hpp @@ -3980,41 +3980,46 @@ ilogb(const detail::expression& val) } //namespace multiprecision namespace math { + + // // Overload of Boost.Math functions that find the wrong overload when used with number: // namespace detail { + template T sinc_pi_imp(T); -template -T sinhc_pi_imp(T); +template +T sinhc_pi_imp(T, const Policy&); + } // namespace detail + template inline multiprecision::number sinc_pi(const multiprecision::number& x) { boost::multiprecision::detail::scoped_default_precision > precision_guard(x); - return std::move(detail::sinc_pi_imp(x)); + return detail::sinc_pi_imp(x); } template inline multiprecision::number sinc_pi(const multiprecision::number& x, const Policy&) { boost::multiprecision::detail::scoped_default_precision > precision_guard(x); - return std::move(detail::sinc_pi_imp(x)); + return detail::sinc_pi_imp(x); } template inline multiprecision::number sinhc_pi(const multiprecision::number& x) { boost::multiprecision::detail::scoped_default_precision > precision_guard(x); - return std::move(detail::sinhc_pi_imp(x)); + return detail::sinhc_pi_imp(x, boost::math::policies::policy<>()); } template -inline multiprecision::number sinhc_pi(const multiprecision::number& x, const Policy&) +inline multiprecision::number sinhc_pi(const multiprecision::number& x, const Policy& pol) { - boost::multiprecision::detail::scoped_default_precision > precision_guard(x); - return std::move(boost::math::sinhc_pi(x)); + boost::multiprecision::detail::scoped_default_precision > precision_guard(x, pol); + return detail::sinhc_pi_imp(x, pol); } using boost::multiprecision::gcd; From 58b396288e20883f527c6da6bb4f45edbdeb958b Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Fri, 21 Jun 2024 17:14:54 +0100 Subject: [PATCH 5/6] Correct divide-by-zero in cpp_int modulus operations. (#625) Correct divide-by-zero in cpp_int modulus operations. Also added some more efficient operator overloads for the trivial case. Fixes https://github.com/boostorg/multiprecision/issues/624 --- .../boost/multiprecision/cpp_int/divide.hpp | 42 +++++++++++++++++++ test/Jamfile.v2 | 1 + test/git_issue_624.cpp | 36 ++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 test/git_issue_624.cpp diff --git a/include/boost/multiprecision/cpp_int/divide.hpp b/include/boost/multiprecision/cpp_int/divide.hpp index 136facea4..50d8aa9f1 100644 --- a/include/boost/multiprecision/cpp_int/divide.hpp +++ b/include/boost/multiprecision/cpp_int/divide.hpp @@ -551,6 +551,10 @@ eval_modulus( const cpp_int_backend& a, const limb_type mod) { + + if(mod == 0) + BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero.")); + const std::ptrdiff_t n = static_cast(a.size()); const double_limb_type two_n_mod = @@ -656,6 +660,44 @@ eval_modulus( result.sign(result.sign()); } +template +BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + is_trivial_cpp_int >::value && std::is_unsigned::value>::type +eval_modulus( + cpp_int_backend& result, + const cpp_int_backend& a, + V o) +{ + using local_limb_type = typename cpp_int_backend::local_limb_type; + + BOOST_IF_CONSTEXPR(std::numeric_limits::digits > MaxBits1) + { + if (o >= (static_cast(1u) << MaxBits1)) + { + // Modulus is larger than any value that the result can hold, + // so the result is just "a": + result = a; + return; + } + } + if (!o) + BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero.")); + *result.limbs() = *a.limbs() % static_cast(o); + result.sign(a.sign()); +} + +template +BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + is_trivial_cpp_int >::value && std::is_signed::value>::type +eval_modulus( + cpp_int_backend& result, + const cpp_int_backend& a, + V o) +{ + using unsigned_type = typename std::make_unsigned::type; + eval_modulus(result, a, static_cast(o < 0 ? -o : o)); +} + }}} // namespace boost::multiprecision::backends #endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 3e490a13c..41c5366c3 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1241,6 +1241,7 @@ test-suite misc : TEST_CPP_DEC_FLOAT TEST_CPP_BIN_FLOAT ] [ compile git_issue_608.cpp ] + [ run git_issue_624.cpp ] [ compile git_issue_98.cpp : [ check-target-builds ../config//has_float128 : TEST_FLOAT128 quadmath : ] [ check-target-builds ../config//has_gmp : TEST_GMP gmp : ] diff --git a/test/git_issue_624.cpp b/test/git_issue_624.cpp new file mode 100644 index 000000000..5e4279cc0 --- /dev/null +++ b/test/git_issue_624.cpp @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2024 John Maddock. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include "test.hpp" + +template +void test_divide_by_zero() +{ + T val = 42; + + BOOST_CHECK_THROW(val % 0, std::overflow_error); + BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); + BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); + BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); + + val = -val; + BOOST_CHECK_THROW(val % 0, std::overflow_error); + BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); + BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); + BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); +} + +int main() +{ + using int64_t = boost::multiprecision::number>; + + test_divide_by_zero(); + test_divide_by_zero(); + test_divide_by_zero(); + test_divide_by_zero(); +} + From c0ff9cffda8c064c6978f3e5df44a5b46046c241 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Mon, 24 Jun 2024 09:12:03 +0100 Subject: [PATCH 6/6] Ensure checked integers are in a sane state after a throw. (#627) Ensure checked integers are in a sane state after a throw. Document that the value of the target operand is unspecified after a throw. Improve testing. Fixes https://github.com/boostorg/multiprecision/issues/626 --- .../boost_multiprecision/indexes/s01.html | 2 +- .../boost_multiprecision/indexes/s02.html | 2 +- .../boost_multiprecision/indexes/s03.html | 2 +- .../boost_multiprecision/indexes/s04.html | 2 +- .../tut/ints/cpp_int.html | 10 +++ doc/tutorial_cpp_int.qbk | 2 + include/boost/multiprecision/cpp_int.hpp | 16 +++- test/Jamfile.v2 | 1 + test/git_issue_624.cpp | 64 +++++++++++++--- test/git_issue_626.cpp | 75 +++++++++++++++++++ 10 files changed, 161 insertions(+), 15 deletions(-) create mode 100644 test/git_issue_626.cpp diff --git a/doc/html/boost_multiprecision/indexes/s01.html b/doc/html/boost_multiprecision/indexes/s01.html index 6362e405d..6c83749f3 100644 --- a/doc/html/boost_multiprecision/indexes/s01.html +++ b/doc/html/boost_multiprecision/indexes/s01.html @@ -25,7 +25,7 @@

-Function Index

+Function Index

A B C D E F G H I L M N O P R S T V X Z

diff --git a/doc/html/boost_multiprecision/indexes/s02.html b/doc/html/boost_multiprecision/indexes/s02.html index a7d2cbf20..9c0c6082b 100644 --- a/doc/html/boost_multiprecision/indexes/s02.html +++ b/doc/html/boost_multiprecision/indexes/s02.html @@ -25,7 +25,7 @@

-Class Index

+Class Index

C D E F G I L M N R T

diff --git a/doc/html/boost_multiprecision/indexes/s03.html b/doc/html/boost_multiprecision/indexes/s03.html index 71f0a6725..296114be6 100644 --- a/doc/html/boost_multiprecision/indexes/s03.html +++ b/doc/html/boost_multiprecision/indexes/s03.html @@ -25,7 +25,7 @@

-Typedef Index

+Typedef Index

diff --git a/doc/html/boost_multiprecision/indexes/s04.html b/doc/html/boost_multiprecision/indexes/s04.html index 2cf41da4b..5f11954b0 100644 --- a/doc/html/boost_multiprecision/indexes/s04.html +++ b/doc/html/boost_multiprecision/indexes/s04.html @@ -24,7 +24,7 @@

-Index

+Index

A B C D E F G H I L M N O P R S T V X Z

diff --git a/doc/html/boost_multiprecision/tut/ints/cpp_int.html b/doc/html/boost_multiprecision/tut/ints/cpp_int.html index 7875d24f8..9a3b71f34 100644 --- a/doc/html/boost_multiprecision/tut/ints/cpp_int.html +++ b/doc/html/boost_multiprecision/tut/ints/cpp_int.html @@ -242,6 +242,16 @@
+
+ + + + + +
[Note]Note

+ When an exception is thrown as a result of using a checked type, then + the value of the target operand after the exception is caught is unspecified. +

Things you should know when using this type:

diff --git a/doc/tutorial_cpp_int.qbk b/doc/tutorial_cpp_int.qbk index d11dbf214..449229474 100644 --- a/doc/tutorial_cpp_int.qbk +++ b/doc/tutorial_cpp_int.qbk @@ -107,6 +107,8 @@ result from treating the unsigned type as a 2's complement signed type.]] that would result from performing the operation on a 2's complement integer type.]] ] +[note When an exception is thrown as a result of using a checked type, then the value of the target operand after the exception is caught is unspecified.] + Things you should know when using this type: * Default constructed `cpp_int_backend`s have the value zero. diff --git a/include/boost/multiprecision/cpp_int.hpp b/include/boost/multiprecision/cpp_int.hpp index f0dad5a13..efcf50cad 100644 --- a/include/boost/multiprecision/cpp_int.hpp +++ b/include/boost/multiprecision/cpp_int.hpp @@ -844,10 +844,17 @@ struct cpp_int_base BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void normalize() noexcept((Checked == unchecked)) { limb_pointer p = limbs(); - detail::verify_limb_mask(m_limbs == internal_limb_count, p[internal_limb_count - 1], upper_limb_mask, checked_type()); + + limb_type c = p[internal_limb_count - 1]; + bool full_limbs = m_limbs == internal_limb_count; + p[internal_limb_count - 1] &= upper_limb_mask; while ((m_limbs - 1) && !p[m_limbs - 1]) --m_limbs; + // + // Verification at the end, so that we're in a valid state if we throw: + // + detail::verify_limb_mask(full_limbs, c, upper_limb_mask, checked_type()); } BOOST_MP_FORCEINLINE constexpr cpp_int_base() noexcept @@ -1264,8 +1271,13 @@ struct cpp_int_base } BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void normalize() noexcept((Checked == unchecked)) { - detail::verify_limb_mask(true, m_data, limb_mask, checked_type()); + local_limb_type c = m_data; m_data &= limb_mask; + // + // Verification has to come afterwards, otherwise we can leave + // ourselves in an invalid state: + // + detail::verify_limb_mask(true, c, limb_mask, checked_type()); } BOOST_MP_FORCEINLINE constexpr cpp_int_base() noexcept : m_data(0) {} diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 41c5366c3..3cf84c0d2 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1242,6 +1242,7 @@ test-suite misc : TEST_CPP_BIN_FLOAT ] [ compile git_issue_608.cpp ] [ run git_issue_624.cpp ] + [ run git_issue_626.cpp ] [ compile git_issue_98.cpp : [ check-target-builds ../config//has_float128 : TEST_FLOAT128 quadmath : ] [ check-target-builds ../config//has_gmp : TEST_GMP gmp : ] diff --git a/test/git_issue_624.cpp b/test/git_issue_624.cpp index 5e4279cc0..c823b20cf 100644 --- a/test/git_issue_624.cpp +++ b/test/git_issue_624.cpp @@ -7,30 +7,76 @@ #include #include "test.hpp" +template +void test_neg_divide_by_zero(std::true_type const&) +{ + T val = -42; + BOOST_CHECK_THROW(static_cast(val % 0), std::overflow_error); + BOOST_CHECK_THROW(static_cast(val % static_cast(0)), std::overflow_error); + BOOST_CHECK_THROW(static_cast(val % static_cast(0)), std::overflow_error); + BOOST_CHECK_THROW(static_cast(val % static_cast(0)), std::overflow_error); +} +template +void test_neg_divide_by_zero(std::false_type const&) +{ +} + template void test_divide_by_zero() { T val = 42; - BOOST_CHECK_THROW(val % 0, std::overflow_error); - BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); - BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); - BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); + BOOST_CHECK_THROW(static_cast(val % 0), std::overflow_error); + BOOST_CHECK_THROW(static_cast(val % static_cast(0)), std::overflow_error); + BOOST_CHECK_THROW(static_cast(val % static_cast(0)), std::overflow_error); + BOOST_CHECK_THROW(static_cast(val % static_cast(0)), std::overflow_error); + + BOOST_IF_CONSTEXPR((std::numeric_limits::digits < 500) && std::numeric_limits::digits) + { + val <<= std::numeric_limits::digits - 10; + } + else + val <<= 500; - val = -val; - BOOST_CHECK_THROW(val % 0, std::overflow_error); - BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); - BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); - BOOST_CHECK_THROW(val % static_cast(0), std::overflow_error); + BOOST_CHECK_THROW(static_cast(val % 0), std::overflow_error); + BOOST_CHECK_THROW(static_cast(val % static_cast(0)), std::overflow_error); + BOOST_CHECK_THROW(static_cast(val % static_cast(0)), std::overflow_error); + BOOST_CHECK_THROW(static_cast(val % static_cast(0)), std::overflow_error); + + using tag_type = std::integral_constant::is_signed>; + + test_neg_divide_by_zero(tag_type()); } int main() { using int64_t = boost::multiprecision::number>; + using uint64_t = boost::multiprecision::number>; + using checked_int64_t = boost::multiprecision::number>; + using checked_uint64_t = boost::multiprecision::number>; test_divide_by_zero(); test_divide_by_zero(); test_divide_by_zero(); test_divide_by_zero(); + + test_divide_by_zero(); + test_divide_by_zero(); + test_divide_by_zero(); + test_divide_by_zero(); + + test_divide_by_zero(); + test_divide_by_zero(); + test_divide_by_zero(); + test_divide_by_zero(); + + test_divide_by_zero(); + test_divide_by_zero(); + test_divide_by_zero(); + test_divide_by_zero(); + + test_divide_by_zero(); + + return boost::report_errors(); } diff --git a/test/git_issue_626.cpp b/test/git_issue_626.cpp new file mode 100644 index 000000000..70b3ef0d6 --- /dev/null +++ b/test/git_issue_626.cpp @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2024 John Maddock. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include "test.hpp" + +template +void test_subtract_underflow() +{ + T val = 42; + + int sub = 43; + + BOOST_CHECK_THROW(static_cast(val - sub), std::range_error); + BOOST_CHECK_THROW(static_cast(val - static_cast(sub)), std::range_error); + BOOST_CHECK_THROW(static_cast(val - static_cast(sub)), std::range_error); + BOOST_CHECK_THROW(static_cast(val - static_cast(sub)), std::range_error); + + BOOST_IF_CONSTEXPR((std::numeric_limits::digits < 500) && std::numeric_limits::digits) + { + val <<= std::numeric_limits::digits - 10; + } + else + val <<= 500; + + T sub2 = val + 1; + + BOOST_CHECK_THROW(static_cast(val - sub2), std::range_error); +} + +template +void test_overflow() { + using uint_t = boost::multiprecision::number>; + + uint_t value = (std::numeric_limits::max)(); + BOOST_CHECK_THROW(value += 1, std::overflow_error); + // + // We don't care what the value is, but it must be sane and normalized + // to be within the range of the type under test: + // + BOOST_CHECK(value <= (std::numeric_limits::max)()); +} + +template +struct TestOverflow { + static void run() { + test_overflow(); + TestOverflow::run(); + } +}; + +template <> +struct TestOverflow<1032> { + static void run() {} +}; + + + +int main() +{ + using checked_uint64_t = boost::multiprecision::number>; + + test_subtract_underflow(); + test_subtract_underflow(); + test_subtract_underflow(); + test_subtract_underflow(); + + TestOverflow<8>::run(); + + return boost::report_errors(); +} +