diff --git a/tests/basictest.cpp b/tests/basictest.cpp index dc11752..15ab344 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -1507,9 +1507,20 @@ 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); } 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 @@ -2086,12 +2097,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 +2115,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 +2291,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