Streamline some syntax and more cover

This commit is contained in:
ckormanyos
2025-07-15 14:12:09 +02:00
parent 7aec17719d
commit eec48fe44f
4 changed files with 102 additions and 85 deletions

View File

@@ -1,7 +1,9 @@
// Copyright 2011 John Maddock.
// Copyright 2011 - 2025 John Maddock.
// Copyright 2025 Christopher Kormanyos.
// 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)
//
// This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
//
@@ -10,7 +12,7 @@ template <class T>
void calc_log2(T& num, unsigned digits)
{
using ui_type = typename boost::multiprecision::detail::canonical<std::uint32_t, T>::type;
using si_type = typename std::tuple_element<0, typename T::signed_types>::type ;
using si_type = typename std::tuple_element<0, typename T::signed_types>::type;
//
// String value with 1100 digits:
@@ -219,14 +221,14 @@ void calc_pi(T& result, unsigned digits)
template <class T>
const T& get_constant_ln2()
{
static BOOST_MP_THREAD_LOCAL T result;
static BOOST_MP_THREAD_LOCAL long digits = 0;
if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
{
boost::multiprecision::detail::maybe_promote_precision(&result);
calc_log2(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
digits = boost::multiprecision::detail::digits2<number<T> >::value();
}
static const BOOST_MP_THREAD_LOCAL T result =
[]()
{
T tmp_val;
boost::multiprecision::detail::maybe_promote_precision(&tmp_val);
calc_log2(tmp_val, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
return tmp_val;
}();
return result;
}
@@ -234,14 +236,14 @@ const T& get_constant_ln2()
template <class T>
const T& get_constant_e()
{
static BOOST_MP_THREAD_LOCAL T result;
static BOOST_MP_THREAD_LOCAL long digits = 0;
if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
{
boost::multiprecision::detail::maybe_promote_precision(&result);
calc_e(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
digits = boost::multiprecision::detail::digits2<number<T> >::value();
}
static const BOOST_MP_THREAD_LOCAL T result =
[]()
{
T tmp_val;
boost::multiprecision::detail::maybe_promote_precision(&tmp_val);
calc_e(tmp_val, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
return tmp_val;
}();
return result;
}
@@ -249,17 +251,18 @@ const T& get_constant_e()
template <class T>
const T& get_constant_pi()
{
static BOOST_MP_THREAD_LOCAL T result;
static BOOST_MP_THREAD_LOCAL long digits = 0;
if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
{
boost::multiprecision::detail::maybe_promote_precision(&result);
calc_pi(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
digits = boost::multiprecision::detail::digits2<number<T> >::value();
}
static const BOOST_MP_THREAD_LOCAL T result =
[]()
{
T tmp_val;
boost::multiprecision::detail::maybe_promote_precision(&tmp_val);
calc_pi(tmp_val, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
return tmp_val;
}();
return result;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4127) // conditional expression is constant
@@ -267,19 +270,22 @@ const T& get_constant_pi()
template <class T>
const T& get_constant_one_over_epsilon()
{
static BOOST_MP_THREAD_LOCAL T result;
static BOOST_MP_THREAD_LOCAL long digits = 0;
if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
{
using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
boost::multiprecision::detail::maybe_promote_precision(&result);
result = static_cast<ui_type>(1u);
BOOST_IF_CONSTEXPR(std::numeric_limits<number<T> >::is_specialized)
eval_divide(result, std::numeric_limits<number<T> >::epsilon().backend());
else
eval_ldexp(result, result, boost::multiprecision::detail::digits2<number<T> >::value() - 1);
digits = boost::multiprecision::detail::digits2<number<T> >::value();
}
static const BOOST_MP_THREAD_LOCAL T result =
[]()
{
using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
T tmp_val;
boost::multiprecision::detail::maybe_promote_precision(&tmp_val);
tmp_val = static_cast<ui_type>(1u);
BOOST_IF_CONSTEXPR(std::numeric_limits<number<T> >::is_specialized)
eval_divide(tmp_val, std::numeric_limits<number<T> >::epsilon().backend());
else
eval_ldexp(tmp_val, tmp_val, boost::multiprecision::detail::digits2<number<T> >::value() - 1);
return tmp_val;
}();
return result;
}

View File

@@ -8,6 +8,7 @@
// This work is based on an earlier work:
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
//
// This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
//
@@ -99,7 +100,7 @@ inline void pow_imp(T& result, const T& t, const U& p, const std::integral_const
{
// Signed integer power, just take care of the sign then call the unsigned version:
using int_type = typename boost::multiprecision::detail::canonical<U, T>::type;
using ui_type = typename boost::multiprecision::detail::make_unsigned<U>::type ;
using ui_type = typename boost::multiprecision::detail::make_unsigned<U>::type;
if (p < 0)
{
@@ -163,7 +164,7 @@ void hyp0F0(T& H0F0, const T& x)
x_pow_n_div_n_fact.negate();
}
if (n >= series_limit)
BOOST_MP_THROW_EXCEPTION(std::runtime_error("H0F0 failed to converge"));
BOOST_MP_THROW_EXCEPTION(std::runtime_error("H0F0 failed to converge")); // LCOV_EXCL_LINE
}
template <class T>
@@ -212,7 +213,7 @@ void hyp1F0(T& H1F0, const T& a, const T& x)
break;
}
if (n >= series_limit)
BOOST_MP_THROW_EXCEPTION(std::runtime_error("H1F0 failed to converge"));
BOOST_MP_THROW_EXCEPTION(std::runtime_error("H1F0 failed to converge")); // LCOV_EXCL_LINE
}
template <class T>
@@ -227,8 +228,8 @@ void eval_exp(T& result, const T& x)
return;
}
using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
using si_type = typename boost::multiprecision::detail::canonical<int, T>::type ;
using exp_type = typename T::exponent_type ;
using si_type = typename boost::multiprecision::detail::canonical<int, T>::type;
using exp_type = typename T::exponent_type;
using canonical_exp_type = typename boost::multiprecision::detail::canonical<exp_type, T>::type;
// Handle special arguments.
@@ -373,10 +374,12 @@ void eval_log(T& result, const T& arg)
// log(x) = log(2) * n + log1p(1 + y)
//
using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
using exp_type = typename T::exponent_type ;
using exp_type = typename T::exponent_type;
using canonical_exp_type = typename boost::multiprecision::detail::canonical<exp_type, T>::type;
using fp_type = typename std::tuple_element<0, typename T::float_types>::type ;
int s = eval_signbit(arg);
using fp_type = typename std::tuple_element<0, typename T::float_types>::type;
const int s = eval_signbit(arg);
switch (eval_fpclassify(arg))
{
case FP_NAN:
@@ -455,16 +458,14 @@ void eval_log(T& result, const T& arg)
template <class T>
const T& get_constant_log10()
{
static BOOST_MP_THREAD_LOCAL T result;
static BOOST_MP_THREAD_LOCAL long digits = 0;
if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
{
using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
T ten;
ten = ui_type(10u);
eval_log(result, ten);
digits = boost::multiprecision::detail::digits2<number<T> >::value();
}
static const BOOST_MP_THREAD_LOCAL T result =
[]()
{
const T ten(10);
T tmp_val;
eval_log(tmp_val, ten);
return tmp_val;
}();
return result;
}
@@ -555,7 +556,7 @@ inline void eval_pow(T& result, const T& x, const T& a)
return;
}
}
BOOST_MP_CATCH(const std::exception&)
BOOST_MP_CATCH(const std::exception&) // LCOV_EXCL_LINE
{
// fallthrough..
}
@@ -679,7 +680,7 @@ inline void eval_pow(T& result, const T& x, const T& a)
}
else
{
BOOST_MP_THROW_EXCEPTION(std::domain_error("Result of pow is undefined or non-real and there is no NaN for this number type."));
BOOST_MP_THROW_EXCEPTION(std::domain_error("Result of pow is undefined or non-real and there is no NaN for this number type.")); // LCOV_EXCL_LINE
}
return;
}
@@ -746,7 +747,7 @@ template <class T, class A>
#if BOOST_WORKAROUND(BOOST_MSVC, < 1800)
inline typename std::enable_if<!boost::multiprecision::detail::is_integral<A>::value, void>::type
#else
inline typename std::enable_if<is_compatible_arithmetic_type<A, number<T> >::value && !boost::multiprecision::detail::is_integral<A>::value, void>::type
inline typename std::enable_if<boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<T> >::value && !boost::multiprecision::detail::is_integral<A>::value, void>::type
#endif
eval_pow(T& result, const T& x, const A& a)
{
@@ -763,7 +764,7 @@ template <class T, class A>
#if BOOST_WORKAROUND(BOOST_MSVC, < 1800)
inline void
#else
inline typename std::enable_if<is_compatible_arithmetic_type<A, number<T> >::value, void>::type
inline typename std::enable_if<boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<T> >::value, void>::type
#endif
eval_pow(T& result, const A& x, const T& a)
{

View File

@@ -9,6 +9,14 @@
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
#define TEST_CPP_BIN_FLOAT
#define TEST_CPP_DEC_FLOAT
#define TEST_CPP_DOUBLE_FLOAT
#if defined(__GNUC__)
#define TEST_FLOAT128
#define TEST_MPF_50
#endif
#ifdef _MSC_VER
#define _SCL_SECURE_NO_WARNINGS
#endif
@@ -66,13 +74,14 @@
#include <boost/multiprecision/cpp_double_fp.hpp>
#endif
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
// These were the only ones I checked locally at the moment that use random tests.
#include <array>
#include <ctime>
#include <random>
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
template<typename FloatType> auto my_zero() -> FloatType&;
@@ -127,7 +136,7 @@ namespace local {
} // namespace local
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
// These were the only ones I checked locally at the moment.
@@ -195,26 +204,26 @@ void test_small_a_in_default_ops()
T("0.99999976301106994561811131758260769485991144451216442896857591003045319114657385381607667593523204524")
}};
unsigned max_err = 0;
unsigned max_err = 0U;
std::size_t k { UINT8_C(0) };
const T x_val(T(789U) / 1000);
const T x_val { T { 789U } / 1000 };
const T local_tol { std::numeric_limits<T>::epsilon() / 8 };
const T local_tol { std::numeric_limits<T>::epsilon() / 4 };
T small_a = pow(T(10), -12);
for (int p10 = -12; p10 < -5; ++p10)
for (std::size_t k { UINT8_C(0) }; k < std::tuple_size<small_a_data_array_type>::value; ++k)
{
const T small_a { pow(T(10), p10) };
const T val = pow(x_val, small_a);
T val = pow(x_val, small_a);
small_a *= 10;
using std::fabs;
const T delta { val / small_a_data[k] };
const T closeness { fabs(1 - delta) };
T rel = closeness / local_tol;
const T rel = closeness / local_tol;
unsigned err = rel.template convert_to<unsigned>();
@@ -222,16 +231,14 @@ void test_small_a_in_default_ops()
{
max_err = err;
}
++k;
}
std::cout << "Max error data having small a: " << max_err << std::endl;
BOOST_TEST(max_err < 32);
BOOST_TEST(max_err < 64U);
}
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
template <class T>
void test()
@@ -245,7 +252,7 @@ void test()
const auto& data = local::data_maker<local_test_pow_data_array_type>::get_data();
unsigned max_err = 0;
unsigned max_err = 0U;
for (unsigned k = 0; k < data.size(); k++)
{
T val = pow(T(data[k][0]), T(data[k][1]));
@@ -266,9 +273,9 @@ void test()
std::cout << "Max error from data table was: " << max_err << std::endl;
#if defined(BOOST_INTEL) && defined(TEST_FLOAT128)
BOOST_TEST(max_err < 40000);
BOOST_TEST(max_err < 40000U);
#else
BOOST_TEST(max_err < 8000);
BOOST_TEST(max_err < 8000U);
#endif
//
@@ -283,7 +290,7 @@ void test()
BOOST_CHECK_EQUAL(pow(T(1), T(2)), 1);
BOOST_CHECK_EQUAL(pow(T(1), 2), 1);
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
// These were the only ones I checked locally at the moment.
std::mt19937_64 gen { };
@@ -297,7 +304,7 @@ void test()
static_cast<float>(1.04L)
);
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
BOOST_IF_CONSTEXPR(std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::has_infinity)
{
@@ -305,7 +312,7 @@ void test()
BOOST_CHECK_EQUAL(pow(T(1.25F), -std::numeric_limits<T>::infinity()), T(0));
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
// These were the only ones I checked locally at the moment.
for (int npow = -8; npow < 8; ++npow)
@@ -377,7 +384,7 @@ void test()
}
}
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
}
BOOST_IF_CONSTEXPR((!boost::multiprecision::is_interval_number<T>::value) && std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::has_quiet_NaN)
@@ -448,6 +455,8 @@ int main()
#endif
#ifdef TEST_FLOAT128
test<boost::multiprecision::float128>();
test_issue722<boost::multiprecision::float128>();
test_small_a_in_default_ops<boost::multiprecision::float128>();
#endif
#ifdef TEST_CPP_BIN_FLOAT
test<boost::multiprecision::cpp_bin_float_50>();

View File

@@ -13,10 +13,9 @@
#define _SCL_SECURE_NO_WARNINGS
#endif
#include <array>
#include <test.hpp>
#include <boost/detail/lightweight_test.hpp>
#include "test.hpp"
#if !defined(TEST_MPF_50) && !defined(TEST_MPF) && !defined(TEST_BACKEND) && !defined(TEST_CPP_DEC_FLOAT) && !defined(TEST_MPFR) && !defined(TEST_MPFR_50) && !defined(TEST_MPFI_50) && !defined(TEST_FLOAT128) && !defined(TEST_CPP_BIN_FLOAT) && !defined(TEST_CPP_DOUBLE_FLOAT)
#define TEST_MPF_50
@@ -64,6 +63,8 @@
#include <boost/multiprecision/cpp_double_fp.hpp>
#endif
#include <array>
template <class T>
struct has_poor_large_value_support
{