diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp index 59c6f6c2..23742463 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp @@ -32,6 +32,23 @@ namespace boost { namespace multiprecision { namespace backends { namespace cpp_df_qf_detail { +template +constexpr auto float_mask() noexcept -> UnsignedIntegralType +{ + using local_unsigned_integral_type = UnsignedIntegralType; + using local_float_type = FloatType; + + static_assert(static_cast(sizeof(UnsignedIntegralType) * 8u) > static_cast(cpp_df_qf_detail::ccmath::numeric_limits::digits), + "Error: this function is intended for unsigned integral type wider than the float type."); + + return + { + local_unsigned_integral_type { local_unsigned_integral_type { 1 } << static_cast(cpp_df_qf_detail::ccmath::numeric_limits::digits) } + - local_unsigned_integral_type { 1 } + }; +} + template struct pair { diff --git a/include/boost/multiprecision/cpp_double_fp.hpp b/include/boost/multiprecision/cpp_double_fp.hpp index c56e5f85..d2c90348 100644 --- a/include/boost/multiprecision/cpp_double_fp.hpp +++ b/include/boost/multiprecision/cpp_double_fp.hpp @@ -277,67 +277,27 @@ class cpp_double_fp_backend && boost::multiprecision::detail::is_unsigned::value && (static_cast(sizeof(UnsignedIntegralType) * 8u) > cpp_df_qf_detail::ccmath::numeric_limits::digits))>::type const* = nullptr> constexpr cpp_double_fp_backend(UnsignedIntegralType u) + : data(static_cast(u & cpp_df_qf_detail::float_mask()), + static_cast(0.0F)) { using local_unsigned_integral_type = UnsignedIntegralType; - constexpr local_unsigned_integral_type - limb_mask - { - local_unsigned_integral_type { local_unsigned_integral_type { 1 } << static_cast(cpp_df_qf_detail::ccmath::numeric_limits::digits) } - - local_unsigned_integral_type { 1 } - }; - - if (u <= limb_mask) + if (u > cpp_df_qf_detail::float_mask()) { - data = - { - static_cast(u), - static_cast(0.0F) - }; - } - else - { - constexpr local_unsigned_integral_type - flt_mask + local_unsigned_integral_type + local_flt_mask { - static_cast - ( - static_cast - ( - static_cast(UINT8_C(1)) << static_cast(cpp_df_qf_detail::ccmath::numeric_limits::digits) - ) - - static_cast(UINT8_C(1)) - ) + cpp_df_qf_detail::float_mask() }; - data.second = static_cast(0.0F); - data.first = static_cast(u & flt_mask); - - constexpr float_type - p2_factor_digits - ( - cpp_df_qf_detail::ccmath::ldexp - ( - static_cast(1.0F), - cpp_df_qf_detail::ccmath::numeric_limits::digits - ) - ); - - float_type p2_factor(p2_factor_digits); - - while (u > static_cast(UINT8_C(0))) + for (int index_mask_lsb = cpp_df_qf_detail::ccmath::numeric_limits::digits; + (index_mask_lsb < static_cast(sizeof(local_unsigned_integral_type) * 8u)) + && (local_flt_mask != local_unsigned_integral_type { UINT8_C(0) }); + index_mask_lsb += cpp_df_qf_detail::ccmath::numeric_limits::digits) { - u >>= static_cast(cpp_df_qf_detail::ccmath::numeric_limits::digits); + local_flt_mask <<= static_cast(cpp_df_qf_detail::ccmath::numeric_limits::digits); - const float_type - xhi - { - static_cast(static_cast(u & flt_mask) * p2_factor) - }; - - add_unchecked_limb(xhi); - - p2_factor *= p2_factor_digits; + add_unchecked_limb(static_cast(u & local_flt_mask)); } } } diff --git a/test/test_round.cpp b/test/test_round.cpp index cd941b1e..89a69d82 100644 --- a/test/test_round.cpp +++ b/test/test_round.cpp @@ -519,18 +519,12 @@ int main() #endif #ifdef TEST_CPP_DOUBLE_FLOAT - // When using very old GCC, categorically disable this test for cpp_double_fp_backend. - // Do not attempt, at the moment, to track down the compiler's "internal failure". - - #if (defined(BOOST_GCC) && !defined(BOOST_CLANG) && (BOOST_GCC < 80000)) - #else test(); test(); test(); #if defined(BOOST_MP_CPP_DOUBLE_FP_HAS_FLOAT128) test(); #endif - #endif #endif