diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_constants.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_constants.hpp index 6fed97547..fad4d9118 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_constants.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_constants.hpp @@ -12,7 +12,7 @@ #include - #if (defined(__GNUC__) && defined(BOOST_MP_CPP_DOUBLE_FP_HAS_FLOAT128)) + #if (defined(BOOST_GCC) && defined(BOOST_MP_CPP_DOUBLE_FP_HAS_FLOAT128)) // // This is the only way we can avoid // warning: non-standard suffix on floating constant [-Wpedantic] diff --git a/include/boost/multiprecision/cpp_double_fp.hpp b/include/boost/multiprecision/cpp_double_fp.hpp index 9265fea4a..66da0d4af 100644 --- a/include/boost/multiprecision/cpp_double_fp.hpp +++ b/include/boost/multiprecision/cpp_double_fp.hpp @@ -249,11 +249,7 @@ class cpp_double_fp_backend typename ::std::enable_if<( cpp_df_qf_detail::is_floating_point::value && (!std::is_same::value))>::type const* = nullptr> constexpr cpp_double_fp_backend(const cpp_double_fp_backend& a) - : cpp_double_fp_backend(a.my_first()) - { - // TBD: Maybe specialize this constructor for cases either wider or less wide. - operator+=(a.my_second()); - } + : cpp_double_fp_backend(cpp_double_fp_backend(a.my_first()) += a.my_second()) { } // Constructors from integers. template cpp_df_qf_detail::float_mask()) + if (u > cpp_df_qf_detail::float_mask()) { local_unsigned_integral_type local_flt_mask @@ -332,9 +328,9 @@ class cpp_double_fp_backend constexpr cpp_double_fp_backend(const cpp_df_qf_detail::pair& p) noexcept : data(p) { } - cpp_double_fp_backend(const char* s) + cpp_double_fp_backend(const char* p_str) { - *this = s; + *this = p_str; } // Assignment operator. @@ -377,9 +373,9 @@ class cpp_double_fp_backend return operator=(cpp_double_fp_backend(n)); } - auto operator=(const char* v) -> cpp_double_fp_backend& + auto operator=(const char* p_str) -> cpp_double_fp_backend& { - rd_string(v); + rd_string(p_str); return *this; } @@ -388,9 +384,6 @@ class cpp_double_fp_backend { std::size_t result { UINT8_C(0) }; - int n_first { }; - int n_second { }; - #if defined(BOOST_MP_CPP_DOUBLE_FP_HAS_FLOAT128) using local_float_type = typename std::conditional<::std::is_same::value, long double, @@ -399,10 +392,8 @@ class cpp_double_fp_backend using local_float_type = float_type; #endif - boost::multiprecision::detail::hash_combine(result, static_cast(cpp_df_qf_detail::ccmath::frexp(data.first, &n_first))); - boost::multiprecision::detail::hash_combine(result, static_cast(cpp_df_qf_detail::ccmath::frexp(data.second, &n_second))); - boost::multiprecision::detail::hash_combine(result, n_first); - boost::multiprecision::detail::hash_combine(result, n_second); + boost::multiprecision::detail::hash_combine(result, static_cast(data.first)); + boost::multiprecision::detail::hash_combine(result, static_cast(data.second)); return result; } @@ -895,9 +886,9 @@ class cpp_double_fp_backend // Use cpp_bin_float when writing to string. This is similar // to the use of cpp_bin_float when reading from string. - cpp_bin_float_read_write_type f_bin { data.first }; + cpp_bin_float_read_write_backend_type f_bin { data.first }; - f_bin += data.second; + eval_add(f_bin, cpp_bin_float_read_write_backend_type(data.second)); return f_bin.str(number_of_digits, format_flags); } @@ -1029,11 +1020,8 @@ class cpp_double_fp_backend rep_type data; using cpp_bin_float_read_write_backend_type = boost::multiprecision::backends::cpp_bin_float(my_digits), digit_base_2, void, int, cpp_df_qf_detail::ccmath::numeric_limits::min_exponent, cpp_df_qf_detail::ccmath::numeric_limits::max_exponent>; - using cpp_bin_float_read_write_exp_type = typename cpp_bin_float_read_write_backend_type::exponent_type; - using cpp_bin_float_read_write_type = boost::multiprecision::number; - - constexpr auto rd_string(const char* pstr) -> bool; + constexpr auto rd_string(const char* p_str) -> bool; constexpr auto add_unchecked(const cpp_double_fp_backend& v) -> void { @@ -1171,11 +1159,15 @@ class cpp_double_fp_backend }; template -constexpr auto cpp_double_fp_backend::rd_string(const char* pstr) -> bool +constexpr auto cpp_double_fp_backend::rd_string(const char* p_str) -> bool { - cpp_bin_float_read_write_type f_bin { pstr }; + // Use an intermediate cpp_bin_float backend type for reading string input. + + cpp_bin_float_read_write_backend_type f_bin { }; - const int fpc { fpclassify(f_bin) }; + f_bin = p_str; + + const int fpc { eval_fpclassify(f_bin) }; const bool is_definitely_nan { (fpc == FP_NAN) }; @@ -1184,98 +1176,130 @@ constexpr auto cpp_double_fp_backend::rd_string(const char* p if (is_definitely_nan) { static_cast(operator=(local_double_fp_type::my_value_nan())); + + return true; } - else - { - const bool b_neg { (signbit(f_bin) == 1) }; - if (b_neg) { f_bin = -f_bin; } + const bool b_neg { (eval_signbit(f_bin) == 1) }; - const int - expval_from_f_bin + if (b_neg) { f_bin.negate(); } + + const int + expval_from_f_bin + { + [&f_bin]() { - [&f_bin]() - { - int expval; + int expval { }; - frexp(f_bin, &expval); + cpp_bin_float_read_write_backend_type dummy { }; - return expval; - }() - }; + eval_frexp(dummy, f_bin, &expval); - const auto is_zero_or_subnormal = - ( - (fpc == FP_ZERO) - || (expval_from_f_bin < static_cast(local_double_fp_type::my_min_exponent)) - ); + return expval; + }() + }; - if (is_zero_or_subnormal) + const auto is_zero_or_subnormal = + ( + (fpc == FP_ZERO) + || (expval_from_f_bin < static_cast(local_double_fp_type::my_min_exponent)) + ); + + if (is_zero_or_subnormal) + { + data.first = float_type { 0.0F }; + data.second = float_type { 0.0F }; + + return true; + } + + float_type flt_inf_check_first { }; + + eval_convert_to(&flt_inf_check_first, f_bin); + + bool is_definitely_inf { ((fpc == FP_INFINITE) || cpp_df_qf_detail::ccmath::isinf(flt_inf_check_first)) }; + + if (!is_definitely_inf) + { + if (flt_inf_check_first > my_value_max().my_first()) { - data.first = float_type { 0.0F }; - data.second = float_type { 0.0F }; + cpp_bin_float_read_write_backend_type f_bin_inf_check(f_bin); + + eval_subtract(f_bin_inf_check, cpp_bin_float_read_write_backend_type(flt_inf_check_first)); + + float_type flt_inf_check_second { }; + + eval_convert_to(&flt_inf_check_second, f_bin_inf_check); + + is_definitely_inf = eval_gt(local_double_fp_type(flt_inf_check_first, flt_inf_check_second), my_value_max()); } - else + }; + + if (is_definitely_inf) + { + static_cast(operator=(local_double_fp_type::my_value_inf())); + + if (b_neg) { - const auto is_definitely_inf = (f_bin > (::std::numeric_limits::max)()); + negate(); + } - if (is_definitely_inf) - { - static_cast(operator=(local_double_fp_type::my_value_inf())); + return true; + } - if (b_neg) { negate(); } - } - else - { - data.first = float_type { 0.0F }; - data.second = float_type { 0.0F }; + // The input string is normal. We will now extract its value. - using local_builtin_float_type = typename std::conditional<(sizeof(float_type) <= sizeof(double)), double, float_type>::type; + data.first = float_type { 0.0F }; + data.second = float_type { 0.0F }; - constexpr int pow2_scaling_for_small_input { cpp_df_qf_detail::ccmath::numeric_limits::digits }; + constexpr int pow2_scaling_for_small_input { cpp_df_qf_detail::ccmath::numeric_limits::digits }; - const auto has_pow2_scaling_for_small_input = - ( - expval_from_f_bin < static_cast(local_double_fp_type::my_min_exponent + pow2_scaling_for_small_input) - ); + const auto has_pow2_scaling_for_small_input = + ( + expval_from_f_bin < static_cast(local_double_fp_type::my_min_exponent + pow2_scaling_for_small_input) + ); - if (has_pow2_scaling_for_small_input) - { - f_bin = ldexp(f_bin, pow2_scaling_for_small_input); - } + if (has_pow2_scaling_for_small_input) + { + eval_ldexp(f_bin, f_bin, pow2_scaling_for_small_input); + } - constexpr auto dig_lim = - static_cast - ( - static_cast - ( - (local_double_fp_type::my_digits / cpp_df_qf_detail::ccmath::numeric_limits::digits) - + (((local_double_fp_type::my_digits % cpp_df_qf_detail::ccmath::numeric_limits::digits) != 0) ? 1 : 0) - ) - * cpp_df_qf_detail::ccmath::numeric_limits::digits - ); + using local_builtin_float_type = typename std::conditional<(sizeof(float_type) <= sizeof(double)), double, float_type>::type; - for(auto i = static_cast(UINT8_C(0)); - i < dig_lim; - i = static_cast(i + static_cast(cpp_df_qf_detail::ccmath::numeric_limits::digits))) - { - const local_builtin_float_type f { static_cast(f_bin) }; + constexpr unsigned + digit_limit + { + static_cast + ( + static_cast + ( + (local_double_fp_type::my_digits / cpp_df_qf_detail::ccmath::numeric_limits::digits) + + (((local_double_fp_type::my_digits % cpp_df_qf_detail::ccmath::numeric_limits::digits) != 0) ? 1 : 0) + ) + * cpp_df_qf_detail::ccmath::numeric_limits::digits + ) + }; - f_bin -= cpp_bin_float_read_write_type { f }; + for(auto i = static_cast(UINT8_C(0)); + i < digit_limit; + i = static_cast(i + static_cast(cpp_df_qf_detail::ccmath::numeric_limits::digits))) + { + local_builtin_float_type flt_part { }; - eval_add(*this, local_double_fp_type { f }); - } + eval_convert_to(&flt_part, f_bin); - if (has_pow2_scaling_for_small_input) - { - eval_ldexp(*this, *this, -pow2_scaling_for_small_input); - } + eval_subtract(f_bin, cpp_bin_float_read_write_backend_type(flt_part)); - if (b_neg) { negate(); } - } - } + eval_add(*this, local_double_fp_type { flt_part }); } + if (has_pow2_scaling_for_small_input) + { + eval_ldexp(*this, *this, -pow2_scaling_for_small_input); + } + + if (b_neg) { negate(); } + return true; } diff --git a/performance/performance_test_df.cpp b/performance/performance_test_df.cpp new file mode 100644 index 000000000..2e3157a88 --- /dev/null +++ b/performance/performance_test_df.cpp @@ -0,0 +1,287 @@ +/////////////////////////////////////////////////////////////// +// Copyright John Maddock 2019. +// Copyright Christopher Kormanyos 2021 - 2025. +// 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 + +// This version of "performance_test_df.cpp" is based almost entirely on +// the original "performance_test.cpp". But it has been specifically +// adapted to test various backends in small precision ranges in order +// to check the performance comparison with cpp_double_double. + +#include + +#if !defined(TEST_CPP_DOUBLE_FLOAT) +#define TEST_CPP_DOUBLE_FLOAT +#endif + +#if !defined(TEST_CPP_BIN_FLOAT) +#define TEST_CPP_BIN_FLOAT +#endif + +#if !defined(TEST_CPP_DEC_FLOAT) +#define TEST_CPP_DEC_FLOAT +#endif + +#if defined(BOOST_HAS_FLOAT128) +#if !defined(TEST_FLOAT128) +#define TEST_FLOAT128 +#endif +#endif + +#include + +#if defined(TEST_CPP_DOUBLE_FLOAT) +#include +#endif + +#if defined(TEST_CPP_BIN_FLOAT) +#include +#endif + +#if defined(TEST_CPP_BIN_FLOAT) +#include +#endif + +#if defined(TEST_FLOAT128) +#include +#endif + +#include "performance_test_df.hpp" + +// cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/Test +// g++ -std=gnu++14 -Wall -Wextra -O3 -I/mnt/c/ChrisGitRepos/modular_boost/multiprecision/performance -I/mnt/c/ChrisGitRepos/modular_boost/multiprecision/include -I/mnt/c/boost/boost_1_89_0 ./test.cpp -lquadmath -o test + +// +// Keys in order are: +// Category +// Operator +// Type +// Precision +// Time +// +std::map > > > result_table; + +unsigned bits_wanted; // for integer types + +void quickbook_results() +{ + // + // Keys in order are: + // Category + // Operator + // Type + // Precision + // Time + // + typedef std::map > > >::const_iterator category_iterator; + typedef std::map > >::const_iterator operator_iterator; + typedef std::map >::const_iterator type_iterator; + typedef std::map::const_iterator precision_iterator; + + for (category_iterator i = result_table.begin(); i != result_table.end(); ++i) + { + std::string cat = i->first; + cat[0] = (char)std::toupper((char)cat[0]); + std::cout << "[section:" << i->first << "_performance " << cat << " Type Perfomance]" << std::endl; + + for (operator_iterator j = i->second.begin(); j != i->second.end(); ++j) + { + std::string op = j->first; + std::cout << "[table Operator " << op << std::endl; + std::cout << "[[Backend]"; + + for (precision_iterator k = j->second.begin()->second.begin(); k != j->second.begin()->second.end(); ++k) + { + std::cout << "[" << k->first << " Bits]"; + } + std::cout << "]\n"; + + std::vector best_times(j->second.begin()->second.size(), (std::numeric_limits::max)()); + for (unsigned m = 0; m < j->second.begin()->second.size(); ++m) + { + for (type_iterator k = j->second.begin(); k != j->second.end(); ++k) + { + if (m < k->second.size()) + { + precision_iterator l = k->second.begin(); + std::advance(l, m); + if (best_times[m] > l->second) + best_times[m] = l->second ? l->second : best_times[m]; + } + } + } + + for (type_iterator k = j->second.begin(); k != j->second.end(); ++k) + { + std::cout << "[[" << k->first << "]"; + + unsigned m = 0; + for (precision_iterator l = k->second.begin(); l != k->second.end(); ++l) + { + double rel_time = l->second / best_times[m]; + if (rel_time == 1) + std::cout << "[[*" << rel_time << "]"; + else + std::cout << "[" << rel_time; + std::cout << " (" << l->second << "s)]"; + ++m; + } + + std::cout << "]\n"; + } + + std::cout << "]\n"; + } + + std::cout << "[endsect]" << std::endl; + } +} + +#if defined(__HAS_INCLUDE) +#if __has_include() +#define HAS_UTSNAME +#include +#endif +#endif +#ifdef _WIN32 +#include +#endif + +void quickbook_platform_details() +{ + std::cout << "[table:platform Platform Details\n[[Platform]["; +#ifdef HAS_UTSNAME + utsname name; + uname(&name); + std::cout << name.sysname << " " << name.release << ", version " << name.version << ", " << name.machine << "]]\n"; +#elif defined(_WIN32) + std::cout << "Windows "; +#ifdef _M_AMD64 + std::cout << "x64"; +#elif defined(_M_IX86) + std::cout << "x86"; +#endif + std::cout << "]]\n"; +#endif + std::cout << "[[Compiler][" << BOOST_COMPILER << "]]\n"; + std::cout << "[[Boost][" << BOOST_VERSION << "]]\n"; + std::cout << "[[Run date][" << __DATE__ << "]]\n"; + std::cout << "]\n\n"; +} + +namespace local { + +void test29(); +void test32(); +void test52(); +void test53(); + +#ifdef TEST_CPP_DOUBLE_FLOAT +template +constexpr inline auto (max)(T a, T b) noexcept -> T { return a > b ? a : b; } +#endif + +} // namespace local + +int main() +{ + quickbook_platform_details(); + + local::test29(); + local::test32(); + local::test52(); + #if defined(BOOST_MP_CPP_DOUBLE_FP_HAS_FLOAT128) + local::test53(); + #endif + + quickbook_results(); +} + +#ifdef TEST_CPP_DOUBLE_FLOAT +using double_float_of_double_type = boost::multiprecision::cpp_double_double; + +constexpr auto digits10_for_performance_test = (local::max)(std::numeric_limits::digits10, 32); +#else +constexpr auto digits10_for_performance_test = 32; +#endif + +void local::test29() +{ +#ifdef TEST_CPP_DEC_FLOAT + static_assert(digits10_for_performance_test >= 32, "Error: Too few digits for performance comparison"); + + using cpp_dec_float_type = + boost::multiprecision::number, + boost::multiprecision::et_off>; + + test("cpp_dec_float", digits10_for_performance_test); +#endif +} + +void local::test32() +{ +#ifdef TEST_CPP_BIN_FLOAT + static_assert(digits10_for_performance_test >= 32, "Error: Too few digits for performance comparison"); + + using cpp_bin_float_type = + boost::multiprecision::number, + boost::multiprecision::et_off>; + + test("cpp_bin_float", digits10_for_performance_test); +#endif +} + +void local::test52() +{ +#ifdef TEST_CPP_DOUBLE_FLOAT + test("cpp_double_fp_backend", digits10_for_performance_test); +#endif +} + +void local::test53() +{ +#if defined(BOOST_HAS_FLOAT128) +#ifdef TEST_FLOAT128 + using boost::multiprecision::float128; + + test("boost::multiprecision::float128(at)", std::numeric_limits::digits10); +#endif +#endif +} + +#if 0 + +See also: https://github.com/BoostGSoC21/multiprecision/issues/178#issuecomment-2580157139 + +## section:float_performance Float Type Perfomance + +| Operation | `float128` |`cpp_bin_float<32>` | `cpp_dec_float<32>` | `cpp_double_fp_backend` | +|---------------------------------|----------------------|------------------------|------------------------|---------------------------------| +| `*` | 1.45209 (0.0530208s) | 1.4866 (0.054281s) | 4.38403 (0.160076s) | [*1] (0.0365135s) | +| `*(int)` | 1.54876 (0.0396009s) | 2.08722 (0.0533689s) | 5.97016 (0.152653s) | [*1] (0.0255694s) | +| `*(unsigned long long)` | 1.66579 (0.083952s) | 1.109 (0.0558912s) | 3.64263 (0.18358s) | [*1] (0.0503976s) | +| `*=(unsigned long long)` | 1.70531 (0.0858822s) | 1.06861 (0.053817s) | 3.47129 (0.17482s) | [*1] (0.0503617s) | +| `+` | 2.4858 (0.0430852s) | 5.38736 (0.0933768s) | 3.06832 (0.0531818s) | [*1] (0.0173326s) | +| `+(int)` | 2.96871 (0.0360276s) | 7.95354 (0.0965222s) | 5.97545 (0.0725166s) | [*1] (0.0121358s) | +| `+(unsigned long long)` | 3.38383 (0.0739771s) | 5.51557 (0.120581s) | 4.42454 (0.0967292s) | [*1] (0.021862s) | +| `+=(unsigned long long)` | 3.3944 (0.0760423s) | 4.98724 (0.111726s) | 3.92369 (0.0878995s) | [*1] (0.0224023s) | +| `-` | 2.20087 (0.0389465s) | 5.40743 (0.0956897s) | 3.24191 (0.0573686s) | [*1] (0.0176959s) | +| `-(int)` | 3.21093 (0.0383358s) | 8.65589 (0.103344s) | 7.53768 (0.0899936s) | [*1] (0.0119392s) | +| `-(unsigned long long)` | 3.45536 (0.075553s) | 5.17747 (0.113208s) | 4.63221 (0.101285s) | [*1] (0.0218654s) | +| `-=(unsigned long long)` | 2.73635 (0.0764208s) | 3.773 (0.105372s) | 3.39784 (0.0948951s) | [*1] (0.027928s) | +| `/` | 1.38437 (0.148412s) | 7.55692 (0.810141s) | 23.5198 (2.52144s) | [*1] (0.107205s) | +| `/(int)` | 1.53126 (0.0384472s) | 6.85045 (0.172002s) | 49.004 (1.2304s) | [*1] (0.0251081s) | +| `/(unsigned long long)` | 2.41876 (0.098966s) | 9.80113 (0.401023s) | 30.6916 (1.25578s) | [*1] (0.040916s) | +| `/=(unsigned long long)` | 1.88263 (0.0994829s) | 7.33976 (0.387852s) | 23.6024 (1.24721s) | [*1] (0.0528426s) | +| `construct` | [*1] (0.000550501s) | 4.74042 (0.00260961s) | 13.0381 (0.00717748s) | 3.51129 (0.00193297s) | +| `construct(unsigned long long)` | 5.33373 (0.0401408s) | 2.82475 (0.0212586s) | 3.38482 (0.0254736s) | [*1] (0.00752583s) | +| `construct(unsigned)` | 23.3495 (0.0403851s) | 12.4928 (0.0216075s) | 14.3869 (0.0248834s) | [*1] (0.00172959s) | +| `exp` | 1.37724 (1.66978s) | 5.45487 (6.61357s) | 5.19473 (6.29817s) | [*1] (1.21242s) | +| `log` | [*1] (2.1149s) | 7.38874 (15.6264s) | 27.0206 (57.146s) | 1.10118 (2.32888s) | +| `sqrt` | 25.9413 (0.53951s) | 24.5484 (0.510541s) | 131.925 (2.74368s) | [*1] (0.0207973s) | +| `str` | [*1] (0.000419145s) | 1.50425 (0.000630497s) | 1.22795 (0.000514689s) | 1.82207 (0.000763711s) | +| `tan` | 1.3995 (1.69463s) | 5.46528 (6.61782s) | 5.20608 (6.30396s) | [*1] (1.21088s) | + +#endif diff --git a/test/test_cpp_double_float_bessel_versus_bin_and_dec.cpp b/test/test_cpp_double_float_bessel_versus_bin_and_dec.cpp index ee2aea7e4..5068f968d 100644 --- a/test/test_cpp_double_float_bessel_versus_bin_and_dec.cpp +++ b/test/test_cpp_double_float_bessel_versus_bin_and_dec.cpp @@ -4,7 +4,7 @@ // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt -// This test file is executes a specific function-by-function +// This test file executes a specific function-by-function // comparison of cpp_double_double with other backends having // similar digit counts. @@ -149,10 +149,10 @@ auto generate_wide_decimal_value(int digits10_to_get = std::numeric_limits(digits10_to_get + 1), '0'); // Get the leading digit before the decimal point. - str_x[std::string::size_type { UINT8_C(0) }] = static_cast(dist_dig(eng_dig)); + str_x.at(std::string::size_type { UINT8_C(0) }) = static_cast(dist_dig(eng_dig)); // Insert a decimal point. - str_x[std::string::size_type { UINT8_C(1) }] = '.'; + str_x.at(std::string::size_type { UINT8_C(1) }) = '.'; std::generate(str_x.begin() + std::string::size_type { UINT8_C(2) }, str_x.end(), @@ -190,6 +190,7 @@ auto is_close_fraction(const NumericType& a, auto do_trials(const std::size_t trial_count) -> void { static std::size_t heat_count { }; + static std::size_t total_count { }; std::cout << "\nheat_count: " << ++heat_count << std::endl; @@ -219,12 +220,14 @@ auto do_trials(const std::size_t trial_count) -> void for(std::size_t index { UINT8_C(0) }; index < dbl_float_a_vec.size(); ++index) { - if(std::size_t { index % unsigned { UINT32_C(0x1000) } } == std::size_t { UINT8_C(0) }) + if(std::size_t { total_count % unsigned { UINT32_C(0x1000) } } == std::size_t { UINT8_C(0) }) { eng_sgn.seed(util::util_pseudorandom_time_point_seed()); eng_dig.seed(util::util_pseudorandom_time_point_seed()); } + ++total_count; + auto gen { @@ -256,18 +259,18 @@ auto do_trials(const std::size_t trial_count) -> void } }; - dbl_float_a_vec[index] = dbl_float_type { gen(true, dbl_float_type { 11 } / 10) }; - dbl_float_b_vec[index] = dbl_float_type { gen(true, dbl_float_type { 11 } / 10) }; + dbl_float_a_vec.at(index) = dbl_float_type { gen(true, dbl_float_type { 11 } / 10) }; + dbl_float_b_vec.at(index) = dbl_float_type { gen(true, dbl_float_type { 11 } / 10) }; - dec_float_a_vec[index] = dec_float_type { dbl_float_a_vec[index] }; - dec_float_b_vec[index] = dec_float_type { dbl_float_b_vec[index] }; + dec_float_a_vec.at(index) = dec_float_type { dbl_float_a_vec.at(index) }; + dec_float_b_vec.at(index) = dec_float_type { dbl_float_b_vec.at(index) }; - bin_float_a_vec[index] = bin_float_type { dbl_float_a_vec[index] }; - bin_float_b_vec[index] = bin_float_type { dbl_float_b_vec[index] }; + bin_float_a_vec.at(index) = bin_float_type { dbl_float_a_vec.at(index) }; + bin_float_b_vec.at(index) = bin_float_type { dbl_float_b_vec.at(index) }; #if defined(BOOST_HAS_FLOAT128) - flt_float_a_vec[index] = flt_float_type { dbl_float_a_vec[index] }; - flt_float_b_vec[index] = flt_float_type { dbl_float_b_vec[index] }; + flt_float_a_vec.at(index) = flt_float_type { dbl_float_a_vec.at(index) }; + flt_float_b_vec.at(index) = flt_float_type { dbl_float_b_vec.at(index) }; #endif } @@ -284,7 +287,7 @@ auto do_trials(const std::size_t trial_count) -> void for(std::size_t count { UINT8_C(0) }; count < trials; ++count) { - dbl_float_c_vec[count] = boost::math::cyl_bessel_j(dbl_float_a_vec[count], dbl_float_b_vec[count]); + dbl_float_c_vec.at(count) = boost::math::cyl_bessel_j(dbl_float_a_vec.at(count), dbl_float_b_vec.at(count)); } const double elapsed_dbl { stopwatch_type::elapsed_time(my_stopwatch) }; @@ -293,7 +296,7 @@ auto do_trials(const std::size_t trial_count) -> void for(std::size_t count { UINT8_C(0) }; count < trials; ++count) { - dec_float_c_vec[count] = boost::math::cyl_bessel_j(dec_float_a_vec[count], dec_float_b_vec[count]); + dec_float_c_vec.at(count) = boost::math::cyl_bessel_j(dec_float_a_vec.at(count), dec_float_b_vec.at(count)); } const double elapsed_dec { stopwatch_type::elapsed_time(my_stopwatch) }; @@ -302,7 +305,7 @@ auto do_trials(const std::size_t trial_count) -> void for(std::size_t count { UINT8_C(0) }; count < trials; ++count) { - bin_float_c_vec[count] = boost::math::cyl_bessel_j(bin_float_a_vec[count], bin_float_b_vec[count]); + bin_float_c_vec.at(count) = boost::math::cyl_bessel_j(bin_float_a_vec.at(count), bin_float_b_vec.at(count)); } const double elapsed_bin { stopwatch_type::elapsed_time(my_stopwatch) }; @@ -312,7 +315,7 @@ auto do_trials(const std::size_t trial_count) -> void for(std::size_t count { UINT8_C(0) }; count < trials; ++count) { - flt_float_c_vec[count] = boost::math::cyl_bessel_j(flt_float_a_vec[count], flt_float_b_vec[count]); + flt_float_c_vec.at(count) = boost::math::cyl_bessel_j(flt_float_a_vec.at(count), flt_float_b_vec.at(count)); } const double elapsed_flt { stopwatch_type::elapsed_time(my_stopwatch) }; diff --git a/test/test_various_edges_more.cpp b/test/test_various_edges_more.cpp index 26e5e9f23..d5f24715b 100644 --- a/test/test_various_edges_more.cpp +++ b/test/test_various_edges_more.cpp @@ -966,6 +966,59 @@ namespace local } } } + + auto test_double_fp_string_gt_max() -> void + { + using float_backend_larger_type = boost::multiprecision::cpp_bin_float<50, boost::multiprecision::digit_base_10, void, std::int32_t>; + + using float_larger_type = boost::multiprecision::number; + + std::mt19937_64 gen { time_point() }; + + auto dis = + std::uniform_real_distribution + { + static_cast(1.01), + static_cast(1.04) + }; + + { + for(auto index = static_cast(UINT8_C(0)); index < static_cast(UINT8_C(32)); ++index) + { + const bool make_neg { ((index % unsigned { UINT8_C(2) }) != unsigned { UINT8_C(0) }) }; + + const double dbl_fuzz { 1.0 - dis(gen) * std::numeric_limits::epsilon() }; + + float_larger_type + flt_larger + ( + float_larger_type((std::numeric_limits::max)()) + / dbl_fuzz + ); + + if(make_neg) + { + flt_larger = -flt_larger; + } + + std::stringstream strm { }; + + strm << std::setprecision(std::numeric_limits::max_digits10) + << flt_larger; + + const std::string str_ovf { strm.str() }; + + const boost::multiprecision::cpp_double_double val_ovf(str_ovf.c_str()); + + BOOST_TEST((boost::multiprecision::isinf)(val_ovf)); + + if(make_neg) + { + BOOST_TEST((boost::multiprecision::signbit)(val_ovf)); + } + } + } + } } // namespace local auto main() -> int @@ -1006,6 +1059,7 @@ auto main() -> int static_cast(local::test_edges_ovf_und()); static_cast(local::test_edges_trig()); local::test_frexp_edge(); + local::test_double_fp_string_gt_max(); } {