From a8d49f40f0d0b13d1c5c6235d91f320751a97f85 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Wed, 7 Apr 2021 13:34:53 -0400 Subject: [PATCH 1/3] This uses the template trick to ensure we get only one definition --- include/fast_float/decimal_to_binary.h | 8 ++++---- include/fast_float/fast_table.h | 12 +++++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 0a4296f..687b834 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -20,18 +20,18 @@ namespace fast_float { template fastfloat_really_inline value128 compute_product_approximation(int64_t q, uint64_t w) { - const int index = 2 * int(q - smallest_power_of_five); + const int index = 2 * int(q - powers::smallest_power_of_five); // For small values of q, e.g., q in [0,27], the answer is always exact because // The line value128 firstproduct = full_multiplication(w, power_of_five_128[index]); // gives the exact answer. - value128 firstproduct = full_multiplication(w, power_of_five_128[index]); + value128 firstproduct = full_multiplication(w, powers::power_of_five_128[index]); static_assert((bit_precision >= 0) && (bit_precision <= 64), " precision should be in (0,64]"); constexpr uint64_t precision_mask = (bit_precision < 64) ? (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision) : uint64_t(0xFFFFFFFFFFFFFFFF); if((firstproduct.high & precision_mask) == precision_mask) { // could further guard with (lower + w < lower) // regarding the second product, we only need secondproduct.high, but our expectation is that the compiler will optimize this extra work away if needed. - value128 secondproduct = full_multiplication(w, power_of_five_128[index + 1]); + value128 secondproduct = full_multiplication(w, powers::power_of_five_128[index + 1]); firstproduct.low += secondproduct.high; if(secondproduct.high > firstproduct.low) { firstproduct.high++; @@ -83,7 +83,7 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept { answer.mantissa = 0; return answer; } - // At this point in time q is in [smallest_power_of_five, largest_power_of_five]. + // At this point in time q is in [powers::smallest_power_of_five, powers::largest_power_of_five]. // We want the most significant bit of i to be 1. Shift if needed. int lz = leading_zeroes(w); diff --git a/include/fast_float/fast_table.h b/include/fast_float/fast_table.h index b68fcac..ec05e8b 100644 --- a/include/fast_float/fast_table.h +++ b/include/fast_float/fast_table.h @@ -28,10 +28,14 @@ namespace fast_float { * infinite in binary64 so we never need to worry about powers * of 5 greater than 308. */ -constexpr int smallest_power_of_five = -342; -constexpr int largest_power_of_five = 308; +template +struct powers_template { + +constexpr static int smallest_power_of_five = binary_format::smallest_power_of_ten(); +constexpr static int largest_power_of_five = binary_format::largest_power_of_ten(); +constexpr static int number_of_entries = 2 * (largest_power_of_five - smallest_power_of_five + 1); // Powers of five from 5^-342 all the way to 5^308 rounded toward one. -const uint64_t power_of_five_128[]= { +constexpr static uint64_t power_of_five_128[number_of_entries] = { 0xeef453d6923bd65a,0x113faa2906a13b3f, 0x9558b4661b6565f8,0x4ac7ca59a424c507, 0xbaaee17fa23ebf76,0x5d79bcf00d2df649, @@ -683,6 +687,8 @@ const uint64_t power_of_five_128[]= { 0xb6472e511c81471d,0xe0133fe4adf8e952, 0xe3d8f9e563a198e5,0x58180fddd97723a6, 0x8e679c2f5e44ff8f,0x570f09eaa7ea7648,}; +}; +using powers = powers_template<>; } From 2cbfc21f8a43df7823a75b2cb795ddc36e22bec8 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Wed, 7 Apr 2021 13:39:07 -0400 Subject: [PATCH 2/3] Avoiding internal name conflict. --- include/fast_float/simple_decimal_conversion.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_float/simple_decimal_conversion.h b/include/fast_float/simple_decimal_conversion.h index 2b3825b..a8c9964 100644 --- a/include/fast_float/simple_decimal_conversion.h +++ b/include/fast_float/simple_decimal_conversion.h @@ -273,14 +273,14 @@ adjusted_mantissa compute_float(decimal &d) { } static const uint32_t max_shift = 60; static const uint32_t num_powers = 19; - static const uint8_t powers[19] = { + static const uint8_t decimal_powers[19] = { 0, 3, 6, 9, 13, 16, 19, 23, 26, 29, // 33, 36, 39, 43, 46, 49, 53, 56, 59, // }; int32_t exp2 = 0; while (d.decimal_point > 0) { uint32_t n = uint32_t(d.decimal_point); - uint32_t shift = (n < num_powers) ? powers[n] : max_shift; + uint32_t shift = (n < num_powers) ? decimal_powers[n] : max_shift; detail::decimal_right_shift(d, shift); if (d.decimal_point < -decimal_point_range) { // should be zero @@ -300,7 +300,7 @@ adjusted_mantissa compute_float(decimal &d) { shift = (d.digits[0] < 2) ? 2 : 1; } else { uint32_t n = uint32_t(-d.decimal_point); - shift = (n < num_powers) ? powers[n] : max_shift; + shift = (n < num_powers) ? decimal_powers[n] : max_shift; } detail::decimal_left_shift(d, shift); if (d.decimal_point > decimal_point_range) { From 19a771c615872709238cea1a2b5436cacb6ffd64 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Thu, 8 Apr 2021 10:46:43 -0400 Subject: [PATCH 3/3] Using out-of-line definition. --- include/fast_float/fast_table.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/fast_float/fast_table.h b/include/fast_float/fast_table.h index ec05e8b..415181e 100644 --- a/include/fast_float/fast_table.h +++ b/include/fast_float/fast_table.h @@ -35,7 +35,11 @@ constexpr static int smallest_power_of_five = binary_format::smallest_po constexpr static int largest_power_of_five = binary_format::largest_power_of_ten(); constexpr static int number_of_entries = 2 * (largest_power_of_five - smallest_power_of_five + 1); // Powers of five from 5^-342 all the way to 5^308 rounded toward one. -constexpr static uint64_t power_of_five_128[number_of_entries] = { +static const uint64_t power_of_five_128[number_of_entries]; +}; + +template +const uint64_t powers_template::power_of_five_128[number_of_entries] = { 0xeef453d6923bd65a,0x113faa2906a13b3f, 0x9558b4661b6565f8,0x4ac7ca59a424c507, 0xbaaee17fa23ebf76,0x5d79bcf00d2df649, @@ -687,7 +691,6 @@ constexpr static uint64_t power_of_five_128[number_of_entries] = { 0xb6472e511c81471d,0xe0133fe4adf8e952, 0xe3d8f9e563a198e5,0x58180fddd97723a6, 0x8e679c2f5e44ff8f,0x570f09eaa7ea7648,}; -}; using powers = powers_template<>; }