Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
pppalka opened this issue Jan 17, 2022 · 7 comments

Comments

@pppalka
Copy link

pppalka commented Jan 17, 2022

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

@lemire
Copy link
Member

lemire commented Jan 17, 2022

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:
#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?

@jwakely
Copy link
Contributor

jwakely commented Jan 17, 2022

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

@lemire lemire changed the title behavior in case of overflow/underflow differs from std::from_chars specification behavior in case of overflow/underflow differs from std::from_chars specification? Jan 17, 2022
@alugowski
Copy link
Contributor

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.

@lemire
Copy link
Member

lemire commented Mar 7, 2023

@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.

@alugowski
Copy link
Contributor

@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: #189

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

@jwakely
Copy link
Contributor

jwakely commented Mar 29, 2023

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

@lemire
Copy link
Member

lemire commented Mar 30, 2023

I will close this issue given that I just merged #189

@lemire lemire closed this as completed Mar 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants