Merge branch 'main' into adding_explicit_cxx23_specialization

This commit is contained in:
Anders Dalvander 2025-09-29 21:35:46 +02:00 committed by GitHub
commit c086f538e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 387 additions and 118 deletions

View File

@ -401,6 +401,23 @@ except `fast_float::integer_times_pow10()` does not report out-of-range errors,
underflows to zero or overflows to infinity when the resulting value is underflows to zero or overflows to infinity when the resulting value is
out of range. out of range.
You can use template overloads to get the result converted to different
supported floating-point types: `float`, `double`, etc.
For example, to get result as `float` use
`fast_float::integer_times_pow10<float>()` specialization:
```C++
const uint64_t W = 12345678;
const int Q = 23;
const float result = fast_float::integer_times_pow10<float>(W, Q);
std::cout.precision(9);
std::cout << "float: " << W << " * 10^" << Q << " = " << result << " ("
<< (result == 12345678e23f ? "==" : "!=") << "expected)\n";
```
outputs
```
float: 12345678 * 10^23 = 1.23456782e+30 (==expected)
```
Overloads of `fast_float::integer_times_pow10()` are provided for Overloads of `fast_float::integer_times_pow10()` are provided for
signed and unsigned integer types: `int64_t`, `uint64_t`, etc. signed and unsigned integer types: `int64_t`, `uint64_t`, etc.

View File

@ -63,6 +63,20 @@ integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept;
FASTFLOAT_CONSTEXPR20 inline double FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept; integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept;
/**
* This function is a template overload of `integer_times_pow10()`
* that returns a floating-point value of type `T` that is one of
* supported floating-point types (e.g. `double`, `float`).
*/
template <typename T>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept;
template <typename T>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept;
/** /**
* from_chars for integer types. * from_chars for integer types.
*/ */

View File

