Skip to content

Commit 156e03e

Browse files
committed
Improve rd_string inf-check and add tests
1 parent 156c878 commit 156e03e

File tree

2 files changed

+126
-59
lines changed

2 files changed

+126
-59
lines changed

include/boost/multiprecision/cpp_double_fp.hpp

Lines changed: 72 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,8 @@ class cpp_double_fp_backend
11611161
template <typename FloatingPointType>
11621162
constexpr auto cpp_double_fp_backend<FloatingPointType>::rd_string(const char* p_str) -> bool
11631163
{
1164+
// Use an intermediate cpp_bin_float backend type for reading string input.
1165+
11641166
cpp_bin_float_read_write_backend_type f_bin { };
11651167

11661168
f_bin = p_str;
@@ -1197,96 +1199,107 @@ constexpr auto cpp_double_fp_backend<FloatingPointType>::rd_string(const char* p
11971199
}()
11981200
};
11991201

1200-
using cpp_bin_float_read_write_exp_type = typename cpp_bin_float_read_write_backend_type::exponent_type;
1201-
12021202
const auto is_zero_or_subnormal =
12031203
(
12041204
(fpc == FP_ZERO)
1205-
|| (expval_from_f_bin < static_cast<cpp_bin_float_read_write_exp_type>(local_double_fp_type::my_min_exponent))
1205+
|| (expval_from_f_bin < static_cast<typename cpp_bin_float_read_write_backend_type::exponent_type>(local_double_fp_type::my_min_exponent))
12061206
);
12071207

12081208
if (is_zero_or_subnormal)
12091209
{
12101210
data.first = float_type { 0.0F };
12111211
data.second = float_type { 0.0F };
1212+
1213+
return true;
12121214
}
1213-
else
1214-
{
1215-
bool is_definitely_inf { (fpc == FP_INFINITE) };
12161215

1217-
if (!is_definitely_inf)
1218-
{
1219-
float_type flt_inf_check { };
1216+
float_type flt_inf_check_first { };
12201217

1221-
eval_convert_to(&flt_inf_check, f_bin);
1218+
eval_convert_to(&flt_inf_check_first, f_bin);
12221219

1223-
if (flt_inf_check > my_value_max().my_first())
1224-
{
1225-
is_definitely_inf = true;
1226-
}
1227-
};
1220+
bool is_definitely_inf { ((fpc == FP_INFINITE) || cpp_df_qf_detail::ccmath::isinf(flt_inf_check_first)) };
12281221

1229-
if (is_definitely_inf)
1222+
if (!is_definitely_inf)
1223+
{
1224+
if (flt_inf_check_first > my_value_max().my_first())
12301225
{
1231-
static_cast<void>(operator=(local_double_fp_type::my_value_inf()));
1226+
cpp_bin_float_read_write_backend_type f_bin_inf_check(f_bin);
1227+
1228+
eval_subtract(f_bin_inf_check, cpp_bin_float_read_write_backend_type(flt_inf_check_first));
1229+
1230+
float_type flt_inf_check_second { };
1231+
1232+
eval_convert_to(&flt_inf_check_second, f_bin_inf_check);
12321233

1233-
if (b_neg) { negate(); }
1234+
is_definitely_inf = eval_gt(local_double_fp_type(flt_inf_check_first, flt_inf_check_second), my_value_max());
12341235
}
1235-
else
1236+
};
1237+
1238+
if (is_definitely_inf)
1239+
{
1240+
static_cast<void>(operator=(local_double_fp_type::my_value_inf()));
1241+
1242+
if (b_neg)
12361243
{
1237-
data.first = float_type { 0.0F };
1238-
data.second = float_type { 0.0F };
1244+
negate();
1245+
}
12391246

1240-
constexpr int pow2_scaling_for_small_input { cpp_df_qf_detail::ccmath::numeric_limits<float_type>::digits };
1247+
return true;
1248+
}
12411249

1242-
const auto has_pow2_scaling_for_small_input =
1243-
(
1244-
expval_from_f_bin < static_cast<int>(local_double_fp_type::my_min_exponent + pow2_scaling_for_small_input)
1245-
);
1250+
// The input string is normal. We will now extract its value.
12461251

1247-
if (has_pow2_scaling_for_small_input)
1248-
{
1249-
eval_ldexp(f_bin, f_bin, pow2_scaling_for_small_input);
1250-
}
1252+
data.first = float_type { 0.0F };
1253+
data.second = float_type { 0.0F };
12511254

1252-
using local_builtin_float_type = typename std::conditional<(sizeof(float_type) <= sizeof(double)), double, float_type>::type;
1255+
constexpr int pow2_scaling_for_small_input { cpp_df_qf_detail::ccmath::numeric_limits<float_type>::digits };
12531256

1254-
constexpr unsigned
1255-
digit_limit
1256-
{
1257-
static_cast<unsigned>
1258-
(
1259-
static_cast<int>
1260-
(
1261-
(local_double_fp_type::my_digits / cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits)
1262-
+ (((local_double_fp_type::my_digits % cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits) != 0) ? 1 : 0)
1263-
)
1264-
* cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits
1265-
)
1266-
};
1257+
const auto has_pow2_scaling_for_small_input =
1258+
(
1259+
expval_from_f_bin < static_cast<int>(local_double_fp_type::my_min_exponent + pow2_scaling_for_small_input)
1260+
);
12671261

1268-
for(auto i = static_cast<unsigned>(UINT8_C(0));
1269-
i < digit_limit;
1270-
i = static_cast<unsigned>(i + static_cast<unsigned>(cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits)))
1271-
{
1272-
local_builtin_float_type flt_part { };
1262+
if (has_pow2_scaling_for_small_input)
1263+
{
1264+
eval_ldexp(f_bin, f_bin, pow2_scaling_for_small_input);
1265+
}
1266+
1267+
using local_builtin_float_type = typename std::conditional<(sizeof(float_type) <= sizeof(double)), double, float_type>::type;
1268+
1269+
constexpr unsigned
1270+
digit_limit
1271+
{
1272+
static_cast<unsigned>
1273+
(
1274+
static_cast<int>
1275+
(
1276+
(local_double_fp_type::my_digits / cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits)
1277+
+ (((local_double_fp_type::my_digits % cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits) != 0) ? 1 : 0)
1278+
)
1279+
* cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits
1280+
)
1281+
};
12731282

1274-
eval_convert_to(&flt_part, f_bin);
1283+
for(auto i = static_cast<unsigned>(UINT8_C(0));
1284+
i < digit_limit;
1285+
i = static_cast<unsigned>(i + static_cast<unsigned>(cpp_df_qf_detail::ccmath::numeric_limits<local_builtin_float_type>::digits)))
1286+
{
1287+
local_builtin_float_type flt_part { };
12751288

1276-
eval_subtract(f_bin, cpp_bin_float_read_write_backend_type(flt_part));
1289+
eval_convert_to(&flt_part, f_bin);
12771290

1278-
eval_add(*this, local_double_fp_type { flt_part });
1279-
}
1291+
eval_subtract(f_bin, cpp_bin_float_read_write_backend_type(flt_part));
12801292

1281-
if (has_pow2_scaling_for_small_input)
1282-
{
1283-
eval_ldexp(*this, *this, -pow2_scaling_for_small_input);
1284-
}
1293+
eval_add(*this, local_double_fp_type { flt_part });
1294+
}
12851295

1286-
if (b_neg) { negate(); }
1287-
}
1296+
if (has_pow2_scaling_for_small_input)
1297+
{
1298+
eval_ldexp(*this, *this, -pow2_scaling_for_small_input);
12881299
}
12891300

