fast_float icon indicating copy to clipboard operation
fast_float copied to clipboard

behavior in case of overflow/underflow differs from std::from_chars specification?

Open pppalka opened this issue 3 years ago • 2 comments

When the parsed value is outside the representable range, such as on input "1e-10000" and "1e+10000", it seems fast_float::from_chars sets the 'value' output parameter to 0 and infinity respectively and returns std::errc{}.

But the specification for std::from_chars (http://eel.is/c++draft/charconv.from.chars#1) says:

If the parsed value is not in the range representable by the type of value, value is unmodified and the member ec of the return value is equal to errc​::​result_­out_­of_­range.

It this deviation from the C++ standard intended?

When integrating fast_float into libstdc++, we adjusted this behavior with the following patch: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=40b0d4472a2591cf27f3a81aa3fba57dc4532648

pppalka avatar Jan 17 '22 20:01 pppalka

The from_chars supports various number types, including integer types. For integer types, there is a finite range. My view is that the range of values from binary64 and binary32 numbers is from -infinity to infinity. So all real numbers are in range. Not all numbers can be represented exactly, but that is nothing to do with the range become the convertion from text to binary is lossy: we always seek to assign the best match.

I covered my stance with respect to this issue in the following PR: https://github.com/fastfloat/fast_float/issues/113 Given a decimal representation, you always seek the best match. My view is that 1e99999 is indeed representable with a binary64 number: it is infinity. I am not exactly sure on what account you would consider that 1e-10000 is not in range. What range is that?

lemire avatar Jan 17 '22 20:01 lemire

I think an LWG issue is warranted, since we have two reasonable but conflicting interpretations of the standard.

jwakely avatar Jan 17 '22 21:01 jwakely

Given a decimal representation, you always seek the best match. My view is that 1e99999 is indeed representable with a binary64 number: it is infinity.

Agreed.

However, this assumes that the user only cares about the best representation of the input in a double (like the JavaScript or Python examples in the link)

A more interesting value is 1e40. It does not fit in a binary32, but does in a binary64. A user may wish to use 32-bit code if the values fit and 64-bit code otherwise. A parser that returns infinity on overflow makes such approaches much more difficult to write. The opposite is easier. Same argument for 64-bit overflow as some platforms offer 80-bit floats and of course variable-precision libraries exist.

I'd also argue that a C++ library should match the behavior of the C++ standard library, not Python, JavaScript, or Swift. AFAIK all floating-point parsers in the C and C++ standard libraries have a way to distinguish overflow.

Heck, you can easily do both. The error code is separate from the return value, so just return infinity (or -infinity, or whatever) but still set result.ec = errc​::​result_­out_­of_­range. Users that care can distinguish overflow, users that don't can just treat errc​::​result_­out_­of_­range as success.

alugowski avatar Mar 06 '23 22:03 alugowski

@alugowski That's reasonable. Pull request invited.

I don't consider the current behaviour incorrect but if someone wants to contribute the code for the functionality that @alugowski described, then we will merge it.

lemire avatar Mar 07 '23 03:03 lemire

@alugowski That's reasonable. Pull request invited.

I don't consider the current behaviour incorrect but if someone wants to contribute the code for the functionality that @alugowski described, then we will merge it.

PR submitted with the behavior as I described above: https://github.com/fastfloat/fast_float/pull/189

The main difference from @pppalka 's patch is that the check is one line lower to still return the best match value.

alugowski avatar Mar 29 '23 05:03 alugowski

I think an LWG issue is warranted, since we have two reasonable but conflicting interpretations of the standard.

Actually I think I'll add a comment to https://cplusplus.github.io/LWG/issue3081

jwakely avatar Mar 29 '23 10:03 jwakely

I will close this issue given that I just merged https://github.com/fastfloat/fast_float/pull/189

lemire avatar Mar 30 '23 22:03 lemire