@ -1166,6 +1166,9 @@ static_assert(std::is_same<equiv_uint_t<std::float64_t>, uint64_t>::value,
static_assert( static_assert(
std::numeric_limits<std::float64_t>::is_iec559, std::numeric_limits<std::float64_t>::is_iec559,
"std::float64_t must fulfill the requirements of IEC 559 (IEEE 754)"); "std::float64_t must fulfill the requirements of IEC 559 (IEEE 754)");
template <>
struct binary_format<std::float64_t> : public binary_format<double> {};
#endif // __STDCPP_FLOAT64_T__ #endif // __STDCPP_FLOAT64_T__
#ifdef __STDCPP_FLOAT32_T__ #ifdef __STDCPP_FLOAT32_T__
@ -1174,6 +1177,9 @@ static_assert(std::is_same<equiv_uint_t<std::float32_t>, uint32_t>::value,
static_assert( static_assert(
std::numeric_limits<std::float32_t>::is_iec559, std::numeric_limits<std::float32_t>::is_iec559,
"std::float32_t must fulfill the requirements of IEC 559 (IEEE 754)"); "std::float32_t must fulfill the requirements of IEC 559 (IEEE 754)");
template <>
struct binary_format<std::float32_t> : public binary_format<float> {};
#endif // __STDCPP_FLOAT32_T__ #endif // __STDCPP_FLOAT32_T__
#ifdef __STDCPP_FLOAT16_T__ #ifdef __STDCPP_FLOAT16_T__

View File

@ -344,44 +344,79 @@ from_chars(UC const *first, UC const *last, T &value, int base) noexcept {
return from_chars_advanced(first, last, value, options); return from_chars_advanced(first, last, value, options);
} }
FASTFLOAT_CONSTEXPR20 inline double template <typename T>
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept { FASTFLOAT_CONSTEXPR20
double value; typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept {
T value;
if (clinger_fast_path_impl(mantissa, decimal_exponent, false, value)) if (clinger_fast_path_impl(mantissa, decimal_exponent, false, value))
return value; return value;
adjusted_mantissa am = adjusted_mantissa am =
compute_float<binary_format<double>>(decimal_exponent, mantissa); compute_float<binary_format<T>>(decimal_exponent, mantissa);
to_float(false, am, value); to_float(false, am, value);
return value; return value;
} }
FASTFLOAT_CONSTEXPR20 inline double template <typename T>
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept { FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept {
const bool is_negative = mantissa < 0; const bool is_negative = mantissa < 0;
const uint64_t m = static_cast<uint64_t>(is_negative ? -mantissa : mantissa); const uint64_t m = static_cast<uint64_t>(is_negative ? -mantissa : mantissa);
double value; T value;
if (clinger_fast_path_impl(m, decimal_exponent, is_negative, value)) if (clinger_fast_path_impl(m, decimal_exponent, is_negative, value))
return value; return value;
adjusted_mantissa am = adjusted_mantissa am = compute_float<binary_format<T>>(decimal_exponent, m);
compute_float<binary_format<double>>(decimal_exponent, m);
to_float(is_negative, am, value); to_float(is_negative, am, value);
return value; return value;
} }
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<double>(mantissa, decimal_exponent);
}
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<double>(mantissa, decimal_exponent);
}
// the following overloads are here to avoid surprising ambiguity for int, // the following overloads are here to avoid surprising ambiguity for int,
// unsigned, etc. // unsigned, etc.
template <typename T, typename Int>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value &&
std::is_integral<Int>::value &&
!std::is_signed<Int>::value,
T>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<T>(static_cast<uint64_t>(mantissa),
decimal_exponent);
}
template <typename T, typename Int>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value &&
std::is_integral<Int>::value &&
std::is_signed<Int>::value,
T>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<T>(static_cast<int64_t>(mantissa),
decimal_exponent);
}
template <typename Int> template <typename Int>
FASTFLOAT_CONSTEXPR20 inline typename std::enable_if< FASTFLOAT_CONSTEXPR20 typename std::enable_if<
std::is_integral<Int>::value && !std::is_signed<Int>::value, double>::type std::is_integral<Int>::value && !std::is_signed<Int>::value, double>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10(static_cast<uint64_t>(mantissa), decimal_exponent); return integer_times_pow10(static_cast<uint64_t>(mantissa), decimal_exponent);
} }
template <typename Int> template <typename Int>
FASTFLOAT_CONSTEXPR20 inline typename std::enable_if< FASTFLOAT_CONSTEXPR20 typename std::enable_if<
std::is_integral<Int>::value && std::is_signed<Int>::value, double>::type std::is_integral<Int>::value && std::is_signed<Int>::value, double>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10(static_cast<int64_t>(mantissa), decimal_exponent); return integer_times_pow10(static_cast<int64_t>(mantissa), decimal_exponent);

View File

