diff --git a/README.md b/README.md index 70fa721..17ddc85 100644 --- a/README.md +++ b/README.md @@ -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()` specialization: +```C++ +const uint64_t W = 12345678; +const int Q = 23; +const float result = fast_float::integer_times_pow10(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 diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index cc3e0dd..a0d5882 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -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 fastfloat_really_inline FASTFLOAT_CONSTEXPR14 am_pow_t -scientific_exponent(parsed_number_string_t 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(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(bigmant, num); // can't underflow, since digits is at most max_digits. am_pow_t const exponent = diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index 08a1a44..a18266f 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -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 +FASTFLOAT_CONSTEXPR20 + typename std::enable_if::value, T>::type + integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept; +template +FASTFLOAT_CONSTEXPR20 + typename std::enable_if::value, T>::type + integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept; + /** * from_chars for integer types. */ diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 72e36ef..66a96d9 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -1238,6 +1238,9 @@ static_assert(std::is_same, uint64_t>::value, static_assert( std::numeric_limits::is_iec559, "std::float64_t must fulfill the requirements of IEC 559 (IEEE 754)"); + +template <> +struct binary_format : public binary_format {}; #endif // __STDCPP_FLOAT64_T__ #ifdef __STDCPP_FLOAT32_T__ @@ -1246,6 +1249,9 @@ static_assert(std::is_same, uint32_t>::value, static_assert( std::numeric_limits::is_iec559, "std::float32_t must fulfill the requirements of IEC 559 (IEEE 754)"); + +template <> +struct binary_format : public binary_format {}; #endif // __STDCPP_FLOAT32_T__ #ifdef __STDCPP_FLOAT16_T__ diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index f7096a6..814f7ec 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -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 +FASTFLOAT_CONSTEXPR20 + typename std::enable_if::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 +FASTFLOAT_CONSTEXPR20 + typename std::enable_if::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(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(mantissa, decimal_exponent); +} + +FASTFLOAT_CONSTEXPR20 inline double +integer_times_pow10(int64_t mantissa, int const decimal_exponent) noexcept { + return integer_times_pow10(mantissa, decimal_exponent); +} + // the following overloads are here to avoid surprising ambiguity for int, // unsigned, etc. +template +FASTFLOAT_CONSTEXPR20 + typename std::enable_if::value && + std::is_integral::value && + !std::is_signed::value, + T>::type + integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { + return integer_times_pow10(static_cast(mantissa), + decimal_exponent); +} + +template +FASTFLOAT_CONSTEXPR20 + typename std::enable_if::value && + std::is_integral::value && + std::is_signed::value, + T>::type + integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { + return integer_times_pow10(static_cast(mantissa), + decimal_exponent); +} + template -FASTFLOAT_CONSTEXPR20 inline typename std::enable_if< +FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && !std::is_signed::value, double>::type integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } template -FASTFLOAT_CONSTEXPR20 inline typename std::enable_if< +FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && std::is_signed::value, double>::type integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); diff --git a/tests/basictest.cpp b/tests/basictest.cpp index dc11752..1a5537b 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -1142,6 +1142,15 @@ TEST_CASE("double.inf") { // DBL_MAX + 0.0000000000000001e308 verify("1.7976931348623159e308", std::numeric_limits::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::infinity(), + std::errc::result_out_of_range); } TEST_CASE("double.general") { @@ -1333,6 +1342,15 @@ TEST_CASE("double.general") { std::numeric_limits::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::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::infinity(), std::errc::result_out_of_range); + // FLT_MAX + 0.00000007e38 + verify("3.40282357e38", std::numeric_limits::infinity(), + std::errc::result_out_of_range); + // FLT_MAX + 0.0000001e38 + verify("3.4028236e38", std::numeric_limits::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::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::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 -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 +void verify_integer_times_pow10_result(Int mantissa, int decimal_exponent, + T actual, U expected) { + static_assert(std::is_same::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 -void verify_integer_multiplication_by_power_of_10(Int mantissa, - int decimal_exponent) { +template +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 +void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent, + double expected) { + static_assert(std::is_integral::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 +void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent) { + static_assert(std::is_integral::value); + + const auto expected_result = + calculate_integer_times_pow10_expected_result(mantissa, + decimal_exponent); + + verify_integer_times_pow10_dflt(mantissa, decimal_exponent, expected_result); +} + +template +void verify_integer_times_pow10(Int mantissa, int decimal_exponent, + T expected) { + static_assert(std::is_floating_point::value); + static_assert(std::is_integral::value); + + // explicit specialization + const auto actual = + fast_float::integer_times_pow10(mantissa, decimal_exponent); + + verify_integer_times_pow10_result(mantissa, decimal_exponent, actual, + expected); +} + +template +void verify_integer_times_pow10(Int mantissa, int decimal_exponent) { + static_assert(std::is_floating_point::value); + static_assert(std::is_integral::value); + + const auto expected_result = calculate_integer_times_pow10_expected_result( + mantissa, decimal_exponent); + + verify_integer_times_pow10(mantissa, decimal_exponent, expected_result); +} + +namespace all_supported_types { +template +void verify_integer_times_pow10(Int mantissa, int decimal_exponent) { + static_assert(std::is_integral::value); + + // verify the "default" overload + verify_integer_times_pow10_dflt(mantissa, decimal_exponent); + + // verify explicit specializations + ::verify_integer_times_pow10(mantissa, decimal_exponent); + ::verify_integer_times_pow10(mantissa, decimal_exponent); +#if defined(__STDCPP_FLOAT64_T__) + ::verify_integer_times_pow10(mantissa, decimal_exponent); +#endif +#if defined(__STDCPP_FLOAT32_T__) + ::verify_integer_times_pow10(mantissa, decimal_exponent); +#endif +#if defined(__STDCPP_FLOAT16_T__) + ::verify_integer_times_pow10(mantissa, decimal_exponent); +#endif +#if defined(__STDCPP_BFLOAT16_T__) + ::verify_integer_times_pow10(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(31, -1, 3.1); - verify_integer_multiplication_by_power_of_10(-31, -1, -3.1); - verify_integer_multiplication_by_power_of_10(31, -1, 3.1); - verify_integer_multiplication_by_power_of_10(31415, -4, 3.1415); - verify_integer_multiplication_by_power_of_10(-31415, -4, -3.1415); - verify_integer_multiplication_by_power_of_10(31415, -4, 3.1415); - verify_integer_multiplication_by_power_of_10(314159265, -8, - 3.14159265); - verify_integer_multiplication_by_power_of_10(-314159265, -8, - -3.14159265); - verify_integer_multiplication_by_power_of_10(3141592653, -9, - 3.141592653); - verify_integer_multiplication_by_power_of_10( - 3141592653589793238, -18, 3.141592653589793238); - verify_integer_multiplication_by_power_of_10( - -3141592653589793238, -18, -3.141592653589793238); - verify_integer_multiplication_by_power_of_10( - 3141592653589793238, -18, 3.141592653589793238); - verify_integer_multiplication_by_power_of_10( - -3141592653589793238, -18, -3.141592653589793238); - verify_integer_multiplication_by_power_of_10( + /* explicitly verifying API with different types of integers */ + // double (the "default" overload) + verify_integer_times_pow10_dflt(31, -1, 3.1); + verify_integer_times_pow10_dflt(-31, -1, -3.1); + verify_integer_times_pow10_dflt(31, -1, 3.1); + verify_integer_times_pow10_dflt(31415, -4, 3.1415); + verify_integer_times_pow10_dflt(-31415, -4, -3.1415); + verify_integer_times_pow10_dflt(31415, -4, 3.1415); + verify_integer_times_pow10_dflt(314159265, -8, 3.14159265); + verify_integer_times_pow10_dflt(-314159265, -8, -3.14159265); + verify_integer_times_pow10_dflt(3141592653, -9, 3.141592653); + verify_integer_times_pow10_dflt(314159265, -8, 3.14159265); + verify_integer_times_pow10_dflt(-314159265, -8, -3.14159265); + verify_integer_times_pow10_dflt(3141592653, -9, 3.141592653); + verify_integer_times_pow10_dflt(3141592653589793238, -18, + 3.141592653589793238); + verify_integer_times_pow10_dflt(-3141592653589793238, -18, + -3.141592653589793238); + verify_integer_times_pow10_dflt(3141592653589793238, -18, + 3.141592653589793238); + verify_integer_times_pow10_dflt(3141592653589793238, -18, + 3.141592653589793238); + verify_integer_times_pow10_dflt(-3141592653589793238, -18, + -3.141592653589793238); + verify_integer_times_pow10_dflt(3141592653589793238, -18, + 3.141592653589793238); + // double (explicit specialization) + verify_integer_times_pow10(31, -1, 3.1); + verify_integer_times_pow10(-31, -1, -3.1); + verify_integer_times_pow10(31, -1, 3.1); + verify_integer_times_pow10(31415, -4, 3.1415); + verify_integer_times_pow10(-31415, -4, -3.1415); + verify_integer_times_pow10(31415, -4, 3.1415); + verify_integer_times_pow10(314159265, -8, 3.14159265); + verify_integer_times_pow10(-314159265, -8, -3.14159265); + verify_integer_times_pow10(3141592653, -9, 3.141592653); + verify_integer_times_pow10(314159265, -8, 3.14159265); + verify_integer_times_pow10(-314159265, -8, -3.14159265); + verify_integer_times_pow10(3141592653, -9, + 3.141592653); + verify_integer_times_pow10(3141592653589793238, -18, + 3.141592653589793238); + verify_integer_times_pow10(-3141592653589793238, -18, + -3.141592653589793238); + verify_integer_times_pow10(3141592653589793238, -18, + 3.141592653589793238); + verify_integer_times_pow10(3141592653589793238, -18, + 3.141592653589793238); + verify_integer_times_pow10(-3141592653589793238, -18, + -3.141592653589793238); + verify_integer_times_pow10( 3141592653589793238, -18, 3.141592653589793238); + // float (explicit specialization) + verify_integer_times_pow10(31, -1, 3.1f); + verify_integer_times_pow10(-31, -1, -3.1f); + verify_integer_times_pow10(31, -1, 3.1f); + verify_integer_times_pow10(31415, -4, 3.1415f); + verify_integer_times_pow10(-31415, -4, -3.1415f); + verify_integer_times_pow10(31415, -4, 3.1415f); + verify_integer_times_pow10(314159265, -8, 3.14159265f); + verify_integer_times_pow10(-314159265, -8, -3.14159265f); + verify_integer_times_pow10(3141592653, -9, 3.14159265f); + verify_integer_times_pow10(314159265, -8, 3.14159265f); + verify_integer_times_pow10(-314159265, -8, -3.14159265f); + verify_integer_times_pow10(3141592653, -9, 3.14159265f); + verify_integer_times_pow10(3141592653589793238, -18, + 3.141592653589793238f); + verify_integer_times_pow10(-3141592653589793238, -18, + -3.141592653589793238f); + verify_integer_times_pow10(3141592653589793238, -18, + 3.141592653589793238f); + verify_integer_times_pow10(3141592653589793238, -18, + 3.141592653589793238f); + verify_integer_times_pow10(-3141592653589793238, -18, + -3.141592653589793238f); + verify_integer_times_pow10( + 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::denorm_min()); + verify_integer_times_pow10( 49406564584124654, -340, std::numeric_limits::denorm_min()); - verify_integer_multiplication_by_power_of_10( - 22250738585072014, -324, std::numeric_limits::min()); - verify_integer_multiplication_by_power_of_10( - 17976931348623158, 292, std::numeric_limits::max()); + verify_integer_times_pow10(14012984, -52, + std::numeric_limits::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::min()); + verify_integer_times_pow10(22250738585072014, -324, + std::numeric_limits::min()); + verify_integer_times_pow10(11754944, -45, + std::numeric_limits::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::max()); + verify_integer_times_pow10(17976931348623158, 292, + std::numeric_limits::max()); + verify_integer_times_pow10(34028235, 31, + std::numeric_limits::max()); + + /* underflow */ + // (DBL_TRUE_MIN / 2) underflows to 0 + verify_integer_times_pow10_dflt(49406564584124654 / 2, -340, 0.); + verify_integer_times_pow10(49406564584124654 / 2, -340, 0.); + // (FLT_TRUE_MIN / 2) underflows to 0 + verify_integer_times_pow10(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::denorm_min()); + verify_integer_times_pow10( 49406564584124654 / 2 + 1, -340, std::numeric_limits::denorm_min()); + // (FLT_TRUE_MIN / 2 + 0.0000001e-45) rounds to FLT_TRUE_MIN + verify_integer_times_pow10(14012984 / 2 + 1, -52, + std::numeric_limits::denorm_min()); - // DBL_MAX + 0.0000000000000001e308 overflows to infinity - verify_integer_multiplication_by_power_of_10( - 17976931348623158 + 1, 292, std::numeric_limits::infinity()); - // DBL_MAX + 0.00000000000000001e308 overflows to infinity - verify_integer_multiplication_by_power_of_10( - 179769313486231580 + 1, 291, std::numeric_limits::infinity()); + /* overflow */ + // (DBL_MAX + 0.0000000000000001e308) overflows to infinity + verify_integer_times_pow10_dflt(17976931348623158 + 1, 292, + std::numeric_limits::infinity()); + verify_integer_times_pow10(17976931348623158 + 1, 292, + std::numeric_limits::infinity()); + // (DBL_MAX + 0.00000000000000001e308) overflows to infinity + verify_integer_times_pow10_dflt(179769313486231580 + 1, 291, + std::numeric_limits::infinity()); + verify_integer_times_pow10(179769313486231580 + 1, 291, + std::numeric_limits::infinity()); + // (FLT_MAX + 0.0000001e38) overflows to infinity + verify_integer_times_pow10(34028235 + 1, 31, + std::numeric_limits::infinity()); + // (FLT_MAX + 0.00000007e38) overflows to infinity + verify_integer_times_pow10(340282350 + 7, 30, + std::numeric_limits::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::max(), 42); - verify_integer_multiplication_by_power_of_10( - std::numeric_limits::max(), -42); - verify_integer_multiplication_by_power_of_10( - std::numeric_limits::max(), 42); - verify_integer_multiplication_by_power_of_10( - std::numeric_limits::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::max(), 42); + all::verify_integer_times_pow10(std::numeric_limits::max(), -42); + all::verify_integer_times_pow10(std::numeric_limits::max(), 42); + all::verify_integer_times_pow10(std::numeric_limits::max(), -42); } } \ No newline at end of file diff --git a/tests/example_integer_times_pow10.cpp b/tests/example_integer_times_pow10.cpp index 3e86826..0205c27 100644 --- a/tests/example_integer_times_pow10.cpp +++ b/tests/example_integer_times_pow10.cpp @@ -2,7 +2,7 @@ #include -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(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(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(); +}