mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-06 08:46:49 +08:00
Merge pull request #320 from toughengineer/int_multiplication_by_power_of_10
Implemented multiplication of integer by a power of 10
This commit is contained in:
commit
e20c952456
27
README.md
27
README.md
@ -377,6 +377,33 @@ int main() {
|
||||
}
|
||||
```
|
||||
|
||||
## Multiplication of an integer by a power of 10
|
||||
An integer `W` can be multiplied by a power of ten `10^Q` and
|
||||
converted to `double` with correctly rounded value
|
||||
(in "round to nearest, tie to even" fashion) using
|
||||
`fast_float::integer_times_pow10()`, e.g.:
|
||||
```C++
|
||||
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 << W << " * 10^" << Q << " = " << result << " ("
|
||||
<< (result == 12345678901234567e23 ? "==" : "!=") << "expected)\n";
|
||||
```
|
||||
outputs
|
||||
```
|
||||
12345678901234567 * 10^23 = 1.2345678901234567e+39 (==expected)
|
||||
```
|
||||
`fast_float::integer_times_pow10()` gives the same result as
|
||||
using `fast_float::from_chars()` when parsing the string `"WeQ"`
|
||||
(in this example `"12345678901234567e23"`),
|
||||
except `fast_float::integer_times_pow10()` does not report out-of-range errors, and
|
||||
underflows to zero or overflows to infinity when the resulting value is
|
||||
out of range.
|
||||
|
||||
Overloads of `fast_float::integer_times_pow10()` are provided for
|
||||
signed and unsigned integer types: `int64_t`, `uint64_t`, etc.
|
||||
|
||||
|
||||
## Users and Related Work
|
||||
|
||||
|
||||
@ -45,6 +45,26 @@ FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_advanced(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept;
|
||||
|
||||
/**
|
||||
* This function multiplies an integer number by a power of 10 and returns
|
||||
* the result as a double precision floating-point value that is correctly
|
||||
* rounded. The resulting floating-point value is the closest floating-point
|
||||
* value, using the "round to nearest, tie to even" convention for values that
|
||||
* would otherwise fall right in-between two values. That is, we provide exact
|
||||
* conversion according to the IEEE standard.
|
||||
*
|
||||
* On overflow infinity is returned, on underflow 0 is returned.
|
||||
*
|
||||
* The implementation does not throw and does not allocate memory (e.g., with
|
||||
* `new` or `malloc`).
|
||||
*/
|
||||
FASTFLOAT_CONSTEXPR20 inline double
|
||||
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept;
|
||||
FASTFLOAT_CONSTEXPR20 inline
|
||||
typename std::enable_if<is_supported_float_type<double>::value,
|
||||
double>::type
|
||||
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept;
|
||||
|
||||
/**
|
||||
* from_chars for integer types.
|
||||
*/
|
||||
|
||||
@ -188,32 +188,17 @@ from_chars(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC>(fmt));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function overload takes parsed_number_string_t structure that is created
|
||||
* and populated either by from_chars_advanced function taking chars range and
|
||||
* parsing options or other parsing custom function implemented by user.
|
||||
*/
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
|
||||
|
||||
static_assert(is_supported_float_type<T>::value,
|
||||
"only some floating-point types are supported");
|
||||
static_assert(is_supported_char_type<UC>::value,
|
||||
"only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
from_chars_result_t<UC> answer;
|
||||
|
||||
answer.ec = std::errc(); // be optimistic
|
||||
answer.ptr = pns.lastmatch;
|
||||
template <typename T>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
|
||||
clinger_fast_path_impl(uint64_t mantissa, int64_t exponent, bool is_negative,
|
||||
T &value) noexcept {
|
||||
// The implementation of the Clinger's fast path is convoluted because
|
||||
// we want round-to-nearest in all cases, irrespective of the rounding mode
|
||||
// selected on the thread.
|
||||
// We proceed optimistically, assuming that detail::rounds_to_nearest()
|
||||
// returns true.
|
||||
if (binary_format<T>::min_exponent_fast_path() <= pns.exponent &&
|
||||
pns.exponent <= binary_format<T>::max_exponent_fast_path() &&
|
||||
!pns.too_many_digits) {
|
||||
if (binary_format<T>::min_exponent_fast_path() <= exponent &&
|
||||
exponent <= binary_format<T>::max_exponent_fast_path()) {
|
||||
// Unfortunately, the conventional Clinger's fast path is only possible
|
||||
// when the system rounds to the nearest float.
|
||||
//
|
||||
@ -224,41 +209,64 @@ from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
|
||||
if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
|
||||
// We have that fegetround() == FE_TONEAREST.
|
||||
// Next is Clinger's fast path.
|
||||
if (pns.mantissa <= binary_format<T>::max_mantissa_fast_path()) {
|
||||
value = T(pns.mantissa);
|
||||
if (pns.exponent < 0) {
|
||||
value = value / binary_format<T>::exact_power_of_ten(-pns.exponent);
|
||||
if (mantissa <= binary_format<T>::max_mantissa_fast_path()) {
|
||||
value = T(mantissa);
|
||||
if (exponent < 0) {
|
||||
value = value / binary_format<T>::exact_power_of_ten(-exponent);
|
||||
} else {
|
||||
value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
|
||||
value = value * binary_format<T>::exact_power_of_ten(exponent);
|
||||
}
|
||||
if (pns.negative) {
|
||||
if (is_negative) {
|
||||
value = -value;
|
||||
}
|
||||
return answer;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// We do not have that fegetround() == FE_TONEAREST.
|
||||
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's
|
||||
// proposal
|
||||
if (pns.exponent >= 0 &&
|
||||
pns.mantissa <=
|
||||
binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
|
||||
if (exponent >= 0 &&
|
||||
mantissa <= binary_format<T>::max_mantissa_fast_path(exponent)) {
|
||||
#if defined(__clang__) || defined(FASTFLOAT_32BIT)
|
||||
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
|
||||
if (pns.mantissa == 0) {
|
||||
value = pns.negative ? T(-0.) : T(0.);
|
||||
return answer;
|
||||
if (mantissa == 0) {
|
||||
value = is_negative ? T(-0.) : T(0.);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
value = T(pns.mantissa) *
|
||||
binary_format<T>::exact_power_of_ten(pns.exponent);
|
||||
if (pns.negative) {
|
||||
value = T(mantissa) * binary_format<T>::exact_power_of_ten(exponent);
|
||||
if (is_negative) {
|
||||
value = -value;
|
||||
}
|
||||
return answer;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function overload takes parsed_number_string_t structure that is created
|
||||
* and populated either by from_chars_advanced function taking chars range and
|
||||
* parsing options or other parsing custom function implemented by user.
|
||||
*/
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
|
||||
static_assert(is_supported_float_type<T>::value,
|
||||
"only some floating-point types are supported");
|
||||
static_assert(is_supported_char_type<UC>::value,
|
||||
"only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
from_chars_result_t<UC> answer;
|
||||
|
||||
answer.ec = std::errc(); // be optimistic
|
||||
answer.ptr = pns.lastmatch;
|
||||
|
||||
if (!pns.too_many_digits &&
|
||||
clinger_fast_path_impl(pns.mantissa, pns.exponent, pns.negative, value))
|
||||
return answer;
|
||||
|
||||
adjusted_mantissa am =
|
||||
compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
|
||||
if (pns.too_many_digits && am.power2 >= 0) {
|
||||
@ -336,6 +344,49 @@ from_chars(UC const *first, UC const *last, T &value, int base) noexcept {
|
||||
return from_chars_advanced(first, last, value, options);
|
||||
}
|
||||
|
||||
FASTFLOAT_CONSTEXPR20 inline double
|
||||
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept {
|
||||
double value;
|
||||
if (clinger_fast_path_impl(mantissa, decimal_exponent, false, value))
|
||||
return value;
|
||||
|
||||
adjusted_mantissa am =
|
||||
compute_float<binary_format<double>>(decimal_exponent, mantissa);
|
||||
to_float(false, am, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
FASTFLOAT_CONSTEXPR20 inline double
|
||||
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept {
|
||||
const bool is_negative = mantissa < 0;
|
||||
const uint64_t m = static_cast<uint64_t>(is_negative ? -mantissa : mantissa);
|
||||
|
||||
double value;
|
||||
if (clinger_fast_path_impl(m, decimal_exponent, is_negative, value))
|
||||
return value;
|
||||
|
||||
adjusted_mantissa am =
|
||||
compute_float<binary_format<double>>(decimal_exponent, m);
|
||||
to_float(is_negative, am, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// the following overloads are here to avoid surprising ambiguity for int,
|
||||
// unsigned, etc.
|
||||
template <typename Int>
|
||||
FASTFLOAT_CONSTEXPR20 inline 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<
|
||||
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);
|
||||
}
|
||||
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_int_advanced(UC const *first, UC const *last, T &value,
|
||||
|
||||
@ -61,6 +61,7 @@ fast_float_add_cpp_test(wide_char_test)
|
||||
fast_float_add_cpp_test(supported_chars_test)
|
||||
fast_float_add_cpp_test(example_test)
|
||||
fast_float_add_cpp_test(example_comma_test)
|
||||
fast_float_add_cpp_test(example_integer_times_pow10)
|
||||
fast_float_add_cpp_test(basictest)
|
||||
option(FASTFLOAT_CONSTEXPR_TESTS "Require constexpr tests (build will fail if the compiler won't support it)" OFF)
|
||||
if (FASTFLOAT_CONSTEXPR_TESTS)
|
||||
|
||||
@ -1134,6 +1134,14 @@ TEST_CASE("double.inf") {
|
||||
std::errc::result_out_of_range);
|
||||
verify("1.9e308", std::numeric_limits<double>::infinity(),
|
||||
std::errc::result_out_of_range);
|
||||
|
||||
// DBL_MAX + 0.00000000000000001e308
|
||||
verify("1.79769313486231581e308", std::numeric_limits<double>::infinity(),
|
||||
std::errc::result_out_of_range);
|
||||
|
||||
// DBL_MAX + 0.0000000000000001e308
|
||||
verify("1.7976931348623159e308", std::numeric_limits<double>::infinity(),
|
||||
std::errc::result_out_of_range);
|
||||
}
|
||||
|
||||
TEST_CASE("double.general") {
|
||||
@ -1143,6 +1151,13 @@ TEST_CASE("double.general") {
|
||||
verify("-22250738585072012e-324",
|
||||
-0x1p-1022); /* limit between normal and subnormal*/
|
||||
verify("-1e-999", -0.0, std::errc::result_out_of_range);
|
||||
|
||||
// DBL_TRUE_MIN / 2
|
||||
verify("2.4703282292062327e-324", 0.0, std::errc::result_out_of_range);
|
||||
|
||||
// DBL_TRUE_MIN / 2 + 0.0000000000000001e-324
|
||||
verify("2.4703282292062328e-324", 0x0.0000000000001p-1022);
|
||||
|
||||
verify("-2.2222222222223e-322", -0x1.68p-1069);
|
||||
verify("9007199254740993.0", 0x1p+53);
|
||||
verify("860228122.6654514319E+90", 0x1.92bb20990715fp+328);
|
||||
@ -2070,3 +2085,155 @@ TEST_CASE("bfloat16.general") {
|
||||
// 0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875bf16);
|
||||
}
|
||||
#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);
|
||||
|
||||
INFO("m * 10^e=" << mantissa << " * 10^" << decimal_exponent
|
||||
<< "\n"
|
||||
" expected="
|
||||
<< fHexAndDec(expected) << "\n"
|
||||
<< " ..actual=" << fHexAndDec(actual) << "\n"
|
||||
<< " expected mantissa="
|
||||
<< iHexAndDec(get_mantissa(expected)) << "\n"
|
||||
<< " ..actual mantissa=" << iHexAndDec(get_mantissa(actual))
|
||||
<< "\n");
|
||||
CHECK_EQ(actual, expected);
|
||||
}
|
||||
|
||||
template <typename Int>
|
||||
void verify_integer_multiplication_by_power_of_10(Int mantissa,
|
||||
int decimal_exponent) {
|
||||
std::string constructed_string =
|
||||
std::to_string(mantissa) + "e" + std::to_string(decimal_exponent);
|
||||
double 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);
|
||||
}
|
||||
|
||||
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,
|
||||
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>(
|
||||
3141592653589793238, -18, 3.141592653589793238);
|
||||
|
||||
for (int mode : {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, FE_TONEAREST}) {
|
||||
fesetround(mode);
|
||||
INFO("fesetround(): " << std::string{round_name(mode)});
|
||||
|
||||
struct Guard {
|
||||
~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);
|
||||
|
||||
verify_integer_multiplication_by_power_of_10(
|
||||
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());
|
||||
|
||||
// DBL_TRUE_MIN / 2 underflows to 0
|
||||
verify_integer_multiplication_by_power_of_10(49406564584124654 / 2, -340,
|
||||
0.);
|
||||
|
||||
// DBL_TRUE_MIN / 2 + 0.0000000000000001e-324 rounds to DBL_TRUE_MIN
|
||||
verify_integer_multiplication_by_power_of_10(
|
||||
49406564584124654 / 2 + 1, -340,
|
||||
std::numeric_limits<double>::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());
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
12
tests/example_integer_times_pow10.cpp
Normal file
12
tests/example_integer_times_pow10.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
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 << W << " * 10^" << Q << " = " << result << " ("
|
||||
<< (result == 12345678901234567e23 ? "==" : "!=") << "expected)\n";
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user