@ -1507,9 +1507,20 @@ TEST_CASE("float.inf") {
std::errc::result_out_of_range); std::errc::result_out_of_range);
verify("3.5028234666e38", std::numeric_limits<float>::infinity(), verify("3.5028234666e38", std::numeric_limits<float>::infinity(),
std::errc::result_out_of_range); std::errc::result_out_of_range);
// FLT_MAX + 0.00000007e38
verify("3.40282357e38", std::numeric_limits<float>::infinity(),
std::errc::result_out_of_range);
// FLT_MAX + 0.0000001e38
verify("3.4028236e38", std::numeric_limits<float>::infinity(),
std::errc::result_out_of_range);
} }
TEST_CASE("float.general") { TEST_CASE("float.general") {
// FLT_TRUE_MIN / 2
verify("0.7006492e-45", 0.f, std::errc::result_out_of_range);
// FLT_TRUE_MIN / 2 + 0.0000001e-45
verify("0.7006493e-45", 0x1p-149f);
// max // max
verify("340282346638528859811704183484516925440", 0x1.fffffep+127f); verify("340282346638528859811704183484516925440", 0x1.fffffep+127f);
// -max // -max
@ -2086,12 +2097,11 @@ TEST_CASE("bfloat16.general") {
} }
#endif #endif
template <typename Int> template <typename Int, typename T, typename U>
void verify_integer_multiplication_by_power_of_10(Int mantissa, void verify_integer_times_pow10_result(Int mantissa, int decimal_exponent,
int decimal_exponent, T actual, U expected) {
double expected) { static_assert(std::is_same<T, U>::value,
const double actual = "expected and actual types must match");
fast_float::integer_times_pow10(mantissa, decimal_exponent);
INFO("m * 10^e=" << mantissa << " * 10^" << decimal_exponent INFO("m * 10^e=" << mantissa << " * 10^" << decimal_exponent
<< "\n" << "\n"
@ -2105,45 +2115,173 @@ void verify_integer_multiplication_by_power_of_10(Int mantissa,
CHECK_EQ(actual, expected); CHECK_EQ(actual, expected);
} }
template <typename Int> template <typename T, typename Int>
void verify_integer_multiplication_by_power_of_10(Int mantissa, T calculate_integer_times_pow10_expected_result(Int mantissa,
int decimal_exponent) { int decimal_exponent) {
std::string constructed_string = std::string constructed_string =
std::to_string(mantissa) + "e" + std::to_string(decimal_exponent); std::to_string(mantissa) + "e" + std::to_string(decimal_exponent);
double expected_result; T expected_result;
const auto result = fast_float::from_chars( const auto result = fast_float::from_chars(
constructed_string.data(), constructed_string.data(),
constructed_string.data() + constructed_string.size(), expected_result); constructed_string.data() + constructed_string.size(), expected_result);
if (result.ec != std::errc()) if (result.ec != std::errc())
INFO("Failed to parse: " << constructed_string); INFO("Failed to parse: " << constructed_string);
verify_integer_multiplication_by_power_of_10(mantissa, decimal_exponent, return expected_result;
expected_result);
} }
template <typename Int>
void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent,
double expected) {
static_assert(std::is_integral<Int>::value);
// the "default" overload
const double actual =
fast_float::integer_times_pow10(mantissa, decimal_exponent);
verify_integer_times_pow10_result(mantissa, decimal_exponent, actual,
expected);
}
template <typename Int>
void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent) {
static_assert(std::is_integral<Int>::value);
const auto expected_result =
calculate_integer_times_pow10_expected_result<double>(mantissa,
decimal_exponent);
verify_integer_times_pow10_dflt(mantissa, decimal_exponent, expected_result);
}
template <typename T, typename Int>
void verify_integer_times_pow10(Int mantissa, int decimal_exponent,
T expected) {
static_assert(std::is_floating_point<T>::value);
static_assert(std::is_integral<Int>::value);
// explicit specialization
const auto actual =
fast_float::integer_times_pow10<T>(mantissa, decimal_exponent);
verify_integer_times_pow10_result(mantissa, decimal_exponent, actual,
expected);
}
template <typename T, typename Int>
void verify_integer_times_pow10(Int mantissa, int decimal_exponent) {
static_assert(std::is_floating_point<T>::value);
static_assert(std::is_integral<Int>::value);
const auto expected_result = calculate_integer_times_pow10_expected_result<T>(
mantissa, decimal_exponent);
verify_integer_times_pow10(mantissa, decimal_exponent, expected_result);
}
namespace all_supported_types {
template <typename Int>
void verify_integer_times_pow10(Int mantissa, int decimal_exponent) {
static_assert(std::is_integral<Int>::value);
// verify the "default" overload
verify_integer_times_pow10_dflt(mantissa, decimal_exponent);
// verify explicit specializations
::verify_integer_times_pow10<double>(mantissa, decimal_exponent);
::verify_integer_times_pow10<float>(mantissa, decimal_exponent);
#if defined(__STDCPP_FLOAT64_T__)
::verify_integer_times_pow10<std::float64_t>(mantissa, decimal_exponent);
#endif
#if defined(__STDCPP_FLOAT32_T__)
::verify_integer_times_pow10<std::float32_t>(mantissa, decimal_exponent);
#endif
#if defined(__STDCPP_FLOAT16_T__)
::verify_integer_times_pow10<std::float16_t>(mantissa, decimal_exponent);
#endif
#if defined(__STDCPP_BFLOAT16_T__)
::verify_integer_times_pow10<std::bfloat16_t>(mantissa, decimal_exponent);
#endif
}
} // namespace all_supported_types
TEST_CASE("integer_times_pow10") { TEST_CASE("integer_times_pow10") {
// explicitly verifying API with different types of integers /* explicitly verifying API with different types of integers */
verify_integer_multiplication_by_power_of_10<int8_t>(31, -1, 3.1); // double (the "default" overload)
verify_integer_multiplication_by_power_of_10<int8_t>(-31, -1, -3.1); verify_integer_times_pow10_dflt<int8_t>(31, -1, 3.1);
verify_integer_multiplication_by_power_of_10<uint8_t>(31, -1, 3.1); verify_integer_times_pow10_dflt<int8_t>(-31, -1, -3.1);
verify_integer_multiplication_by_power_of_10<int16_t>(31415, -4, 3.1415); verify_integer_times_pow10_dflt<uint8_t>(31, -1, 3.1);
verify_integer_multiplication_by_power_of_10<int16_t>(-31415, -4, -3.1415); verify_integer_times_pow10_dflt<int16_t>(31415, -4, 3.1415);
verify_integer_multiplication_by_power_of_10<uint16_t>(31415, -4, 3.1415); verify_integer_times_pow10_dflt<int16_t>(-31415, -4, -3.1415);
verify_integer_multiplication_by_power_of_10<int32_t>(314159265, -8, verify_integer_times_pow10_dflt<uint16_t>(31415, -4, 3.1415);
3.14159265); verify_integer_times_pow10_dflt<int32_t>(314159265, -8, 3.14159265);
verify_integer_multiplication_by_power_of_10<int32_t>(-314159265, -8, verify_integer_times_pow10_dflt<int32_t>(-314159265, -8, -3.14159265);
-3.14159265); verify_integer_times_pow10_dflt<uint32_t>(3141592653, -9, 3.141592653);
verify_integer_multiplication_by_power_of_10<uint32_t>(3141592653, -9, verify_integer_times_pow10_dflt<long>(314159265, -8, 3.14159265);
verify_integer_times_pow10_dflt<long>(-314159265, -8, -3.14159265);
verify_integer_times_pow10_dflt<unsigned long>(3141592653, -9, 3.141592653);
verify_integer_times_pow10_dflt<int64_t>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10_dflt<int64_t>(-3141592653589793238, -18,
-3.141592653589793238);
verify_integer_times_pow10_dflt<uint64_t>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10_dflt<long long>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10_dflt<long long>(-3141592653589793238, -18,
-3.141592653589793238);
verify_integer_times_pow10_dflt<unsigned long long>(3141592653589793238, -18,
3.141592653589793238);
// double (explicit specialization)
verify_integer_times_pow10<double, int8_t>(31, -1, 3.1);
verify_integer_times_pow10<double, int8_t>(-31, -1, -3.1);
verify_integer_times_pow10<double, uint8_t>(31, -1, 3.1);
verify_integer_times_pow10<double, int16_t>(31415, -4, 3.1415);
verify_integer_times_pow10<double, int16_t>(-31415, -4, -3.1415);
verify_integer_times_pow10<double, uint16_t>(31415, -4, 3.1415);
verify_integer_times_pow10<double, int32_t>(314159265, -8, 3.14159265);
verify_integer_times_pow10<double, int32_t>(-314159265, -8, -3.14159265);
verify_integer_times_pow10<double, uint32_t>(3141592653, -9, 3.141592653);
verify_integer_times_pow10<double, long>(314159265, -8, 3.14159265);
verify_integer_times_pow10<double, long>(-314159265, -8, -3.14159265);
verify_integer_times_pow10<double, unsigned long>(3141592653, -9,
3.141592653); 3.141592653);
verify_integer_multiplication_by_power_of_10<int64_t>( verify_integer_times_pow10<double, int64_t>(3141592653589793238, -18,
3141592653589793238, -18, 3.141592653589793238); 3.141592653589793238);
verify_integer_multiplication_by_power_of_10<int64_t>( verify_integer_times_pow10<double, int64_t>(-3141592653589793238, -18,
-3141592653589793238, -18, -3.141592653589793238); -3.141592653589793238);
verify_integer_multiplication_by_power_of_10<uint64_t>( verify_integer_times_pow10<double, uint64_t>(3141592653589793238, -18,
3141592653589793238, -18, 3.141592653589793238); 3.141592653589793238);
verify_integer_multiplication_by_power_of_10<long long>( verify_integer_times_pow10<double, long long>(3141592653589793238, -18,
-3141592653589793238, -18, -3.141592653589793238); 3.141592653589793238);
verify_integer_multiplication_by_power_of_10<unsigned long long>( verify_integer_times_pow10<double, long long>(-3141592653589793238, -18,
-3.141592653589793238);
verify_integer_times_pow10<double, unsigned long long>(
3141592653589793238, -18, 3.141592653589793238); 3141592653589793238, -18, 3.141592653589793238);
// float (explicit specialization)
verify_integer_times_pow10<float, int8_t>(31, -1, 3.1f);
verify_integer_times_pow10<float, int8_t>(-31, -1, -3.1f);
verify_integer_times_pow10<float, uint8_t>(31, -1, 3.1f);
verify_integer_times_pow10<float, int16_t>(31415, -4, 3.1415f);
verify_integer_times_pow10<float, int16_t>(-31415, -4, -3.1415f);
verify_integer_times_pow10<float, uint16_t>(31415, -4, 3.1415f);
verify_integer_times_pow10<float, int32_t>(314159265, -8, 3.14159265f);
verify_integer_times_pow10<float, int32_t>(-314159265, -8, -3.14159265f);
verify_integer_times_pow10<float, uint32_t>(3141592653, -9, 3.14159265f);
verify_integer_times_pow10<float, long>(314159265, -8, 3.14159265f);
verify_integer_times_pow10<float, long>(-314159265, -8, -3.14159265f);
verify_integer_times_pow10<float, unsigned long>(3141592653, -9, 3.14159265f);
verify_integer_times_pow10<float, int64_t>(3141592653589793238, -18,
3.141592653589793238f);
verify_integer_times_pow10<float, int64_t>(-3141592653589793238, -18,
-3.141592653589793238f);
verify_integer_times_pow10<float, uint64_t>(3141592653589793238, -18,
3.141592653589793238f);
verify_integer_times_pow10<float, long long>(3141592653589793238, -18,
3.141592653589793238f);
verify_integer_times_pow10<float, long long>(-3141592653589793238, -18,
-3.141592653589793238f);
verify_integer_times_pow10<float, unsigned long long>(
3141592653589793238, -18, 3.141592653589793238f);
for (int mode : {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, FE_TONEAREST}) { for (int mode : {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, FE_TONEAREST}) {
fesetround(mode); fesetround(mode);
@ -2153,87 +2291,122 @@ TEST_CASE("integer_times_pow10") {
~Guard() { fesetround(FE_TONEAREST); } ~Guard() { fesetround(FE_TONEAREST); }
} guard; } guard;
verify_integer_multiplication_by_power_of_10(0, 0); namespace all = all_supported_types;
verify_integer_multiplication_by_power_of_10(1, 0);
verify_integer_multiplication_by_power_of_10(0, 1);
verify_integer_multiplication_by_power_of_10(1, 1);
verify_integer_multiplication_by_power_of_10(-1, 0);
verify_integer_multiplication_by_power_of_10(0, -1);
verify_integer_multiplication_by_power_of_10(-1, -1);
verify_integer_multiplication_by_power_of_10(-1, 1);
verify_integer_multiplication_by_power_of_10(1, -1);
verify_integer_multiplication_by_power_of_10( all::verify_integer_times_pow10(0, 0);
all::verify_integer_times_pow10(1, 0);
all::verify_integer_times_pow10(0, 1);
all::verify_integer_times_pow10(1, 1);
all::verify_integer_times_pow10(-1, 0);
all::verify_integer_times_pow10(0, -1);
all::verify_integer_times_pow10(-1, -1);
all::verify_integer_times_pow10(-1, 1);
all::verify_integer_times_pow10(1, -1);
/* denormal min */
verify_integer_times_pow10_dflt(49406564584124654, -340,
std::numeric_limits<double>::denorm_min());
verify_integer_times_pow10<double>(
49406564584124654, -340, std::numeric_limits<double>::denorm_min()); 49406564584124654, -340, std::numeric_limits<double>::denorm_min());
verify_integer_multiplication_by_power_of_10( verify_integer_times_pow10<float>(14012984, -52,
22250738585072014, -324, std::numeric_limits<double>::min()); std::numeric_limits<float>::denorm_min());
verify_integer_multiplication_by_power_of_10(
17976931348623158, 292, std::numeric_limits<double>::max());
// DBL_TRUE_MIN / 2 underflows to 0 /* normal min */
verify_integer_multiplication_by_power_of_10(49406564584124654 / 2, -340, verify_integer_times_pow10_dflt(22250738585072014, -324,
0.); std::numeric_limits<double>::min());
verify_integer_times_pow10<double>(22250738585072014, -324,
std::numeric_limits<double>::min());
verify_integer_times_pow10<float>(11754944, -45,
std::numeric_limits<float>::min());
// DBL_TRUE_MIN / 2 + 0.0000000000000001e-324 rounds to DBL_TRUE_MIN /* max */
verify_integer_multiplication_by_power_of_10( verify_integer_times_pow10_dflt(17976931348623158, 292,
std::numeric_limits<double>::max());
verify_integer_times_pow10<double>(17976931348623158, 292,
std::numeric_limits<double>::max());
verify_integer_times_pow10<float>(34028235, 31,
std::numeric_limits<float>::max());
/* underflow */
// (DBL_TRUE_MIN / 2) underflows to 0
verify_integer_times_pow10_dflt(49406564584124654 / 2, -340, 0.);
verify_integer_times_pow10<double>(49406564584124654 / 2, -340, 0.);
// (FLT_TRUE_MIN / 2) underflows to 0
verify_integer_times_pow10<float>(14012984 / 2, -52, 0.f);
/* rounding to denormal min */
// (DBL_TRUE_MIN / 2 + 0.0000000000000001e-324) rounds to DBL_TRUE_MIN
verify_integer_times_pow10_dflt(49406564584124654 / 2 + 1, -340,
std::numeric_limits<double>::denorm_min());
verify_integer_times_pow10<double>(
49406564584124654 / 2 + 1, -340, 49406564584124654 / 2 + 1, -340,
std::numeric_limits<double>::denorm_min()); std::numeric_limits<double>::denorm_min());
// (FLT_TRUE_MIN / 2 + 0.0000001e-45) rounds to FLT_TRUE_MIN
verify_integer_times_pow10<float>(14012984 / 2 + 1, -52,
std::numeric_limits<float>::denorm_min());
// DBL_MAX + 0.0000000000000001e308 overflows to infinity /* overflow */
verify_integer_multiplication_by_power_of_10( // (DBL_MAX + 0.0000000000000001e308) overflows to infinity
17976931348623158 + 1, 292, std::numeric_limits<double>::infinity()); verify_integer_times_pow10_dflt(17976931348623158 + 1, 292,
// DBL_MAX + 0.00000000000000001e308 overflows to infinity std::numeric_limits<double>::infinity());
verify_integer_multiplication_by_power_of_10( verify_integer_times_pow10<double>(17976931348623158 + 1, 292,
179769313486231580 + 1, 291, std::numeric_limits<double>::infinity()); std::numeric_limits<double>::infinity());
// (DBL_MAX + 0.00000000000000001e308) overflows to infinity
verify_integer_times_pow10_dflt(179769313486231580 + 1, 291,
std::numeric_limits<double>::infinity());
verify_integer_times_pow10<double>(179769313486231580 + 1, 291,
std::numeric_limits<double>::infinity());
// (FLT_MAX + 0.0000001e38) overflows to infinity
verify_integer_times_pow10<float>(34028235 + 1, 31,
std::numeric_limits<float>::infinity());
// (FLT_MAX + 0.00000007e38) overflows to infinity
verify_integer_times_pow10<float>(340282350 + 7, 30,
std::numeric_limits<float>::infinity());
// loosely verifying correct rounding of 1 to 64 bits // loosely verifying correct rounding of 1 to 64 bits
// worth of significant digits // worth of significant digits
verify_integer_multiplication_by_power_of_10(1, 42); all::verify_integer_times_pow10(1, 42);
verify_integer_multiplication_by_power_of_10(1, -42); all::verify_integer_times_pow10(1, -42);
verify_integer_multiplication_by_power_of_10(12, 42); all::verify_integer_times_pow10(12, 42);
verify_integer_multiplication_by_power_of_10(12, -42); all::verify_integer_times_pow10(12, -42);
verify_integer_multiplication_by_power_of_10(123, 42); all::verify_integer_times_pow10(123, 42);
verify_integer_multiplication_by_power_of_10(123, -42); all::verify_integer_times_pow10(123, -42);
verify_integer_multiplication_by_power_of_10(1234, 42); all::verify_integer_times_pow10(1234, 42);
verify_integer_multiplication_by_power_of_10(1234, -42); all::verify_integer_times_pow10(1234, -42);
verify_integer_multiplication_by_power_of_10(12345, 42); all::verify_integer_times_pow10(12345, 42);
verify_integer_multiplication_by_power_of_10(12345, -42); all::verify_integer_times_pow10(12345, -42);
verify_integer_multiplication_by_power_of_10(123456, 42); all::verify_integer_times_pow10(123456, 42);
verify_integer_multiplication_by_power_of_10(123456, -42); all::verify_integer_times_pow10(123456, -42);
verify_integer_multiplication_by_power_of_10(1234567, 42); all::verify_integer_times_pow10(1234567, 42);
verify_integer_multiplication_by_power_of_10(1234567, -42); all::verify_integer_times_pow10(1234567, -42);
verify_integer_multiplication_by_power_of_10(12345678, 42); all::verify_integer_times_pow10(12345678, 42);
verify_integer_multiplication_by_power_of_10(12345678, -42); all::verify_integer_times_pow10(12345678, -42);
verify_integer_multiplication_by_power_of_10(123456789, 42); all::verify_integer_times_pow10(123456789, 42);
verify_integer_multiplication_by_power_of_10(1234567890, 42); all::verify_integer_times_pow10(1234567890, 42);
verify_integer_multiplication_by_power_of_10(1234567890, -42); all::verify_integer_times_pow10(1234567890, -42);
verify_integer_multiplication_by_power_of_10(12345678901, 42); all::verify_integer_times_pow10(12345678901, 42);
verify_integer_multiplication_by_power_of_10(12345678901, -42); all::verify_integer_times_pow10(12345678901, -42);
verify_integer_multiplication_by_power_of_10(123456789012, 42); all::verify_integer_times_pow10(123456789012, 42);
verify_integer_multiplication_by_power_of_10(123456789012, -42); all::verify_integer_times_pow10(123456789012, -42);
verify_integer_multiplication_by_power_of_10(1234567890123, 42); all::verify_integer_times_pow10(1234567890123, 42);
verify_integer_multiplication_by_power_of_10(1234567890123, -42); all::verify_integer_times_pow10(1234567890123, -42);
verify_integer_multiplication_by_power_of_10(12345678901234, 42); all::verify_integer_times_pow10(12345678901234, 42);
verify_integer_multiplication_by_power_of_10(12345678901234, -42); all::verify_integer_times_pow10(12345678901234, -42);
verify_integer_multiplication_by_power_of_10(123456789012345, 42); all::verify_integer_times_pow10(123456789012345, 42);
verify_integer_multiplication_by_power_of_10(123456789012345, -42); all::verify_integer_times_pow10(123456789012345, -42);
verify_integer_multiplication_by_power_of_10(1234567890123456, 42); all::verify_integer_times_pow10(1234567890123456, 42);
verify_integer_multiplication_by_power_of_10(1234567890123456, -42); all::verify_integer_times_pow10(1234567890123456, -42);
verify_integer_multiplication_by_power_of_10(12345678901234567, 42); all::verify_integer_times_pow10(12345678901234567, 42);
verify_integer_multiplication_by_power_of_10(12345678901234567, -42); all::verify_integer_times_pow10(12345678901234567, -42);
verify_integer_multiplication_by_power_of_10(123456789012345678, 42); all::verify_integer_times_pow10(123456789012345678, 42);
verify_integer_multiplication_by_power_of_10(123456789012345678, -42); all::verify_integer_times_pow10(123456789012345678, -42);
verify_integer_multiplication_by_power_of_10(1234567890123456789, 42); all::verify_integer_times_pow10(1234567890123456789, 42);
verify_integer_multiplication_by_power_of_10(1234567890123456789, -42); all::verify_integer_times_pow10(1234567890123456789, -42);
verify_integer_multiplication_by_power_of_10(12345678901234567890ull, 42); all::verify_integer_times_pow10(12345678901234567890ull, 42);
verify_integer_multiplication_by_power_of_10(12345678901234567890ull, -42); all::verify_integer_times_pow10(12345678901234567890ull, -42);
verify_integer_multiplication_by_power_of_10( all::verify_integer_times_pow10(std::numeric_limits<int64_t>::max(), 42);
std::numeric_limits<int64_t>::max(), 42); all::verify_integer_times_pow10(std::numeric_limits<int64_t>::max(), -42);
verify_integer_multiplication_by_power_of_10( all::verify_integer_times_pow10(std::numeric_limits<uint64_t>::max(), 42);
std::numeric_limits<int64_t>::max(), -42); all::verify_integer_times_pow10(std::numeric_limits<uint64_t>::max(), -42);
verify_integer_multiplication_by_power_of_10(
std::numeric_limits<uint64_t>::max(), 42);
verify_integer_multiplication_by_power_of_10(
std::numeric_limits<uint64_t>::max(), -42);
} }
} }

View File

@ -2,7 +2,7 @@
#include <iostream> #include <iostream>
int main() { void default_overload() {
const uint64_t W = 12345678901234567; const uint64_t W = 12345678901234567;
const int Q = 23; const int Q = 23;
const double result = fast_float::integer_times_pow10(W, Q); const double result = fast_float::integer_times_pow10(W, Q);
@ -10,3 +10,27 @@ int main() {
std::cout << W << " * 10^" << Q << " = " << result << " (" std::cout << W << " * 10^" << Q << " = " << result << " ("
<< (result == 12345678901234567e23 ? "==" : "!=") << "expected)\n"; << (result == 12345678901234567e23 ? "==" : "!=") << "expected)\n";
} }
void double_specialization() {
const uint64_t W = 12345678901234567;
const int Q = 23;
const double result = fast_float::integer_times_pow10<double>(W, Q);
std::cout.precision(17);
std::cout << "double: " << W << " * 10^" << Q << " = " << result << " ("
<< (result == 12345678901234567e23 ? "==" : "!=") << "expected)\n";
}
void float_specialization() {
const uint64_t W = 12345678;
const int Q = 23;
const float result = fast_float::integer_times_pow10<float>(W, Q);
std::cout.precision(9);
std::cout << "float: " << W << " * 10^" << Q << " = " << result << " ("
<< (result == 12345678e23f ? "==" : "!=") << "expected)\n";
}
int main() {
default_overload();
double_specialization();
float_specialization();
}