1301+
if (b_neg) { negate(); }
1302+
12901303
return true;
12911304
}
12921305

test/test_various_edges_more.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,59 @@ namespace local
966966
}
967967
}
968968
}
969+
970+
auto test_double_fp_string_gt_max() -> void
971+
{
972+
using float_backend_larger_type = boost::multiprecision::cpp_bin_float<50, boost::multiprecision::digit_base_10, void, std::int32_t>;
973+
974+
using float_larger_type = boost::multiprecision::number<float_backend_larger_type, boost::multiprecision::et_off>;
975+
976+
std::mt19937_64 gen { time_point<typename std::mt19937_64::result_type>() };
977+
978+
auto dis =
979+
std::uniform_real_distribution<double>
980+
{
981+
static_cast<double>(1.01),
982+
static_cast<double>(1.04)
983+
};
984+
985+
{
986+
for(auto index = static_cast<unsigned>(UINT8_C(0)); index < static_cast<unsigned>(UINT8_C(32)); ++index)
987+
{
988+
const bool make_neg { ((index % unsigned { UINT8_C(2) }) != unsigned { UINT8_C(0) }) };
989+
990+
const double dbl_fuzz { 1.0 - dis(gen) * std::numeric_limits<double>::epsilon() };
991+
992+
float_larger_type
993+
flt_larger
994+
(
995+
float_larger_type((std::numeric_limits<boost::multiprecision::cpp_double_double>::max)())
996+
/ dbl_fuzz
997+
);
998+
999+
if(make_neg)
1000+
{
1001+
flt_larger = -flt_larger;
1002+
}
1003+
1004+
std::stringstream strm { };
1005+
1006+
strm << std::setprecision(std::numeric_limits<boost::multiprecision::cpp_double_double>::max_digits10)
1007+
<< flt_larger;
1008+
1009+
const std::string str_ovf { strm.str() };
1010+
1011+
const boost::multiprecision::cpp_double_double val_ovf(str_ovf.c_str());
1012+
1013+
BOOST_TEST((boost::multiprecision::isinf)(val_ovf));
1014+
1015+
if(make_neg)
1016+
{
1017+
BOOST_TEST((boost::multiprecision::signbit)(val_ovf));
1018+
}
1019+
}
1020+
}
1021+
}
9691022
} // namespace local
9701023

9711024
auto main() -> int
@@ -1006,6 +1059,7 @@ auto main() -> int
10061059
static_cast<void>(local::test_edges_ovf_und<double_float_type>());
10071060
static_cast<void>(local::test_edges_trig<double_float_type>());
10081061
local::test_frexp_edge<double_float_type>();
1062+
local::test_double_fp_string_gt_max();
10091063
}
10101064

10111065
{

0 commit comments

Comments
 (0)