This commit is contained in:
IRainman 2025-10-21 15:43:38 +03:00
commit 0f1a96a389
7 changed files with 422 additions and 124 deletions

View File

@ -428,6 +428,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
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
signed and unsigned integer types: `int64_t`, `uint64_t`, etc.
@ -469,7 +486,7 @@ framework](https://github.com/microsoft/LightGBM).
Packages
------
[![Packaging status](https://repology.org/badge/vertical-allrepos/fastfloat.svg)](https://repology.org/project/fastfloat/versions)
[![Packaging status](https://repology.org/badge/vertical-allrepos/fast-float.svg)](https://repology.org/project/fast-float/versions)
## References
@ -624,6 +641,11 @@ long digits.
The library includes code adapted from Google Wuffs (written by Nigel Tao) which
was originally published under the Apache 2.0 license.
## Stars
[![Star History Chart](https://api.star-history.com/svg?repos=fastfloat/fast_float&type=Date)](https://www.star-history.com/#fastfloat/fast_float&Date)
## License
<sup>

View File

@ -40,9 +40,7 @@ constexpr static uint64_t powers_of_ten_uint64[] = {1UL,
// to slow down performance for faster algorithms, and this is still fast.
template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 am_pow_t
scientific_exponent(parsed_number_string_t<UC> const &num) noexcept {
am_mant_t mantissa = num.mantissa;
am_pow_t exponent = num.exponent;
scientific_exponent(am_mant_t mantissa, am_pow_t exponent) noexcept {
while (mantissa >= 10000) {
mantissa /= 10000;
exponent += 4;
@ -413,7 +411,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
FASTFLOAT_ASSERT(real_digits.pow2(-pow2_exp));
}
// compare digits, and use it to director rounding
// compare digits, and use it to direct rounding
int ord = real_digits.compare(theor_digits);
round<T>(am, [ord](adjusted_mantissa &a, am_pow_t shift) {
round_nearest_tie_even(
@ -433,7 +431,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
return am;
}
// parse the significant digits as a big integer to unambiguously round the
// parse the significant digits as a big integer to unambiguously round
// the significant digits. here, we are trying to determine how to round
// an extended float representation close to `b+h`, halfway between `b`
// (the float rounded-down) and `b+u`, the next positive float. this
@ -452,9 +450,8 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp(
// remove the invalid exponent bias
am.power2 -= invalid_am_bias;
bigint bigmant;
am_pow_t const sci_exp = scientific_exponent(num);
bigint bigmant;
am_digits const digits = parse_mantissa<T, UC>(bigmant, num);
// can't underflow, since digits is at most max_digits.
am_pow_t const exponent =

View File

@ -65,6 +65,20 @@ FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(int64_t const mantissa,
int const 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.
*/

View File

@ -1238,6 +1238,9 @@ static_assert(std::is_same<equiv_uint_t<std::float64_t>, uint64_t>::value,
static_assert(
std::numeric_limits<std::float64_t>::is_iec559,
"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__
#ifdef __STDCPP_FLOAT32_T__
@ -1246,6 +1249,9 @@ static_assert(std::is_same<equiv_uint_t<std::float32_t>, uint32_t>::value,
static_assert(
std::numeric_limits<std::float32_t>::is_iec559,
"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__
#ifdef __STDCPP_FLOAT16_T__

View File

@ -384,10 +384,11 @@ from_chars(UC const *first, UC const *last, T &value, int const base) noexcept {
return from_chars_advanced(first, last, value, options);
}
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(uint64_t const mantissa,
int const decimal_exponent) noexcept {
double value;
template <typename T>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(uint64_t mantissa, int const decimal_exponent) noexcept {
T value;
if (clinger_fast_path_impl(mantissa, decimal_exponent,
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
false,
@ -405,9 +406,10 @@ integer_times_pow10(uint64_t const mantissa,
return value;
}
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(int64_t const mantissa,
int const 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 const decimal_exponent) noexcept {
#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
FASTFLOAT_ASSUME(mantissa > 0);
const uint64_t m = static_cast<uint64_t>(mantissa);
@ -433,17 +435,49 @@ integer_times_pow10(int64_t const mantissa,
return value;
}
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(uint64_t mantissa, int const decimal_exponent) noexcept {
return integer_times_pow10<double>(mantissa, decimal_exponent);
}
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(int64_t mantissa, int const decimal_exponent) noexcept {
return integer_times_pow10<double>(mantissa, decimal_exponent);
}
// the following overloads are here to avoid surprising ambiguity for int,
// 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>
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
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10(static_cast<uint64_t>(mantissa), decimal_exponent);
}
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
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10(static_cast<int64_t>(mantissa), decimal_exponent);

View File

@ -1142,6 +1142,15 @@ TEST_CASE("double.inf") {
// DBL_MAX + 0.0000000000000001e308
verify("1.7976931348623159e308", std::numeric_limits<double>::infinity(),
std::errc::result_out_of_range);
// ( (2 - 0.5*2^(52)) * 2^1023 ) smallest number that overflows to infinity
verify("179769313486231580793728971405303415079934132710037826936173778980444"
"968292764750946649017977587207096330286416692887910946555547851940402"
"630657488671505820681908902000708383676273854845817711531764475730270"
"069855571366959622842914819860834936475292719074168444365510704342711"
"559699508093042880177904174497792",
std::numeric_limits<double>::infinity(),
std::errc::result_out_of_range);
}
TEST_CASE("double.general") {
@ -1333,6 +1342,15 @@ TEST_CASE("double.general") {
std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
verify("-2240084132271013504.131248280843119943687942846658579428",
-0x1.f1660a65b00bfp+60);
// ( (2 - 0.5*2^(52)) * 2^1023 - 1 ) largest 309 decimal digit number
// that rounds to DBL_MAX
verify("179769313486231580793728971405303415079934132710037826936173778980444"
"968292764750946649017977587207096330286416692887910946555547851940402"
"630657488671505820681908902000708383676273854845817711531764475730270"
"069855571366959622842914819860834936475292719074168444365510704342711"
"559699508093042880177904174497791",
std::numeric_limits<double>::max());
}
TEST_CASE("double.decimal_point") {
@ -1507,14 +1525,35 @@ TEST_CASE("float.inf") {
std::errc::result_out_of_range);
verify("3.5028234666e38", std::numeric_limits<float>::infinity(),
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);
// ( (2 - 0.5*2^(-23)) * 2^127 ) smallest number that overflows to infinity
verify("340282356779733661637539395458142568448",
std::numeric_limits<float>::infinity(),
std::errc::result_out_of_range);
}
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
verify("340282346638528859811704183484516925440", 0x1.fffffep+127f);
// -max
verify("-340282346638528859811704183484516925440", -0x1.fffffep+127f);
// ( (2 - 0.5*2^(-23)) * 2^127 - 1 ) largest 39 decimal digits number
// that rounds to FLT_MAX
verify("340282356779733661637539395458142568447",
std::numeric_limits<float>::max());
verify("-1e-999", -0.0f, std::errc::result_out_of_range);
verify("1."
"175494140627517859246175898662808184331245864732796240031385942718174"
@ -2086,12 +2125,11 @@ TEST_CASE("bfloat16.general") {
}
#endif
template <typename Int>
void verify_integer_multiplication_by_power_of_10(Int mantissa,
int decimal_exponent,
double expected) {
const double actual =
fast_float::integer_times_pow10(mantissa, decimal_exponent);
template <typename Int, typename T, typename U>
void verify_integer_times_pow10_result(Int mantissa, int decimal_exponent,
T actual, U expected) {
static_assert(std::is_same<T, U>::value,
"expected and actual types must match");
INFO("m * 10^e=" << mantissa << " * 10^" << decimal_exponent
<< "\n"
@ -2105,45 +2143,173 @@ void verify_integer_multiplication_by_power_of_10(Int mantissa,
CHECK_EQ(actual, expected);
}
template <typename Int>
void verify_integer_multiplication_by_power_of_10(Int mantissa,
template <typename T, typename Int>
T calculate_integer_times_pow10_expected_result(Int mantissa,
int decimal_exponent) {
std::string constructed_string =
std::to_string(mantissa) + "e" + std::to_string(decimal_exponent);
double expected_result;
T expected_result;
const auto result = fast_float::from_chars(
constructed_string.data(),
constructed_string.data() + constructed_string.size(), expected_result);
if (result.ec != std::errc())
INFO("Failed to parse: " << constructed_string);
verify_integer_multiplication_by_power_of_10(mantissa, decimal_exponent,
expected_result);
return 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") {
// explicitly verifying API with different types of integers
verify_integer_multiplication_by_power_of_10<int8_t>(31, -1, 3.1);
verify_integer_multiplication_by_power_of_10<int8_t>(-31, -1, -3.1);
verify_integer_multiplication_by_power_of_10<uint8_t>(31, -1, 3.1);
verify_integer_multiplication_by_power_of_10<int16_t>(31415, -4, 3.1415);
verify_integer_multiplication_by_power_of_10<int16_t>(-31415, -4, -3.1415);
verify_integer_multiplication_by_power_of_10<uint16_t>(31415, -4, 3.1415);
verify_integer_multiplication_by_power_of_10<int32_t>(314159265, -8,
3.14159265);
verify_integer_multiplication_by_power_of_10<int32_t>(-314159265, -8,
-3.14159265);
verify_integer_multiplication_by_power_of_10<uint32_t>(3141592653, -9,
/* explicitly verifying API with different types of integers */
// double (the "default" overload)
verify_integer_times_pow10_dflt<int8_t>(31, -1, 3.1);
verify_integer_times_pow10_dflt<int8_t>(-31, -1, -3.1);
verify_integer_times_pow10_dflt<uint8_t>(31, -1, 3.1);
verify_integer_times_pow10_dflt<int16_t>(31415, -4, 3.1415);
verify_integer_times_pow10_dflt<int16_t>(-31415, -4, -3.1415);
verify_integer_times_pow10_dflt<uint16_t>(31415, -4, 3.1415);
verify_integer_times_pow10_dflt<int32_t>(314159265, -8, 3.14159265);
verify_integer_times_pow10_dflt<int32_t>(-314159265, -8, -3.14159265);
verify_integer_times_pow10_dflt<uint32_t>(3141592653, -9, 3.141592653);
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);
verify_integer_multiplication_by_power_of_10<int64_t>(
3141592653589793238, -18, 3.141592653589793238);
verify_integer_multiplication_by_power_of_10<int64_t>(
-3141592653589793238, -18, -3.141592653589793238);
verify_integer_multiplication_by_power_of_10<uint64_t>(
3141592653589793238, -18, 3.141592653589793238);
verify_integer_multiplication_by_power_of_10<long long>(
-3141592653589793238, -18, -3.141592653589793238);
verify_integer_multiplication_by_power_of_10<unsigned long long>(
verify_integer_times_pow10<double, int64_t>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10<double, int64_t>(-3141592653589793238, -18,
-3.141592653589793238);
verify_integer_times_pow10<double, uint64_t>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10<double, long long>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10<double, long long>(-3141592653589793238, -18,
-3.141592653589793238);
verify_integer_times_pow10<double, unsigned long long>(
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}) {
fesetround(mode);
@ -2153,87 +2319,122 @@ TEST_CASE("integer_times_pow10") {
~Guard() { fesetround(FE_TONEAREST); }
} guard;
verify_integer_multiplication_by_power_of_10(0, 0);
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);
namespace all = all_supported_types;
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());
verify_integer_multiplication_by_power_of_10(
22250738585072014, -324, std::numeric_limits<double>::min());
verify_integer_multiplication_by_power_of_10(
17976931348623158, 292, std::numeric_limits<double>::max());
verify_integer_times_pow10<float>(14012984, -52,
std::numeric_limits<float>::denorm_min());
// DBL_TRUE_MIN / 2 underflows to 0
verify_integer_multiplication_by_power_of_10(49406564584124654 / 2, -340,
0.);
/* normal min */
verify_integer_times_pow10_dflt(22250738585072014, -324,
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
verify_integer_multiplication_by_power_of_10(
/* max */
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,
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
verify_integer_multiplication_by_power_of_10(
17976931348623158 + 1, 292, std::numeric_limits<double>::infinity());
// DBL_MAX + 0.00000000000000001e308 overflows to infinity
verify_integer_multiplication_by_power_of_10(
179769313486231580 + 1, 291, std::numeric_limits<double>::infinity());
/* overflow */
// (DBL_MAX + 0.0000000000000001e308) overflows to infinity
verify_integer_times_pow10_dflt(17976931348623158 + 1, 292,
std::numeric_limits<double>::infinity());
verify_integer_times_pow10<double>(17976931348623158 + 1, 292,
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
// worth of significant digits
verify_integer_multiplication_by_power_of_10(1, 42);
verify_integer_multiplication_by_power_of_10(1, -42);
verify_integer_multiplication_by_power_of_10(12, 42);
verify_integer_multiplication_by_power_of_10(12, -42);
verify_integer_multiplication_by_power_of_10(123, 42);
verify_integer_multiplication_by_power_of_10(123, -42);
verify_integer_multiplication_by_power_of_10(1234, 42);
verify_integer_multiplication_by_power_of_10(1234, -42);
verify_integer_multiplication_by_power_of_10(12345, 42);
verify_integer_multiplication_by_power_of_10(12345, -42);
verify_integer_multiplication_by_power_of_10(123456, 42);
verify_integer_multiplication_by_power_of_10(123456, -42);
verify_integer_multiplication_by_power_of_10(1234567, 42);
verify_integer_multiplication_by_power_of_10(1234567, -42);
verify_integer_multiplication_by_power_of_10(12345678, 42);
verify_integer_multiplication_by_power_of_10(12345678, -42);
verify_integer_multiplication_by_power_of_10(123456789, 42);
verify_integer_multiplication_by_power_of_10(1234567890, 42);
verify_integer_multiplication_by_power_of_10(1234567890, -42);
verify_integer_multiplication_by_power_of_10(12345678901, 42);
verify_integer_multiplication_by_power_of_10(12345678901, -42);
verify_integer_multiplication_by_power_of_10(123456789012, 42);
verify_integer_multiplication_by_power_of_10(123456789012, -42);
verify_integer_multiplication_by_power_of_10(1234567890123, 42);
verify_integer_multiplication_by_power_of_10(1234567890123, -42);
verify_integer_multiplication_by_power_of_10(12345678901234, 42);
verify_integer_multiplication_by_power_of_10(12345678901234, -42);
verify_integer_multiplication_by_power_of_10(123456789012345, 42);
verify_integer_multiplication_by_power_of_10(123456789012345, -42);
verify_integer_multiplication_by_power_of_10(1234567890123456, 42);
verify_integer_multiplication_by_power_of_10(1234567890123456, -42);
verify_integer_multiplication_by_power_of_10(12345678901234567, 42);
verify_integer_multiplication_by_power_of_10(12345678901234567, -42);
verify_integer_multiplication_by_power_of_10(123456789012345678, 42);
verify_integer_multiplication_by_power_of_10(123456789012345678, -42);
verify_integer_multiplication_by_power_of_10(1234567890123456789, 42);
verify_integer_multiplication_by_power_of_10(1234567890123456789, -42);
verify_integer_multiplication_by_power_of_10(12345678901234567890ull, 42);
verify_integer_multiplication_by_power_of_10(12345678901234567890ull, -42);
verify_integer_multiplication_by_power_of_10(
std::numeric_limits<int64_t>::max(), 42);
verify_integer_multiplication_by_power_of_10(
std::numeric_limits<int64_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);
all::verify_integer_times_pow10(1, 42);
all::verify_integer_times_pow10(1, -42);
all::verify_integer_times_pow10(12, 42);
all::verify_integer_times_pow10(12, -42);
all::verify_integer_times_pow10(123, 42);
all::verify_integer_times_pow10(123, -42);
all::verify_integer_times_pow10(1234, 42);
all::verify_integer_times_pow10(1234, -42);
all::verify_integer_times_pow10(12345, 42);
all::verify_integer_times_pow10(12345, -42);
all::verify_integer_times_pow10(123456, 42);
all::verify_integer_times_pow10(123456, -42);
all::verify_integer_times_pow10(1234567, 42);
all::verify_integer_times_pow10(1234567, -42);
all::verify_integer_times_pow10(12345678, 42);
all::verify_integer_times_pow10(12345678, -42);
all::verify_integer_times_pow10(123456789, 42);
all::verify_integer_times_pow10(1234567890, 42);
all::verify_integer_times_pow10(1234567890, -42);
all::verify_integer_times_pow10(12345678901, 42);
all::verify_integer_times_pow10(12345678901, -42);
all::verify_integer_times_pow10(123456789012, 42);
all::verify_integer_times_pow10(123456789012, -42);
all::verify_integer_times_pow10(1234567890123, 42);
all::verify_integer_times_pow10(1234567890123, -42);
all::verify_integer_times_pow10(12345678901234, 42);
all::verify_integer_times_pow10(12345678901234, -42);
all::verify_integer_times_pow10(123456789012345, 42);
all::verify_integer_times_pow10(123456789012345, -42);
all::verify_integer_times_pow10(1234567890123456, 42);
all::verify_integer_times_pow10(1234567890123456, -42);
all::verify_integer_times_pow10(12345678901234567, 42);
all::verify_integer_times_pow10(12345678901234567, -42);
all::verify_integer_times_pow10(123456789012345678, 42);
all::verify_integer_times_pow10(123456789012345678, -42);
all::verify_integer_times_pow10(1234567890123456789, 42);
all::verify_integer_times_pow10(1234567890123456789, -42);
all::verify_integer_times_pow10(12345678901234567890ull, 42);
all::verify_integer_times_pow10(12345678901234567890ull, -42);
all::verify_integer_times_pow10(std::numeric_limits<int64_t>::max(), 42);
all::verify_integer_times_pow10(std::numeric_limits<int64_t>::max(), -42);
all::verify_integer_times_pow10(std::numeric_limits<uint64_t>::max(), 42);
all::verify_integer_times_pow10(std::numeric_limits<uint64_t>::max(), -42);
}
}

View File

@ -2,7 +2,7 @@
#include <iostream>
int main() {
void default_overload() {
const uint64_t W = 12345678901234567;
const int Q = 23;
const double result = fast_float::integer_times_pow10(W, Q);
@ -10,3 +10,27 @@ int main() {
std::cout << W << " * 10^" << Q << " = " << result << " ("
<< (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();
}