Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,39 @@ print the number 22250738585072012 three times:
std::cout << "parsed the number "<< i << std::endl;
```

## Behavior of result_out_of_range

When parsing floating-point values, the numbers can sometimes be too small (e.g., `1e-1000`) or
too large (e.g., `1e1000`). In such cases, it is customary to parse small values to zero and large
values to infinity. That is the behaviour followed by the fast_float library.

Specifically, we follow Jonathan Wakely's interpretation of the standard:

> In any case, the resulting value is one of at most two floating-point values closest to the value of the string matching the pattern. On overflow, value is set to plus or minus `std::numeric_limits<T>::max()` of the appropriate type. On underflow, value is set to a value with magnitude no greater than `std::numeric_limits<T>::min()`.

It is also the approach taken by the [Microsoft C++ library](https://github.com/microsoft/STL/blob/62205ab155d093e71dd9588a78f02c5396c3c14b/tests/std/tests/P0067R5_charconv/test.cpp#L943-L946).

Hence, we have the following examples:

```cpp
double result = -1;
std::string str = "3e-1000";
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
// r.ec == std::errc::result_out_of_range
// r.ptr == str.data() + 7
// result == 0
```


```cpp
double result = -1;
std::string str = "3e1000";
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
// r.ec == std::errc::result_out_of_range
// r.ptr == str.data() + 6
// result == std::numeric_limits<double>::infinity()
```

## C++20: compile-time evaluation (constexpr)

In C++20, you may use `fast_float::from_chars` to parse strings
Expand Down
30 changes: 30 additions & 0 deletions tests/example_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,28 @@ consteval double parse(std::string_view input) {
constexpr double constexptest() { return parse("3.1415 input"); }
#endif

bool small() {
double result = -1;
std::string str = "3e-1000";
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
if(r.ec != std::errc::result_out_of_range) { return false; }
if(r.ptr != str.data() + 7) { return false; }
if(result != 0) { return false; }
printf("small values go to zero\n");
return true;
}

bool large() {
double result = -1;
std::string str = "3e1000";
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
if(r.ec != std::errc::result_out_of_range) { return false; }
if(r.ptr != str.data() + 6) { return false; }
if(result != std::numeric_limits<double>::infinity()) { return false; }
printf("large values go to infinity\n");
return true;
}

int main() {
const std::string input = "3.1416 xyz ";
double result;
Expand All @@ -87,6 +109,14 @@ int main() {
return EXIT_FAILURE;
}
std::cout << "parsed the number " << result << std::endl;
if (!small()) {
printf("Bug\n");
return EXIT_FAILURE;
}
if (!large()) {
printf("Bug\n");
return EXIT_FAILURE;
}

if (!many()) {
printf("Bug\n");
Expand Down