mirror of
https://github.com/boostorg/multiprecision.git
synced 2026-07-21 13:23:49 +00:00
Improve rd_string inf-check and add tests
This commit is contained in:
@@ -1161,6 +1161,8 @@ class cpp_double_fp_backend
|
||||
template <typename FloatingPointType>
|
||||
constexpr auto cpp_double_fp_backend<FloatingPointType>::rd_string(const char* p_str) -> bool
|
||||
{
|
||||
// Use an intermediate cpp_bin_float backend type for reading string input.
|
||||
|
||||
cpp_bin_float_read_write_backend_type f_bin { };
|
||||
|
||||
f_bin = p_str;
|
||||
@@ -1197,96 +1199,107 @@ constexpr auto cpp_double_fp_backend<FloatingPointType>::rd_string(const char* p
|
||||
}()
|
||||
};
|
||||
|
||||
using cpp_bin_float_read_write_exp_type = typename cpp_bin_float_read_write_backend_type::exponent_type;
|
||||
|
||||
const auto is_zero_or_subnormal =
|
||||
(
|
||||
(fpc == FP_ZERO)
|
||||
|| (expval_from_f_bin < static_cast<cpp_bin_float_read_write_exp_type>(local_double_fp_type::my_min_exponent))
|
||||
|| (expval_from_f_bin < static_cast<typename cpp_bin_float_read_write_backend_type::exponent_type>(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;
|
||||
}
|
||||
else
|
||||
|
||||
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)
|
||||
{
|
||||
bool is_definitely_inf { (fpc == FP_INFINITE) };
|
||||
|
||||
if (!is_definitely_inf)
|
||||
if (flt_inf_check_first > my_value_max().my_first())
|
||||
{
|
||||
float_type flt_inf_check { };
|
||||
cpp_bin_float_read_write_backend_type f_bin_inf_check(f_bin);
|
||||
|
||||
eval_convert_to(&flt_inf_check, f_bin);
|
||||
eval_subtract(f_bin_inf_check, cpp_bin_float_read_write_backend_type(flt_inf_check_first));
|
||||
|
||||
if (flt_inf_check > my_value_max().my_first())
|
||||
{
|
||||
is_definitely_inf = true;
|
||||
}
|
||||
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());
|
||||
}
|
||||
};
|
||||
|
||||
if (is_definitely_inf)
|
||||
{
|
||||
static_cast<void>(operator=(local_double_fp_type::my_value_inf()));
|
||||
|
||||
if (b_neg)
|
||||
{
|
||||
negate();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// The input string is normal. We will now extract its value.
|
||||
|
||||
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<float_type>::digits };
|
||||
|
||||
const auto has_pow2_scaling_for_small_input =
|
||||
(
|
||||
expval_from_f_bin < static_cast<int>(local_double_fp_type::my_min_exponent + pow2_scaling_for_small_input)
|
||||
);
|
||||
|
||||
if (has_pow2_scaling_for_small_input)
|
||||
{
|
||||
eval_ldexp(f_bin, f_bin, pow2_scaling_for_small_input);
|
||||
}
|
||||
|
||||
using local_builtin_float_type = typename std::conditional<(sizeof(float_type) <= sizeof(double)), double, float_type>::type;
|
||||
|
||||
constexpr unsigned
|
||||
digit_limit
|
||||
{
|
||||
static_cast<unsigned>
|
||||
(
|
||||
static_cast<int>
|
||||
(
|
||||
(local_double_fp_type::my_digits / cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits)
|
||||
+ (((local_double_fp_type::my_digits % cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits) != 0) ? 1 : 0)
|
||||
)
|
||||
* cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits
|
||||
)
|
||||
};
|
||||
|
||||
if (is_definitely_inf)
|
||||
{
|
||||
static_cast<void>(operator=(local_double_fp_type::my_value_inf()));
|
||||
for(auto i = static_cast<unsigned>(UINT8_C(0));
|
||||
i < digit_limit;
|
||||
i = static_cast<unsigned>(i + static_cast<unsigned>(cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits)))
|
||||
{
|
||||
local_builtin_float_type flt_part { };
|
||||
|
||||
if (b_neg) { negate(); }
|
||||
}
|
||||
else
|
||||
{
|
||||
data.first = float_type { 0.0F };
|
||||
data.second = float_type { 0.0F };
|
||||
eval_convert_to(&flt_part, f_bin);
|
||||
|
||||
constexpr int pow2_scaling_for_small_input { cpp_df_qf_detail::ccmath::numeric_limits<float_type>::digits };
|
||||
eval_subtract(f_bin, cpp_bin_float_read_write_backend_type(flt_part));
|
||||
|
||||
const auto has_pow2_scaling_for_small_input =
|
||||
(
|
||||
expval_from_f_bin < static_cast<int>(local_double_fp_type::my_min_exponent + pow2_scaling_for_small_input)
|
||||
);
|
||||
|
||||
if (has_pow2_scaling_for_small_input)
|
||||
{
|
||||
eval_ldexp(f_bin, f_bin, pow2_scaling_for_small_input);
|
||||
}
|
||||
|
||||
using local_builtin_float_type = typename std::conditional<(sizeof(float_type) <= sizeof(double)), double, float_type>::type;
|
||||
|
||||
constexpr unsigned
|
||||
digit_limit
|
||||
{
|
||||
static_cast<unsigned>
|
||||
(
|
||||
static_cast<int>
|
||||
(
|
||||
(local_double_fp_type::my_digits / cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits)
|
||||
+ (((local_double_fp_type::my_digits % cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits) != 0) ? 1 : 0)
|
||||
)
|
||||
* cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits
|
||||
)
|
||||
};
|
||||
|
||||
for(auto i = static_cast<unsigned>(UINT8_C(0));
|
||||
i < digit_limit;
|
||||
i = static_cast<unsigned>(i + static_cast<unsigned>(cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits)))
|
||||
{
|
||||
local_builtin_float_type flt_part { };
|
||||
|
||||
eval_convert_to(&flt_part, f_bin);
|
||||
|
||||
eval_subtract(f_bin, cpp_bin_float_read_write_backend_type(flt_part));
|
||||
|
||||
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(); }
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<float_backend_larger_type, boost::multiprecision::et_off>;
|
||||
|
||||
std::mt19937_64 gen { time_point<typename std::mt19937_64::result_type>() };
|
||||
|
||||
auto dis =
|
||||
std::uniform_real_distribution<double>
|
||||
{
|
||||
static_cast<double>(1.01),
|
||||
static_cast<double>(1.04)
|
||||
};
|
||||
|
||||
{
|
||||
for(auto index = static_cast<unsigned>(UINT8_C(0)); index < static_cast<unsigned>(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<double>::epsilon() };
|
||||
|
||||
float_larger_type
|
||||
flt_larger
|
||||
(
|
||||
float_larger_type((std::numeric_limits<boost::multiprecision::cpp_double_double>::max)())
|
||||
/ dbl_fuzz
|
||||
);
|
||||
|
||||
if(make_neg)
|
||||
{
|
||||
flt_larger = -flt_larger;
|
||||
}
|
||||
|
||||
std::stringstream strm { };
|
||||
|
||||
strm << std::setprecision(std::numeric_limits<boost::multiprecision::cpp_double_double>::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<void>(local::test_edges_ovf_und<double_float_type>());
|
||||
static_cast<void>(local::test_edges_trig<double_float_type>());
|
||||
local::test_frexp_edge<double_float_type>();
|
||||
local::test_double_fp_string_gt_max();
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user