/////////////////////////////////////////////////////////////// // Copyright 2012 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 // // Compare arithmetic results using fixed_int to GMP results. // #ifdef _MSC_VER #define _SCL_SECURE_NO_WARNINGS #endif #include #include "test.hpp" #include #include template T generate_random(unsigned bits_wanted) { static boost::random::mt19937 gen; typedef boost::random::mt19937::result_type random_type; T max_val; unsigned digits; if (std::numeric_limits::is_bounded && (bits_wanted == (unsigned)std::numeric_limits::digits)) { max_val = (std::numeric_limits::max)(); digits = std::numeric_limits::digits; } else { max_val = T(1) << bits_wanted; digits = bits_wanted; } unsigned bits_per_r_val = std::numeric_limits::digits - 1; while ((random_type(1) << bits_per_r_val) > (gen.max)()) --bits_per_r_val; unsigned terms_needed = digits / bits_per_r_val + 1; T val = 0; for (unsigned i = 0; i < terms_needed; ++i) { val *= (gen.max)(); val += gen(); } val %= max_val; return val; } template void test_signed_overflow(Number a, Number b, const boost::mpl::true_&) { a = -a; BOOST_CHECK_THROW(Number(a * b), std::overflow_error); ++a; BOOST_CHECK(Number(a * b) >= (std::numeric_limits::min)()); } template void test_signed_overflow(Number, Number, const boost::mpl::false_&) { } template void test() { using namespace boost::multiprecision; typedef Number test_type; if (std::numeric_limits::is_bounded) { test_type val = (std::numeric_limits::max)(); #ifndef BOOST_NO_EXCEPTIONS BOOST_CHECK_THROW(++val, std::overflow_error); val = (std::numeric_limits::max)(); BOOST_CHECK_THROW(test_type(1 + val), std::overflow_error); BOOST_CHECK_THROW(test_type(val + 1), std::overflow_error); BOOST_CHECK_THROW(test_type(2 * val), std::overflow_error); val /= 2; val += 1; BOOST_CHECK_THROW(test_type(2 * val), std::overflow_error); if (std::numeric_limits::is_signed) { val = (std::numeric_limits::min)(); BOOST_CHECK_THROW(--val, std::overflow_error); val = (std::numeric_limits::min)(); BOOST_CHECK_THROW(test_type(val - 1), std::overflow_error); BOOST_CHECK_THROW(test_type(2 * val), std::overflow_error); val /= 2; val -= 1; BOOST_CHECK_THROW(test_type(2 * val), std::overflow_error); } else { val = (std::numeric_limits::min)(); BOOST_CHECK_THROW(--val, std::range_error); val = (std::numeric_limits::min)(); BOOST_CHECK_THROW(test_type(val - 1), std::range_error); } #endif // // Test overflow in random values: // for (unsigned bits = 30; bits < std::numeric_limits::digits; bits += 30) { for (unsigned i = 0; i < 100; ++i) { val = static_cast(generate_random(bits)); test_type val2 = 1 + (std::numeric_limits::max)() / val; BOOST_CHECK_THROW(test_type(val2 * val), std::overflow_error); test_signed_overflow(val2, val, boost::mpl::bool_::is_signed>()); --val2; BOOST_CHECK(cpp_int(val2) * cpp_int(val) <= cpp_int((std::numeric_limits::max)())); BOOST_CHECK(val2 * val <= (std::numeric_limits::max)()); val2 = (std::numeric_limits::max)() - val; ++val2; BOOST_CHECK_THROW(test_type(val2 + val), std::overflow_error); BOOST_CHECK((val2 - 1) + val == (std::numeric_limits::max)()); if (std::numeric_limits::is_signed) { val2 = (std::numeric_limits::min)() + val; --val2; BOOST_CHECK_THROW(test_type(val2 - val), std::overflow_error); ++val2; BOOST_CHECK(val2 - val == (std::numeric_limits::min)()); } unsigned shift = std::numeric_limits::digits - msb(val); BOOST_CHECK_THROW((val << shift) > 0, std::overflow_error); } } } #ifndef BOOST_NO_EXCEPTIONS if (std::numeric_limits::is_signed) { test_type a = -1; test_type b = 1; BOOST_CHECK_THROW(test_type(a | b), std::range_error); BOOST_CHECK_THROW(test_type(a & b), std::range_error); BOOST_CHECK_THROW(test_type(a ^ b), std::range_error); } else { // Constructing from a negative value is not allowed: BOOST_CHECK_THROW(test_type(-2), std::range_error); BOOST_CHECK_THROW(test_type("-2"), std::range_error); } if (std::numeric_limits::digits < std::numeric_limits::digits) { long long llm = (std::numeric_limits::max)(); test_type t; BOOST_CHECK_THROW(t = llm, std::range_error); BOOST_CHECK_THROW(t = static_cast(llm), std::range_error); unsigned long long ullm = (std::numeric_limits::max)(); BOOST_CHECK_THROW(t = ullm, std::range_error); BOOST_CHECK_THROW(t = static_cast(ullm), std::range_error); static const checked_uint512_t big = (std::numeric_limits::max)(); BOOST_CHECK_THROW(t = static_cast(big), std::range_error); } // // String errors: // BOOST_CHECK_THROW(test_type("12A"), std::runtime_error); BOOST_CHECK_THROW(test_type("0658"), std::runtime_error); if (std::numeric_limits::is_signed) { BOOST_CHECK_THROW(test_type(-2).str(0, std::ios_base::hex), std::runtime_error); BOOST_CHECK_THROW(test_type(-2).str(0, std::ios_base::oct), std::runtime_error); } #endif } int main() { using namespace boost::multiprecision; test > >(); test(); test(); test > >(); test > >(); // // We also need to test type with "odd" bit counts in order to ensure full code coverage: // test > >(); test > >(); test > >(); test > >(); return boost::report_errors(); }