From 20187736b3dc9349997114b0b0e69e9d62705c26 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Sat, 16 Dec 2023 09:21:29 +0000 Subject: [PATCH] Fix up cpp_bin_float for very small bit counts. (#577) Fix up cpp_bin_float for very small bit counts. Adds support for emulating float16_t and bfloat16_t. Also adds test cases, and updates test_arithmetic.hpp to cope with testing small bit count types. Fixes https://github.com/boostorg/multiprecision/issues/576. --- .../boost/multiprecision/cpp_bin_float.hpp | 72 ++++- test/Jamfile.v2 | 2 + test/git_issue_576.cpp | 122 ++++++++ test/test_arithmetic.hpp | 268 ++++++++++-------- test/test_arithmetic_cpp_bin_float_6.cpp | 28 ++ 5 files changed, 363 insertions(+), 129 deletions(-) create mode 100644 test/git_issue_576.cpp create mode 100644 test/test_arithmetic_cpp_bin_float_6.cpp diff --git a/include/boost/multiprecision/cpp_bin_float.hpp b/include/boost/multiprecision/cpp_bin_float.hpp index d620d3800..cc0ff4689 100644 --- a/include/boost/multiprecision/cpp_bin_float.hpp +++ b/include/boost/multiprecision/cpp_bin_float.hpp @@ -300,7 +300,13 @@ class cpp_bin_float #ifdef BOOST_HAS_FLOAT128 template - typename std::enable_if::value, cpp_bin_float&>::type assign_float(Float f) + typename std::enable_if::value && (std::numeric_limits::digits > Digits), cpp_bin_float&>::type assign_float(Float f) + { + cpp_bin_float<113, DigitBase, Allocator, Exponent, MinExponent, MaxExponent> bf(f); + return *this = bf; + } + template + typename std::enable_if::value && (std::numeric_limits::digits <= Digits), cpp_bin_float&>::type assign_float(Float f) { using default_ops::eval_add; using bf_int_type = typename boost::multiprecision::detail::canonical::type; @@ -337,7 +343,7 @@ class cpp_bin_float m_sign = false; m_exponent = 0; - constexpr std::ptrdiff_t bits = sizeof(int) * CHAR_BIT - 1; + constexpr std::ptrdiff_t bits = sizeof(int) * CHAR_BIT - 1 < MaxExponent - 1 ? sizeof(int) * CHAR_BIT - 1 : 3; int e; f = frexpq(f, &e); while (f) @@ -352,15 +358,36 @@ class cpp_bin_float eval_add(*this, t); } m_exponent += static_cast(e); + if (m_exponent > max_exponent) + { + m_exponent = exponent_infinity; + m_data = static_cast(0u); + } + else if (m_exponent < min_exponent) + { + m_exponent = exponent_zero; + m_data = static_cast(0u); + } return *this; } #endif #ifdef BOOST_HAS_FLOAT128 template - typename std::enable_if::value && !std::is_same::value, cpp_bin_float&>::type assign_float(Float f) + typename std::enable_if::value && !std::is_same::value && (std::numeric_limits::digits > Digits), cpp_bin_float&>::type assign_float(Float f) #else template - typename std::enable_if::value, cpp_bin_float&>::type assign_float(Float f) + typename std::enable_if::value && (std::numeric_limits::digits > Digits), cpp_bin_float&>::type assign_float(Float f) +#endif + { + cpp_bin_float::digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent> bf(f); + return *this = bf; + } +#ifdef BOOST_HAS_FLOAT128 + template + typename std::enable_if::value && !std::is_same::value && (std::numeric_limits::digits <= Digits), cpp_bin_float&>::type assign_float(Float f) +#else + template + typename std::enable_if::value && (std::numeric_limits::digits <= Digits), cpp_bin_float&>::type assign_float(Float f) #endif { using std::frexp; @@ -399,7 +426,13 @@ class cpp_bin_float m_sign = false; m_exponent = 0; - constexpr std::ptrdiff_t bits = sizeof(int) * CHAR_BIT - 1; + // + // This code picks off the bits in f a few at a time and injects them into *this. + // It does not do roundingm so we must have more digits precision in *this than + // in the floating point value (the normal situation, unless we're emulating another + // type like float16_t). + // + constexpr std::ptrdiff_t bits = static_cast(sizeof(int) * CHAR_BIT - 1) < static_cast(MaxExponent - 1) ? static_cast(sizeof(int) * CHAR_BIT - 1) : 3; int e; f = frexp(f, &e); while (f != static_cast(0.0F)) @@ -414,6 +447,16 @@ class cpp_bin_float eval_add(*this, t); } m_exponent += static_cast(e); + if (m_exponent > max_exponent) + { + m_exponent = exponent_infinity; + m_data = static_cast(0u); + } + else if(m_exponent < min_exponent) + { + m_exponent = exponent_zero; + m_data = static_cast(0u); + } return *this; } @@ -514,7 +557,12 @@ class cpp_bin_float using ar_type = typename boost::multiprecision::detail::canonical::type; m_data = static_cast(fi); std::size_t shift = msb(fi); - if (shift >= bit_count) + if (shift > max_exponent) + { + m_exponent = exponent_infinity; + m_data = static_cast(0); + } + else if (shift >= bit_count) { m_exponent = static_cast(shift); m_data = static_cast(fi >> (shift + 1 - bit_count)); @@ -524,7 +572,7 @@ class cpp_bin_float m_exponent = static_cast(shift); eval_left_shift(m_data, bit_count - shift - 1); } - BOOST_MP_ASSERT(eval_bit_test(m_data, bit_count - 1)); + BOOST_MP_ASSERT((m_exponent == exponent_infinity) || eval_bit_test(m_data, bit_count - 1)); m_sign = detail::is_negative(i); } return *this; @@ -1281,7 +1329,7 @@ inline void eval_divide(cpp_bin_float -inline typename std::enable_if::value>::type eval_divide(cpp_bin_float& res, +inline typename std::enable_if::value && (std::numeric_limits::digits <= Digits)>::type eval_divide(cpp_bin_float& res, const cpp_bin_float& u, const U& v) { #ifdef BOOST_MSVC @@ -1396,14 +1444,14 @@ inline typename std::enable_if::va } template -inline typename std::enable_if::value>::type eval_divide(cpp_bin_float& res, const U& v) +inline typename std::enable_if::value && (std::numeric_limits::digits <= Digits)>::type eval_divide(cpp_bin_float& res, const U& v) { eval_divide(res, res, v); } template -inline typename std::enable_if::value && boost::multiprecision::detail::is_integral::value>::type eval_divide(cpp_bin_float& res, +inline typename std::enable_if::value && boost::multiprecision::detail::is_integral::value && (std::numeric_limits::digits <= Digits)>::type eval_divide(cpp_bin_float& res, const cpp_bin_float& u, const S& v) { using ui_type = typename boost::multiprecision::detail::make_unsigned::type; @@ -1413,7 +1461,7 @@ inline typename std::enable_if::valu } template -inline typename std::enable_if::value && boost::multiprecision::detail::is_integral::value>::type eval_divide(cpp_bin_float& res, const S& v) +inline typename std::enable_if::value && boost::multiprecision::detail::is_integral::value && (std::numeric_limits::digits <= Digits)>::type eval_divide(cpp_bin_float& res, const S& v) { eval_divide(res, res, v); } @@ -1658,7 +1706,7 @@ inline typename std::enable_if::value>::type eval_ // // Perform rounding first, then afterwards extract the digits: // - cpp_bin_float(float_digits), digit_base_2, Allocator, Exponent, MinE, MaxE> arg; + cpp_bin_float(float_digits), digit_base_2, Allocator, Exponent, 0, 0> arg; typename cpp_bin_float::rep_type bits(original_arg.bits()); arg.exponent() = original_arg.exponent(); copy_and_round(arg, bits, (std::ptrdiff_t)digits_to_round_to); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a05a3aee5..130244609 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -127,6 +127,7 @@ test-suite arithmetic_tests : [ run test_arithmetic_cpp_bin_float_3.cpp no_eh_support : : : msvc:-bigobj [ check-target-builds ../config//has_float128 : quadmath ] ] [ run test_arithmetic_cpp_bin_float_4.cpp no_eh_support : : : msvc:-bigobj [ check-target-builds ../config//has_float128 : quadmath ] ] [ run test_arithmetic_cpp_bin_float_5.cpp no_eh_support : : : msvc:-bigobj [ check-target-builds ../config//has_float128 : quadmath ] ] + [ run test_arithmetic_cpp_bin_float_6.cpp no_eh_support : : : msvc:-bigobj [ check-target-builds ../config//has_float128 : quadmath ] [ requires cxx17_if_constexpr ] ] [ run test_arithmetic_mpf_50.cpp gmp no_eh_support : : : [ check-target-builds ../config//has_gmp : : no ] [ check-target-builds ../config//has_float128 : quadmath ] ] [ run test_arithmetic_mpf.cpp gmp no_eh_support : : : [ check-target-builds ../config//has_gmp : : no ] [ check-target-builds ../config//has_float128 : quadmath ] ] @@ -1232,6 +1233,7 @@ test-suite misc : [ run git_issue_526.cpp ] [ run git_issue_540.cpp ] [ run git_issue_573.cpp : : : msvc:-sdl ] + [ run git_issue_576.cpp : : : [ check-target-builds ../config//has_float128 : TEST_FLOAT128 quadmath : ] ] [ 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_576.cpp b/test/git_issue_576.cpp new file mode 100644 index 000000000..e78623e57 --- /dev/null +++ b/test/git_issue_576.cpp @@ -0,0 +1,122 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright 2023 John Maddock. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include "test.hpp" + +template +void test(F f, bool big) +{ + Float f2(f); + if (big) + { + F tol = f * static_cast(std::numeric_limits::epsilon()); + F max = static_cast((std::numeric_limits::max)()); + F diff = static_cast(f2) - f; + if (diff < 0) + diff = -diff; + if (f > max) + { + BOOST_CHECK(isinf(f2) || (diff < tol)); + } + else + { + BOOST_CHECK_LE(diff, tol); + } + } + else + { + BOOST_CHECK_EQUAL(static_cast(f2), f); + } +} + + +template +void test() +{ + std::int64_t i = static_cast(1) << (std::numeric_limits::max_exponent + 1); + Float f(i); + BOOST_CHECK_EQUAL(f, std::numeric_limits::infinity()); + + if (std::numeric_limits::max_exponent < std::numeric_limits::digits) + { + BOOST_CHECK_EQUAL(Float(static_cast(i)), std::numeric_limits::infinity()); + } + if (std::numeric_limits::max_exponent < std::numeric_limits::digits) + { + BOOST_CHECK_EQUAL(Float(static_cast(i)), std::numeric_limits::infinity()); + } + if (std::numeric_limits::max_exponent < std::numeric_limits::digits) + { + BOOST_CHECK_EQUAL(Float(static_cast(i)), std::numeric_limits::infinity()); + } +#ifdef BOOST_HAS_FLOAT128 + if (std::numeric_limits::max_exponent < std::numeric_limits<__float128>::digits) + { + BOOST_CHECK_EQUAL(Float(static_cast<__float128>(i)), std::numeric_limits::infinity()); + } +#endif + + --i; + + while (i) + { + Float f2(i); + BOOST_CHECK_NE(f2, std::numeric_limits::infinity()); + bool big = boost::multiprecision::msb(i) >= std::numeric_limits::digits; + if (big) + { + BOOST_CHECK_LE(static_cast(f2), i); + } + else + { + BOOST_CHECK_EQUAL(static_cast(f2), i); + } + + if (std::numeric_limits::max_exponent < std::numeric_limits::digits) + { + test(static_cast(i), big); + for (int exp = -1; exp >= std::numeric_limits::min_exponent; --exp) + test(std::ldexp(static_cast(i), exp), big); + } + if (std::numeric_limits::max_exponent < std::numeric_limits::digits) + { + test(static_cast(i), big); + for (int exp = -1; exp >= std::numeric_limits::min_exponent; --exp) + test(std::ldexp(static_cast(i), exp), big); + } + if (std::numeric_limits::max_exponent < std::numeric_limits::digits) + { + test(static_cast(i), big); + for (int exp = -1; exp >= std::numeric_limits::min_exponent; --exp) + test(std::ldexp(static_cast(i), exp), big); + } +#ifdef BOOST_HAS_FLOAT128 + if (std::numeric_limits::max_exponent < std::numeric_limits<__float128>::digits) + { + test(static_cast<__float128>(i), big); + for (int exp = -1; exp >= std::numeric_limits::min_exponent; --exp) + test(ldexpq(static_cast<__float128>(i), exp), big); + } +#endif + + --i; + } +} + + + +int main() +{ + using namespace boost::multiprecision; + typedef number, et_off> float16_t; + //typedef number, et_off> bfloat16_t; + + test(); + //test(); + + return boost::report_errors(); +} diff --git a/test/test_arithmetic.hpp b/test/test_arithmetic.hpp index 7016187f8..f9ebe4058 100644 --- a/test/test_arithmetic.hpp +++ b/test/test_arithmetic.hpp @@ -16,6 +16,7 @@ #include #include "test.hpp" #include +#include #ifndef BOOST_MP_STANDALONE #include @@ -1186,16 +1187,16 @@ void test_float_funcs(const std::integral_constant&) a = -2; a = fabs(a); BOOST_CHECK_EQUAL(a, 2); - a = 2.5; + a = static_cast(2.5); a = floor(a); BOOST_CHECK_EQUAL(a, 2); - a = 2.5; + a = static_cast(2.5); a = ceil(a); BOOST_CHECK_EQUAL(a, 3); - a = 2.5; + a = static_cast(2.5); a = trunc(a); BOOST_CHECK_EQUAL(a, 2); - a = 2.25; + a = static_cast(2.25); a = round(a); BOOST_CHECK_EQUAL(a, 2); a = 2; @@ -1203,7 +1204,10 @@ void test_float_funcs(const std::integral_constant&) BOOST_CHECK_EQUAL(a, 4); int i; a = frexp(a, &i); - BOOST_CHECK_EQUAL(a, 0.5); + BOOST_IF_CONSTEXPR(std::is_convertible::value) + { + BOOST_CHECK_EQUAL(a, 0.5); + } Real tol = std::numeric_limits::epsilon() * 3; a = 4; @@ -1219,31 +1223,31 @@ void test_float_funcs(const std::integral_constant&) a = log10(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(log10(Real(3))), tol); - a = 0.5; + a = static_cast(0.5); a = sin(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(sin(Real(0.5))), tol); - a = 0.5; + a = static_cast(0.5); a = cos(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(cos(Real(0.5))), tol); - a = 0.5; + a = static_cast(0.5); a = tan(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(tan(Real(0.5))), tol); - a = 0.5; + a = static_cast(0.5); a = asin(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(asin(Real(0.5))), tol); - a = 0.5; + a = static_cast(0.5); a = acos(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(acos(Real(0.5))), tol); - a = 0.5; + a = static_cast(0.5); a = atan(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(atan(Real(0.5))), tol); - a = 0.5; + a = static_cast(0.5); a = sinh(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(sinh(Real(0.5))), tol); - a = 0.5; + a = static_cast(0.5); a = cosh(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(cosh(Real(0.5))), tol); - a = 0.5; + a = static_cast(0.5); a = tanh(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(tanh(Real(0.5))), tol); // fmod, need to check all the sign permutations: @@ -1378,39 +1382,42 @@ void test_float_funcs(const std::integral_constant&) template void compare_NaNs(const T& a, const U& b) { - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - BOOST_CHECK_EQUAL(a <= b, false); - BOOST_CHECK_EQUAL(a >= b, false); - BOOST_CHECK_EQUAL(a > b, false); - BOOST_CHECK_EQUAL(a < b, false); - // - // Again where LHS may be an expression template: - // - BOOST_CHECK_EQUAL(1 * a == b, false); - BOOST_CHECK_EQUAL(1 * a != b, true); - BOOST_CHECK_EQUAL(1 * a <= b, false); - BOOST_CHECK_EQUAL(1 * a >= b, false); - BOOST_CHECK_EQUAL(1 * a > b, false); - BOOST_CHECK_EQUAL(1 * a < b, false); - // - // Again where RHS may be an expression template: - // - BOOST_CHECK_EQUAL(a == b * 1, false); - BOOST_CHECK_EQUAL(a != b * 1, true); - BOOST_CHECK_EQUAL(a <= b * 1, false); - BOOST_CHECK_EQUAL(a >= b * 1, false); - BOOST_CHECK_EQUAL(a > b * 1, false); - BOOST_CHECK_EQUAL(a < b * 1, false); - // - // Again where LHS and RHS may be an expression templates: - // - BOOST_CHECK_EQUAL(1 * a == b * 1, false); - BOOST_CHECK_EQUAL(1 * a != b * 1, true); - BOOST_CHECK_EQUAL(1 * a <= b * 1, false); - BOOST_CHECK_EQUAL(1 * a >= b * 1, false); - BOOST_CHECK_EQUAL(1 * a > b * 1, false); - BOOST_CHECK_EQUAL(1 * a < b * 1, false); + BOOST_IF_CONSTEXPR(std::is_convertible::value) + { + BOOST_CHECK_EQUAL(a == b, false); + BOOST_CHECK_EQUAL(a != b, true); + BOOST_CHECK_EQUAL(a <= b, false); + BOOST_CHECK_EQUAL(a >= b, false); + BOOST_CHECK_EQUAL(a > b, false); + BOOST_CHECK_EQUAL(a < b, false); + // + // Again where LHS may be an expression template: + // + BOOST_CHECK_EQUAL(1 * a == b, false); + BOOST_CHECK_EQUAL(1 * a != b, true); + BOOST_CHECK_EQUAL(1 * a <= b, false); + BOOST_CHECK_EQUAL(1 * a >= b, false); + BOOST_CHECK_EQUAL(1 * a > b, false); + BOOST_CHECK_EQUAL(1 * a < b, false); + // + // Again where RHS may be an expression template: + // + BOOST_CHECK_EQUAL(a == b * 1, false); + BOOST_CHECK_EQUAL(a != b * 1, true); + BOOST_CHECK_EQUAL(a <= b * 1, false); + BOOST_CHECK_EQUAL(a >= b * 1, false); + BOOST_CHECK_EQUAL(a > b * 1, false); + BOOST_CHECK_EQUAL(a < b * 1, false); + // + // Again where LHS and RHS may be an expression templates: + // + BOOST_CHECK_EQUAL(1 * a == b * 1, false); + BOOST_CHECK_EQUAL(1 * a != b * 1, true); + BOOST_CHECK_EQUAL(1 * a <= b * 1, false); + BOOST_CHECK_EQUAL(1 * a >= b * 1, false); + BOOST_CHECK_EQUAL(1 * a > b * 1, false); + BOOST_CHECK_EQUAL(1 * a < b * 1, false); + } } template @@ -1438,24 +1445,36 @@ void test_float_ops(const std::integral_constant::value) + { + BOOST_CHECK_EQUAL(r, 0.5); + } BOOST_CHECK_EQUAL(exponent, 10); BOOST_CHECK_EQUAL(v, 512); v = 1 / v; r = frexp(v, &exponent); - BOOST_CHECK_EQUAL(r, 0.5); + BOOST_IF_CONSTEXPR(std::is_convertible::value) + { + BOOST_CHECK_EQUAL(r, 0.5); + } BOOST_CHECK_EQUAL(exponent, -8); BOOST_CHECK_EQUAL(ldexp(Real(2), e_type(5)), 64); BOOST_CHECK_EQUAL(ldexp(Real(2), e_type(-5)), Real(2) / 32); v = 512; e_type exp2; r = frexp(v, &exp2); - BOOST_CHECK_EQUAL(r, 0.5); + BOOST_IF_CONSTEXPR(std::is_convertible::value) + { + BOOST_CHECK_EQUAL(r, 0.5); + } BOOST_CHECK_EQUAL(exp2, 10); BOOST_CHECK_EQUAL(v, 512); v = 1 / v; r = frexp(v, &exp2); - BOOST_CHECK_EQUAL(r, 0.5); + BOOST_IF_CONSTEXPR(std::is_convertible::value) + { + BOOST_CHECK_EQUAL(r, 0.5); + } BOOST_CHECK_EQUAL(exp2, -8); // // scalbn and logb, these are the same as ldexp and frexp unless the radix is @@ -1463,8 +1482,11 @@ void test_float_ops(const std::integral_constant::is_specialized && std::numeric_limits::radix) { - BOOST_CHECK_EQUAL(scalbn(Real(2), 5), 2 * pow(double(std::numeric_limits::radix), 5)); - BOOST_CHECK_EQUAL(scalbn(Real(2), -5), Real(2) / pow(double(std::numeric_limits::radix), 5)); + BOOST_IF_CONSTEXPR(std::is_convertible::value) + { + BOOST_CHECK_EQUAL(scalbn(Real(2), 5), 2 * pow(double(std::numeric_limits::radix), 5)); + BOOST_CHECK_EQUAL(scalbn(Real(2), -5), Real(2) / pow(double(std::numeric_limits::radix), 5)); + } v = 512; exponent = ilogb(v); r = scalbn(v, -exponent); @@ -1484,68 +1506,71 @@ void test_float_ops(const std::integral_constant(3.25)); - r = pow(v, 3); - BOOST_CHECK_EQUAL(r, boost::math::pow<3>(3.25)); - - BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 11) - { - // (13/4)^4 - // 28561 / 256 - // 111.56640625 - r = pow(v, 4); - BOOST_CHECK_EQUAL(r, boost::math::pow<4>(Real(3.25))); - } + BOOST_IF_CONSTEXPR(std::is_convertible::value) + { + v = 3.25; + r = pow(v, 0); + BOOST_CHECK_EQUAL(r, 1); + r = pow(v, 1); + BOOST_CHECK_EQUAL(r, 3.25); + r = pow(v, 2); + BOOST_CHECK_EQUAL(r, boost::math::pow<2>(3.25)); + r = pow(v, 3); + BOOST_CHECK_EQUAL(r, boost::math::pow<3>(3.25)); + + BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 11) + { + // (13/4)^4 + // 28561 / 256 + // 111.56640625 + r = pow(v, 4); + BOOST_CHECK_EQUAL(r, boost::math::pow<4>(Real(3.25))); + } - BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 13) - { - // (13/4)^5 - // 371293 / 1024 - // 362.5908203125 - r = pow(v, 5); - BOOST_CHECK_EQUAL(r, boost::math::pow<5>(Real(3.25))); - } + BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 13) + { + // (13/4)^5 + // 371293 / 1024 + // 362.5908203125 + r = pow(v, 5); + BOOST_CHECK_EQUAL(r, boost::math::pow<5>(Real(3.25))); + } - BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 16) - { - // (13/4)^6 - // 4826809 / 4096 - // 1178.420166015625 - r = pow(v, 6); - BOOST_CHECK_EQUAL(r, boost::math::pow<6>(Real(3.25))); - } + BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 16) + { + // (13/4)^6 + // 4826809 / 4096 + // 1178.420166015625 + r = pow(v, 6); + BOOST_CHECK_EQUAL(r, boost::math::pow<6>(Real(3.25))); + } - BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 26) - { - // (13/4)^10 - // 137858491849 / 1048576 - // 131472.10297489166259765625 - r = pow(v, 10); - BOOST_CHECK_EQUAL(r, boost::math::pow<10>(Real(3.25))); - } + BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 26) + { + // (13/4)^10 + // 137858491849 / 1048576 + // 131472.10297489166259765625 + r = pow(v, 10); + BOOST_CHECK_EQUAL(r, boost::math::pow<10>(Real(3.25))); + } - BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 38) - { - // (13/4)^15 - // 51185893014090757 / 1073741824 - // 47670577.665875439532101154327392578125 - r = pow(v, 15); - BOOST_CHECK_EQUAL(r, boost::math::pow<15>(Real(3.25))); - } + BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 38) + { + // (13/4)^15 + // 51185893014090757 / 1073741824 + // 47670577.665875439532101154327392578125 + r = pow(v, 15); + BOOST_CHECK_EQUAL(r, boost::math::pow<15>(Real(3.25))); + } - BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 63) - { - // (13/4)^25 - // 7056410014866816666030739693 / 1125899906842624 - // 6267351095760.54642313524184960016327750054188072681427001953125 - r = pow(v, 25); - BOOST_CHECK_EQUAL(r, boost::math::pow<25>(Real(3.25))); + BOOST_IF_CONSTEXPR(std::numeric_limits::digits10 > 63) + { + // (13/4)^25 + // 7056410014866816666030739693 / 1125899906842624 + // 6267351095760.54642313524184960016327750054188072681427001953125 + r = pow(v, 25); + BOOST_CHECK_EQUAL(r, boost::math::pow<25>(Real(3.25))); + } } #endif @@ -1602,7 +1627,7 @@ void test_float_ops(const std::integral_constant::has_quiet_NaN) { #ifndef BOOST_MP_STANDALONE - v = 20.25; + v = static_cast(20.25); r = std::numeric_limits::quiet_NaN(); BOOST_CHECK((boost::math::isnan)(v + r)); BOOST_CHECK((boost::math::isnan)(r + v)); @@ -1635,7 +1660,7 @@ void test_float_ops(const std::integral_constant::has_infinity) { - v = 20.25; + v = static_cast(20.25); r = std::numeric_limits::infinity(); #ifndef BOOST_MP_STANDALONE @@ -3262,7 +3287,10 @@ void test() BOOST_CHECK_EQUAL(ac, 8 * 500L); ac = 8 * 500L; ac = ac + b + c; - BOOST_CHECK_EQUAL(ac, 8 * 500L + 64 + 500); + if (std::numeric_limits::digits > boost::multiprecision::msb(8 * 500L + 64 + 500)) + { + BOOST_CHECK_EQUAL(ac, 8 * 500L + 64 + 500); + } ac = a; ac = b + c + ac; BOOST_CHECK_EQUAL(ac, 8 + 64 + 500); @@ -3337,7 +3365,10 @@ void test() BOOST_CHECK_EQUAL(ac, 8 - (500 - 64)); ac = a; ac -= b * c; - BOOST_CHECK_EQUAL(ac, 8 - 500 * 64); + if (std::numeric_limits::digits > boost::multiprecision::msb(std::abs(8 - 500 * 64))) + { + BOOST_CHECK_EQUAL(ac, 8 - 500 * 64); + } } ac = a; ac += ac * b; @@ -3441,9 +3472,12 @@ void test() a = 20; b = 30; c = (a * b) + 22; - BOOST_CHECK_EQUAL(c, 20 * 30 + 22); - c = 22 + (a * b); - BOOST_CHECK_EQUAL(c, 20 * 30 + 22); + if (std::numeric_limits::digits > boost::multiprecision::msb(20 * 30 + 22)) + { + BOOST_CHECK_EQUAL(c, 20 * 30 + 22); + c = 22 + (a * b); + BOOST_CHECK_EQUAL(c, 20 * 30 + 22); + } c = 10; ac = a + b * c; BOOST_CHECK_EQUAL(ac, 20 + 30 * 10); diff --git a/test/test_arithmetic_cpp_bin_float_6.cpp b/test/test_arithmetic_cpp_bin_float_6.cpp new file mode 100644 index 000000000..8fa90bcfb --- /dev/null +++ b/test/test_arithmetic_cpp_bin_float_6.cpp @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////// +// 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 + +#include + +#include "libs/multiprecision/test/test_arithmetic.hpp" + +#if 0 +template +struct related_type, ET> > +{ + typedef boost::multiprecision::number, ET> number_type; + typedef boost::multiprecision::number::digits / 2) > std::numeric_limits::digits ? Digits / 2 : Digits), DigitBase, Allocator, Exponent, MinExponent, MaxExponent>, ET> type; +}; +#endif + +int main() +{ + using namespace boost::multiprecision; + typedef number, et_off> float16_t; + typedef number, et_off> bfloat16_t; + + test(); + test(); + return boost::report_errors(); +}