/////////////////////////////////////////////////////////////// // Copyright 2021 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 // #ifdef _MSC_VER #define _SCL_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include "test.hpp" #if !defined(TEST_MPF) && !defined(TEST_MPFR) && !defined(TEST_MPFI) && !defined(TEST_MPC) #define TEST_MPF #define TEST_MPFR #define TEST_MPFI #define TEST_MPC #ifdef _MSC_VER #pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!") #endif #ifdef __GNUC__ #pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!" #endif #endif #include #include #include #include #if defined(TEST_MPFR) #include #endif #if defined(TEST_MPFI) #include #endif #if defined(TEST_MPC) #include #endif template T new_value() { return T("0.1"); } template Other make_other_big_value() { if constexpr (std::numeric_limits::is_integer && !std::numeric_limits::is_bounded) return (Other(1) << 1000) + 1; else if constexpr (!std::numeric_limits::is_integer && std::numeric_limits::is_exact && (std::numeric_limits::max_exponent == std::numeric_limits::min_exponent)) { using value_type = typename Other::value_type; return Other(1) / ((value_type(1) << 1000) + 1); } else return (std::numeric_limits::max)(); } template struct is_related_type : public std::false_type {}; template <> struct is_related_type : public std::true_type {}; template <> struct is_related_type, boost::multiprecision::et_off>, boost::multiprecision::mpf_float_100> : public std::true_type {}; #if defined(TEST_MPFR) template <> struct is_related_type : public std::true_type {}; template <> struct is_related_type, boost::multiprecision::et_off>, boost::multiprecision::mpfr_float_100> : public std::true_type {}; #endif #if defined(TEST_MPFI) template <> struct is_related_type : public std::true_type {}; template <> struct is_related_type, boost::multiprecision::et_off>, boost::multiprecision::mpfr_float_100> : public std::true_type {}; #endif #if defined(TEST_MPC) template <> struct is_related_type : public std::true_type {}; template <> struct is_related_type, boost::multiprecision::et_off>, boost::multiprecision::mpfr_float_100> : public std::true_type {}; #endif template void test_mixed() { T::thread_default_precision(10); T::thread_default_variable_precision_options(boost::multiprecision::variable_precision_options::preserve_related_precision); Other big_a(make_other_big_value()), big_b(make_other_big_value()), big_c(make_other_big_value()), big_d(make_other_big_value()); unsigned target_precision; if constexpr (is_related_type::value) target_precision = std::numeric_limits::digits10; else target_precision = T::thread_default_precision(); T a(big_a); BOOST_CHECK_EQUAL(a.precision(), target_precision); T b(std::move(big_d)); BOOST_CHECK_EQUAL(b.precision(), target_precision); if constexpr (std::is_assignable_v) { a = big_b; BOOST_CHECK_EQUAL(a.precision(), target_precision); b = std::move(big_c); BOOST_CHECK_EQUAL(b.precision(), target_precision); if constexpr (!std::is_assignable_v) { a = b + big_a; BOOST_CHECK_EQUAL(a.precision(), target_precision); a = b * big_a; BOOST_CHECK_EQUAL(a.precision(), target_precision); a = b - big_a; BOOST_CHECK_EQUAL(a.precision(), target_precision); a = b / big_a; BOOST_CHECK_EQUAL(a.precision(), target_precision); a += big_a; BOOST_CHECK_EQUAL(a.precision(), target_precision); a -= big_a; BOOST_CHECK_EQUAL(a.precision(), target_precision); a *= big_a; BOOST_CHECK_EQUAL(a.precision(), target_precision); a /= big_a; BOOST_CHECK_EQUAL(a.precision(), target_precision); } } if constexpr (!std::is_same_v) { T cc(big_a, big_b); BOOST_CHECK_EQUAL(cc.precision(), target_precision); T dd(big_a, big_b, 55); BOOST_CHECK_EQUAL(dd.precision(), 55); T aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 10); aa.assign(big_a); BOOST_CHECK_EQUAL(aa.precision(), target_precision); aa.assign(big_a, big_b); BOOST_CHECK_EQUAL(aa.precision(), target_precision); if constexpr (0 && std::is_constructible_v) { aa.assign(big_a, big_b, 55); BOOST_CHECK_EQUAL(aa.precision(), 55); } } else { if constexpr (std::is_constructible_v) { T aa(big_a, 55); BOOST_CHECK_EQUAL(aa.precision(), 55); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), T::thread_default_precision()); aa.assign(big_a, 55); BOOST_CHECK_EQUAL(aa.precision(), 55); } else { T aa; BOOST_CHECK_EQUAL(aa.precision(), target_precision); aa.assign(big_a); BOOST_CHECK_EQUAL(aa.precision(), target_precision); } } } template void test() { T::thread_default_precision(100); T::thread_default_variable_precision_options(boost::multiprecision::variable_precision_options::preserve_related_precision); T hp1("0.1"), hp2("0.3"), hp3("0.11"), hp4("0.1231"); BOOST_CHECK_EQUAL(hp1.precision(), 100); BOOST_CHECK_EQUAL(hp2.precision(), 100); T::thread_default_precision(35); T a(hp1); BOOST_CHECK_EQUAL(a.precision(), 100); a = new_value(); BOOST_CHECK_EQUAL(a.precision(), 35); a = hp1; BOOST_CHECK_EQUAL(a.precision(), 100); a = new_value(); BOOST_CHECK_EQUAL(a.precision(), 35); a = std::move(hp1); BOOST_CHECK_EQUAL(a.precision(), 100); a = new_value(); BOOST_CHECK_EQUAL(a.precision(), 35); T b(std::move(hp2)); BOOST_CHECK_EQUAL(b.precision(), 100); b = new_value(); BOOST_CHECK_EQUAL(b.precision(), 35); a = b + hp3; BOOST_CHECK_EQUAL(a.precision(), 100); a = new_value(); BOOST_CHECK_EQUAL(a.precision(), 35); a = hp3 * b; BOOST_CHECK_EQUAL(a.precision(), 100); a = new_value(); BOOST_CHECK_EQUAL(a.precision(), 35); a += hp3; BOOST_CHECK_EQUAL(a.precision(), 100); a = new_value(); BOOST_CHECK_EQUAL(a.precision(), 35); a *= hp4; BOOST_CHECK_EQUAL(a.precision(), 100); a = new_value(); BOOST_CHECK_EQUAL(a.precision(), 35); a -= b * hp3; BOOST_CHECK_EQUAL(a.precision(), 100); a = new_value(); BOOST_CHECK_EQUAL(a.precision(), 35); if constexpr (!std::is_same_v) { // // If we have a component type: ie we are an interval or a complex number, then // operations involving the component type should match those of T: // using component_t = typename T::value_type; component_t::thread_default_precision(100); component_t::thread_default_variable_precision_options(boost::multiprecision::variable_precision_options::preserve_source_precision); component_t cp1("0.1"), cp2("0.3"), cp3("0.11"), cp4("0.1231"); BOOST_CHECK_EQUAL(cp1.precision(), 100); BOOST_CHECK_EQUAL(cp2.precision(), 100); component_t::thread_default_precision(35); T aa(cp1); BOOST_CHECK_EQUAL(aa.precision(), 100); T cc(cp1, cp2); BOOST_CHECK_EQUAL(cc.precision(), 100); T dd(cp1, cp2, 55); BOOST_CHECK_EQUAL(dd.precision(), 55); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); if constexpr (std::is_assignable_v) { aa = cp1; BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); aa = std::move(cp1); BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); } T bb(std::move(cp2)); BOOST_CHECK_EQUAL(bb.precision(), 100); bb = new_value(); BOOST_CHECK_EQUAL(bb.precision(), 35); if constexpr (boost::multiprecision::is_compatible_arithmetic_type::value) { aa = bb + cp3; BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); aa = cp3 * bb; BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); aa += cp3; BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); aa -= cp3; BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); aa *= cp4; BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); aa /= cp4; BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); aa -= bb * cp3; BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); } aa.assign(cp1); BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); aa.assign(cp1, cp2); BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); aa.assign(cp1, cp2, 20); BOOST_CHECK_EQUAL(aa.precision(), 20); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); } else { T aa(hp4, 20); BOOST_CHECK_EQUAL(aa.precision(), 20); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); aa.assign(hp4); BOOST_CHECK_EQUAL(aa.precision(), 100); aa = new_value(); BOOST_CHECK_EQUAL(aa.precision(), 35); aa.assign(hp4, 20); BOOST_CHECK_EQUAL(aa.precision(), 20); } test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); // // Test with other compatible multiprecision types: // test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); test_mixed(); #if defined(TEST_MPFR) || defined(TEST_MPC) || defined(TEST_MPFI) test_mixed(); #endif } int main() { #ifdef TEST_MPF test(); test, boost::multiprecision::et_off>>(); #endif #ifdef TEST_MPFR test(); test, boost::multiprecision::et_off> >(); #endif #ifdef TEST_MPFI test(); test, boost::multiprecision::et_off> >(); #endif #ifdef TEST_MPC test(); test, boost::multiprecision::et_off> >(); #endif return boost::report_errors(); }