mirror of
https://github.com/boostorg/multiprecision.git
synced 2026-01-19 04:22:11 +00:00
Merge pull request #732 from boostorg/more_double_fp_findings
Try handle more double_fp findings
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2021 Fahad Syed.
|
||||
// Copyright 2021 - 2025 Fahad Syed.
|
||||
// Copyright 2021 - 2025 Christopher Kormanyos.
|
||||
// Copyright 2021 Janek Kozicki.
|
||||
// Copyright 2021 - 2025 Janek Kozicki.
|
||||
// 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)
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <boost/multiprecision/detail/standalone_config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_FLOAT128)
|
||||
#if defined(__has_include)
|
||||
#if __has_include(<quadmath.h>)
|
||||
|
||||
#include <quadmath.h>
|
||||
@@ -23,7 +22,6 @@
|
||||
#endif
|
||||
|
||||
#endif // __has_include(<quadmath.h>)
|
||||
#endif // defined(__has_include)
|
||||
#endif // defined(BOOST_HAS_FLOAT128)
|
||||
|
||||
#include <boost/multiprecision/number.hpp>
|
||||
@@ -59,12 +57,14 @@ struct pair
|
||||
float_type first;
|
||||
float_type second;
|
||||
|
||||
constexpr pair() : first { }, second { } { };
|
||||
constexpr pair(float_type a, float_type b) : first { a }, second { b } { }
|
||||
constexpr pair(const pair& other) : first { other.first }, second { other.second } { }
|
||||
// Default-constructed cpp_double_fp_backend values are zero.
|
||||
constexpr pair() noexcept : first { }, second { } { }
|
||||
|
||||
constexpr pair(float_type a, float_type b) noexcept : first { a }, second { b } { }
|
||||
constexpr pair(const pair& other) noexcept : first { other.first }, second { other.second } { }
|
||||
constexpr pair(pair&& other) noexcept : first { other.first }, second { other.second } { }
|
||||
|
||||
constexpr auto operator=(const pair& other) -> pair&
|
||||
constexpr auto operator=(const pair& other) noexcept -> pair&
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
};
|
||||
|
||||
static_assert(n_shl < std::numeric_limits<std::uint64_t>::digits,
|
||||
"Error: Left-shift amount for split does not fin in std::uint64_t");
|
||||
"Error: Left-shift amount for split does not fit in std::uint64_t");
|
||||
|
||||
static constexpr float_type
|
||||
value
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
|
||||
#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]
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#if (defined(__clang__) && (__clang_major__ <= 9))
|
||||
#if (defined(BOOST_CLANG) && defined(BOOST_CLANG_VERSION) && (BOOST_CLANG_VERSION <= 90000))
|
||||
#define BOOST_MP_DF_QF_NUM_LIMITS_CLASS_TYPE struct
|
||||
#else
|
||||
#define BOOST_MP_DF_QF_NUM_LIMITS_CLASS_TYPE class
|
||||
@@ -137,9 +137,8 @@ template <typename FloatingPointType,
|
||||
typename OtherFloatingPointType>
|
||||
constexpr auto eval_convert_to(OtherFloatingPointType* result, const cpp_double_fp_backend<FloatingPointType>& backend) -> typename ::std::enable_if<cpp_df_qf_detail::is_floating_point<OtherFloatingPointType>::value>::type;
|
||||
|
||||
// TBD: constexpr on hash_value?
|
||||
template <typename FloatingPointType>
|
||||
auto hash_value(const cpp_double_fp_backend<FloatingPointType>& a) -> ::std::size_t;
|
||||
constexpr auto hash_value(const cpp_double_fp_backend<FloatingPointType>& a) -> ::std::size_t;
|
||||
|
||||
template <typename FloatingPointType>
|
||||
constexpr auto fabs(const cpp_double_fp_backend<FloatingPointType>& a) -> cpp_double_fp_backend<FloatingPointType>;
|
||||
@@ -385,38 +384,25 @@ class cpp_double_fp_backend
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto hash() const -> ::std::size_t
|
||||
constexpr auto hash() const -> ::std::size_t
|
||||
{
|
||||
// Hash the raw values of the data field with direct-memory access.
|
||||
// Use 16-bit (2 byte) chunks as the data size when hashing.
|
||||
|
||||
static_assert( ( sizeof(data.first) == sizeof(data.second))
|
||||
&& ( sizeof(float_type) >= sizeof(std::uint16_t))
|
||||
&& ((sizeof(float_type) % sizeof(std::uint16_t)) == std::size_t { UINT8_C(0) }),
|
||||
"Error: float_type size is inappropriate for hashing routine");
|
||||
|
||||
auto hash_one
|
||||
{
|
||||
[](std::size_t& res, const float_type& val)
|
||||
{
|
||||
const std::uint16_t* first { reinterpret_cast<const std::uint16_t*>(&val) };
|
||||
const std::uint16_t* last { first + std::size_t { sizeof(float_type) / sizeof(std::uint16_t) } };
|
||||
|
||||
while (first != last)
|
||||
{
|
||||
boost::multiprecision::detail::hash_combine(res, *first);
|
||||
|
||||
++first;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
std::size_t result { UINT8_C(0) };
|
||||
|
||||
static_cast<void>(hash_one(result, data.first));
|
||||
static_cast<void>(hash_one(result, data.second));
|
||||
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<float_type, ::boost::float128_type>::value,
|
||||
long double,
|
||||
float_type>::type;
|
||||
#else
|
||||
using local_float_type = float_type;
|
||||
#endif
|
||||
|
||||
boost::multiprecision::detail::hash_combine(result, static_cast<local_float_type>(cpp_df_qf_detail::ccmath::frexp(data.first, &n_first)));
|
||||
boost::multiprecision::detail::hash_combine(result, static_cast<local_float_type>(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);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -574,6 +560,21 @@ class cpp_double_fp_backend
|
||||
|
||||
data = arithmetic::two_diff(data.first, v.data.first);
|
||||
|
||||
if (cpp_df_qf_detail::ccmath::isinf(data.first))
|
||||
{
|
||||
// Handle overflow.
|
||||
const bool b_neg { (data.first < float_type { 0.0F }) };
|
||||
|
||||
*this = cpp_double_fp_backend::my_value_inf();
|
||||
|
||||
if (b_neg)
|
||||
{
|
||||
negate();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
data = arithmetic::two_hilo_sum(data.first, data.second + thi_tlo.first);
|
||||
|
||||
data = arithmetic::two_hilo_sum(data.first, thi_tlo.second + data.second);
|
||||
@@ -885,6 +886,10 @@ class cpp_double_fp_backend
|
||||
}
|
||||
}
|
||||
|
||||
// TBD: Exactly what compilers/language-standards are needed to make this constexpr?
|
||||
// TBD: It odes not really become constexpr until we stop using an intermediate
|
||||
// cpp_bin_float anyway. But I will leave this comment for future library evolution.
|
||||
|
||||
auto str(std::streamsize number_of_digits, const std::ios::fmtflags format_flags) const -> std::string
|
||||
{
|
||||
if (number_of_digits == 0)
|
||||
@@ -1033,7 +1038,7 @@ class cpp_double_fp_backend
|
||||
|
||||
using cpp_bin_float_read_write_type = boost::multiprecision::number<cpp_bin_float_read_write_backend_type, boost::multiprecision::et_off>;
|
||||
|
||||
auto rd_string(const char* pstr) -> bool;
|
||||
constexpr auto rd_string(const char* pstr) -> bool;
|
||||
|
||||
constexpr auto add_unchecked(const cpp_double_fp_backend& v) -> void
|
||||
{
|
||||
@@ -1041,6 +1046,21 @@ class cpp_double_fp_backend
|
||||
|
||||
data = arithmetic::two_sum(data.first, v.data.first);
|
||||
|
||||
if (cpp_df_qf_detail::ccmath::isinf(data.first))
|
||||
{
|
||||
// Handle overflow.
|
||||
const bool b_neg { (data.first < float_type { 0.0F }) };
|
||||
|
||||
*this = cpp_double_fp_backend::my_value_inf();
|
||||
|
||||
if (b_neg)
|
||||
{
|
||||
negate();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
data = arithmetic::two_hilo_sum(data.first, data.second + thi_tlo.first);
|
||||
|
||||
data = arithmetic::two_hilo_sum(data.first, thi_tlo.second + data.second);
|
||||
@@ -1156,7 +1176,7 @@ class cpp_double_fp_backend
|
||||
};
|
||||
|
||||
template <typename FloatingPointType>
|
||||
auto cpp_double_fp_backend<FloatingPointType>::rd_string(const char* pstr) -> bool
|
||||
constexpr auto cpp_double_fp_backend<FloatingPointType>::rd_string(const char* pstr) -> bool
|
||||
{
|
||||
cpp_bin_float_read_write_type f_bin { pstr };
|
||||
|
||||
@@ -2458,7 +2478,7 @@ constexpr auto eval_convert_to(OtherFloatingPointType* result, const cpp_double_
|
||||
}
|
||||
|
||||
template <typename FloatingPointType>
|
||||
auto hash_value(const cpp_double_fp_backend<FloatingPointType>& a) -> ::std::size_t
|
||||
constexpr auto hash_value(const cpp_double_fp_backend<FloatingPointType>& a) -> ::std::size_t
|
||||
{
|
||||
return a.hash();
|
||||
}
|
||||
|
||||
@@ -499,8 +499,6 @@ namespace local
|
||||
result_is_ok = (result_unf_is_ok && result_is_ok);
|
||||
}
|
||||
|
||||
// TBD: See open issues for reminder to get this working in cpp_double_fp_backend.
|
||||
BOOST_IF_CONSTEXPR(!::has_poor_exp_range_or_precision_support<float_type>::value)
|
||||
{
|
||||
using std::ldexp;
|
||||
|
||||
@@ -524,8 +522,6 @@ namespace local
|
||||
result_is_ok = (result_ovf_is_ok && result_is_ok);
|
||||
}
|
||||
|
||||
// TBD: See open issues for reminder to get this working in cpp_double_fp_backend.
|
||||
BOOST_IF_CONSTEXPR(!::has_poor_exp_range_or_precision_support<float_type>::value)
|
||||
{
|
||||
using std::ldexp;
|
||||
|
||||
@@ -549,6 +545,29 @@ namespace local
|
||||
result_is_ok = (result_ovf_is_ok && result_is_ok);
|
||||
}
|
||||
|
||||
{
|
||||
using std::ldexp;
|
||||
|
||||
float_type flt_near_lowest { -ldexp((std::numeric_limits<float_type>::max)(), -1) };
|
||||
|
||||
const float_type neg_flt_less_near_max { -ldexp((std::numeric_limits<float_type>::max)(), -4) };
|
||||
|
||||
unsigned index { };
|
||||
|
||||
while((index < max_index) && (!(boost::multiprecision::isinf)(flt_near_lowest)))
|
||||
{
|
||||
flt_near_lowest += (neg_flt_less_near_max * dis(gen));
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
const bool result_ovf_is_ok { ((index > 1U) && (index < max_index)) && signbit(flt_near_lowest) };
|
||||
|
||||
BOOST_TEST(result_ovf_is_ok);
|
||||
|
||||
result_is_ok = (result_ovf_is_ok && result_is_ok);
|
||||
}
|
||||
|
||||
for(int n_loop = static_cast<int>(INT8_C(-16)); n_loop < static_cast<int>(INT8_C(-8)); ++n_loop)
|
||||
{
|
||||
using std::ldexp;
|
||||
|
||||
Reference in New Issue
Block a user