mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-07 01:06:48 +08:00
Merge remote-tracking branch 'upstream/main'
- Fix conflicts
This commit is contained in:
commit
65bd922e38
26
.github/workflows/ubuntu18.yml
vendored
26
.github/workflows/ubuntu18.yml
vendored
@ -1,26 +0,0 @@
|
|||||||
name: Ubuntu 18.04 CI (GCC 7)
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ubuntu-build:
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Setup cmake
|
|
||||||
uses: jwlawson/actions-setup-cmake@v1.4
|
|
||||||
with:
|
|
||||||
cmake-version: '3.11.x'
|
|
||||||
#- name: Install older compilers
|
|
||||||
# run: |
|
|
||||||
# sudo -E dpkg --add-architecture i386
|
|
||||||
# sudo -E apt-get update
|
|
||||||
# sudo -E apt-get install -y --force-yes g++-5 g++-6 g++-5-multilib g++-6-multilib g++-multilib linux-libc-dev:i386 libc6:i386 libc6-dev:i386 libc6-dbg:i386
|
|
||||||
- name: Prepare build dir
|
|
||||||
run: mkdir build
|
|
||||||
- name: Configure
|
|
||||||
run: cd build && cmake ${{matrix.cxx}} ${{matrix.arch}} -DFASTFLOAT_TEST=ON ..
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build
|
|
||||||
- name: Run basic tests
|
|
||||||
run: cd build && ctest --output-on-failure -R basictest
|
|
||||||
2
.github/workflows/ubuntu22-clang.yml
vendored
2
.github/workflows/ubuntu22-clang.yml
vendored
@ -22,4 +22,4 @@ jobs:
|
|||||||
cd build20 &&
|
cd build20 &&
|
||||||
CXX=clang++-14 cmake -DFASTFLOAT_CONSTEXPR_TESTS=ON -DCMAKE_CXX_STANDARD=20 -DFASTFLOAT_TEST=ON .. &&
|
CXX=clang++-14 cmake -DFASTFLOAT_CONSTEXPR_TESTS=ON -DCMAKE_CXX_STANDARD=20 -DFASTFLOAT_TEST=ON .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest --output-on-failure
|
ctest --output-on-failure
|
||||||
2
.github/workflows/ubuntu22-gcc12.yml
vendored
2
.github/workflows/ubuntu22-gcc12.yml
vendored
@ -20,4 +20,4 @@ jobs:
|
|||||||
cd build20 &&
|
cd build20 &&
|
||||||
CXX=g++-12 CXXFLAGS=-Werror cmake -DFASTFLOAT_CONSTEXPR_TESTS=ON -DCMAKE_CXX_STANDARD=20 -DFASTFLOAT_TEST=ON .. &&
|
CXX=g++-12 CXXFLAGS=-Werror cmake -DFASTFLOAT_CONSTEXPR_TESTS=ON -DCMAKE_CXX_STANDARD=20 -DFASTFLOAT_TEST=ON .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest --output-on-failure
|
ctest --output-on-failure
|
||||||
2
.github/workflows/ubuntu22.yml
vendored
2
.github/workflows/ubuntu22.yml
vendored
@ -13,4 +13,4 @@ jobs:
|
|||||||
cd build &&
|
cd build &&
|
||||||
cmake -DFASTFLOAT_TEST=ON .. &&
|
cmake -DFASTFLOAT_TEST=ON .. &&
|
||||||
cmake --build . &&
|
cmake --build . &&
|
||||||
ctest --output-on-failure
|
ctest --output-on-failure
|
||||||
@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.9)
|
cmake_minimum_required(VERSION 3.9)
|
||||||
|
|
||||||
project(fast_float VERSION 3.10.0 LANGUAGES CXX)
|
project(fast_float VERSION 4.0.0 LANGUAGES CXX)
|
||||||
option(FASTFLOAT_TEST "Enable tests" OFF)
|
option(FASTFLOAT_TEST "Enable tests" OFF)
|
||||||
if(FASTFLOAT_TEST)
|
if(FASTFLOAT_TEST)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|||||||
16
README.md
16
README.md
@ -1,4 +1,8 @@
|
|||||||
|
|
||||||
## fast_float number parsing library: 4x faster than strtod
|
## fast_float number parsing library: 4x faster than strtod
|
||||||
|
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:fast_float)
|
||||||
|
[](https://github.com/fastfloat/fast_float/actions/workflows/vs17-ci.yml)
|
||||||
|
[](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml)
|
||||||
|
|
||||||
The fast_float library provides fast header-only implementations for the C++ from_chars
|
The fast_float library provides fast header-only implementations for the C++ from_chars
|
||||||
functions for `float` and `double` types. These functions convert ASCII strings representing
|
functions for `float` and `double` types. These functions convert ASCII strings representing
|
||||||
@ -66,7 +70,7 @@ The library seeks to follow the C++17 (see [20.19.3](http://eel.is/c++draft/char
|
|||||||
Furthermore, we have the following restrictions:
|
Furthermore, we have the following restrictions:
|
||||||
* We only support `float` and `double` types at this time.
|
* We only support `float` and `double` types at this time.
|
||||||
* We only support the decimal format: we do not support hexadecimal strings.
|
* We only support the decimal format: we do not support hexadecimal strings.
|
||||||
* For values that are either very large or very small (e.g., `1e9999`), we represent it using the infinity or negative infinity value.
|
* For values that are either very large or very small (e.g., `1e9999`), we represent it using the infinity or negative infinity value and the returned `ec` is set to `std::errc::result_out_of_range`.
|
||||||
|
|
||||||
We support Visual Studio, macOS, Linux, freeBSD. We support big and little endian. We support 32-bit and 64-bit systems.
|
We support Visual Studio, macOS, Linux, freeBSD. We support big and little endian. We support 32-bit and 64-bit systems.
|
||||||
|
|
||||||
@ -189,11 +193,11 @@ It can parse random floating-point numbers at a speed of 1 GB/s on some systems.
|
|||||||
$ ./build/benchmarks/benchmark
|
$ ./build/benchmarks/benchmark
|
||||||
# parsing random integers in the range [0,1)
|
# parsing random integers in the range [0,1)
|
||||||
volume = 2.09808 MB
|
volume = 2.09808 MB
|
||||||
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
|
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
|
||||||
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
|
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
|
||||||
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
|
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
|
||||||
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
|
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
|
||||||
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
|
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
|
||||||
```
|
```
|
||||||
|
|
||||||
See https://github.com/lemire/simple_fastfloat_benchmark for our benchmarking code.
|
See https://github.com/lemire/simple_fastfloat_benchmark for our benchmarking code.
|
||||||
|
|||||||
@ -92,7 +92,6 @@ uint64_t read_u64(const CharT *chars) {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
void write_u64(uint8_t *chars, uint64_t val) {
|
void write_u64(uint8_t *chars, uint64_t val) {
|
||||||
if (cpp20_and_in_constexpr()) {
|
if (cpp20_and_in_constexpr()) {
|
||||||
@ -208,7 +207,6 @@ FASTFLOAT_SIMD_RESTORE_WARNINGS
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef span<const char> byte_span;
|
typedef span<const char> byte_span;
|
||||||
|
|
||||||
template <typename CharT>
|
template <typename CharT>
|
||||||
@ -238,7 +236,7 @@ parsed_number_string<CharT> parse_number_string(const CharT *p, const CharT *pen
|
|||||||
answer.valid = false;
|
answer.valid = false;
|
||||||
answer.too_many_digits = false;
|
answer.too_many_digits = false;
|
||||||
answer.negative = (*p == CharT('-'));
|
answer.negative = (*p == CharT('-'));
|
||||||
#if FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
||||||
if ((*p == CharT('-')) || (*p == CharT('+'))) {
|
if ((*p == CharT('-')) || (*p == CharT('+'))) {
|
||||||
#else
|
#else
|
||||||
if (*p == CharT('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
if (*p == CharT('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||||
|
|||||||
@ -14,13 +14,13 @@
|
|||||||
#define FASTFLOAT_CONSTEXPR14
|
#define FASTFLOAT_CONSTEXPR14
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __cpp_lib_bit_cast >= 201806L
|
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||||
#define FASTFLOAT_HAS_BIT_CAST 1
|
#define FASTFLOAT_HAS_BIT_CAST 1
|
||||||
#else
|
#else
|
||||||
#define FASTFLOAT_HAS_BIT_CAST 0
|
#define FASTFLOAT_HAS_BIT_CAST 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __cpp_lib_is_constant_evaluated >= 201811L
|
#if defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L
|
||||||
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1
|
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1
|
||||||
#else
|
#else
|
||||||
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0
|
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0
|
||||||
|
|||||||
@ -48,9 +48,9 @@ namespace detail {
|
|||||||
* where
|
* where
|
||||||
* p = log(5**q)/log(2) = q * log(5)/log(2)
|
* p = log(5**q)/log(2) = q * log(5)/log(2)
|
||||||
*
|
*
|
||||||
* For negative values of q in (-400,0), we have that
|
* For negative values of q in (-400,0), we have that
|
||||||
* f = (((152170 + 65536) * q ) >> 16);
|
* f = (((152170 + 65536) * q ) >> 16);
|
||||||
* is equal to
|
* is equal to
|
||||||
* -ceil(p) + q
|
* -ceil(p) + q
|
||||||
* where
|
* where
|
||||||
* p = log(5**-q)/log(2) = -q * log(5)/log(2)
|
* p = log(5**-q)/log(2) = -q * log(5)/log(2)
|
||||||
|
|||||||
@ -513,7 +513,7 @@ void to_float(bool negative, adjusted_mantissa am, T &value) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
||||||
template <typename = void>
|
template <typename = void>
|
||||||
struct space_lut {
|
struct space_lut {
|
||||||
static constexpr bool value[] = {
|
static constexpr bool value[] = {
|
||||||
|
|||||||
@ -30,7 +30,7 @@ parse_infnan(const CharT *first, const CharT *last, T &value) noexcept {
|
|||||||
minusSign = true;
|
minusSign = true;
|
||||||
++first;
|
++first;
|
||||||
}
|
}
|
||||||
#if FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
||||||
if (*first == CharT('+')) {
|
if (*first == CharT('+')) {
|
||||||
++first;
|
++first;
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
|||||||
//
|
//
|
||||||
// Note: This may fail to be accurate if fast-math has been
|
// Note: This may fail to be accurate if fast-math has been
|
||||||
// enabled, as rounding conventions may not apply.
|
// enabled, as rounding conventions may not apply.
|
||||||
#if FASTFLOAT_VISUAL_STUDIO
|
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
// todo: is there a VS warning?
|
// todo: is there a VS warning?
|
||||||
// see https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013
|
// see https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013
|
||||||
@ -123,7 +123,7 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
|||||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||||
#endif
|
#endif
|
||||||
return (fmini + 1.0f == 1.0f - fmini);
|
return (fmini + 1.0f == 1.0f - fmini);
|
||||||
#if FASTFLOAT_VISUAL_STUDIO
|
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||||
# pragma warning(pop)
|
# pragma warning(pop)
|
||||||
#elif defined(__clang__)
|
#elif defined(__clang__)
|
||||||
# pragma clang diagnostic pop
|
# pragma clang diagnostic pop
|
||||||
@ -213,6 +213,10 @@ from_chars_result<CharT> from_chars_preparsed(parsed_number_string<CharT> pns, c
|
|||||||
// then we need to go the long way around again. This is very uncommon.
|
// then we need to go the long way around again. This is very uncommon.
|
||||||
if(am.power2 < 0) { am = digit_comp<T>(pns, am); }
|
if(am.power2 < 0) { am = digit_comp<T>(pns, am); }
|
||||||
to_float(pns.negative, am, value);
|
to_float(pns.negative, am, value);
|
||||||
|
// Test for over/underflow.
|
||||||
|
if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) || am.power2 == binary_format<T>::infinite_power()) {
|
||||||
|
answer.ec = std::errc::result_out_of_range;
|
||||||
|
}
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +226,7 @@ from_chars_result<CharT> from_chars_advanced(const CharT *first, const CharT *la
|
|||||||
T &value, parse_options options) noexcept {
|
T &value, parse_options options) noexcept {
|
||||||
|
|
||||||
from_chars_result<CharT> answer;
|
from_chars_result<CharT> answer;
|
||||||
#if FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
||||||
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
|
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
|
||||||
first++;
|
first++;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,360 +0,0 @@
|
|||||||
#ifndef FASTFLOAT_GENERIC_DECIMAL_TO_BINARY_H
|
|
||||||
#define FASTFLOAT_GENERIC_DECIMAL_TO_BINARY_H
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This code is meant to handle the case where we have more than 19 digits.
|
|
||||||
*
|
|
||||||
* It is based on work by Nigel Tao (at https://github.com/google/wuffs/)
|
|
||||||
* who credits Ken Thompson for the design (via a reference to the Go source
|
|
||||||
* code).
|
|
||||||
*
|
|
||||||
* Rob Pike suggested that this algorithm be called "Simple Decimal Conversion".
|
|
||||||
*
|
|
||||||
* It is probably not very fast but it is a fallback that should almost never
|
|
||||||
* be used in real life. Though it is not fast, it is "easily" understood and debugged.
|
|
||||||
**/
|
|
||||||
#include "ascii_number.h"
|
|
||||||
#include "decimal_to_binary.h"
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace fast_float {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
// remove all final zeroes
|
|
||||||
inline void trim(decimal &h) {
|
|
||||||
while ((h.num_digits > 0) && (h.digits[h.num_digits - 1] == 0)) {
|
|
||||||
h.num_digits--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline uint32_t number_of_digits_decimal_left_shift(const decimal &h, uint32_t shift) {
|
|
||||||
shift &= 63;
|
|
||||||
constexpr uint16_t number_of_digits_decimal_left_shift_table[65] = {
|
|
||||||
0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817,
|
|
||||||
0x181D, 0x2024, 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067,
|
|
||||||
0x3073, 0x3080, 0x388E, 0x389C, 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF,
|
|
||||||
0x4902, 0x4915, 0x4929, 0x513E, 0x5153, 0x5169, 0x5180, 0x5998, 0x59B0,
|
|
||||||
0x59C9, 0x61E3, 0x61FD, 0x6218, 0x6A34, 0x6A50, 0x6A6D, 0x6A8B, 0x72AA,
|
|
||||||
0x72C9, 0x72E9, 0x7B0A, 0x7B2B, 0x7B4D, 0x8370, 0x8393, 0x83B7, 0x83DC,
|
|
||||||
0x8C02, 0x8C28, 0x8C4F, 0x9477, 0x949F, 0x94C8, 0x9CF2, 0x051C, 0x051C,
|
|
||||||
0x051C, 0x051C,
|
|
||||||
};
|
|
||||||
uint32_t x_a = number_of_digits_decimal_left_shift_table[shift];
|
|
||||||
uint32_t x_b = number_of_digits_decimal_left_shift_table[shift + 1];
|
|
||||||
uint32_t num_new_digits = x_a >> 11;
|
|
||||||
uint32_t pow5_a = 0x7FF & x_a;
|
|
||||||
uint32_t pow5_b = 0x7FF & x_b;
|
|
||||||
constexpr uint8_t
|
|
||||||
number_of_digits_decimal_left_shift_table_powers_of_5[0x051C] = {
|
|
||||||
5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3,
|
|
||||||
9, 0, 6, 2, 5, 1, 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8,
|
|
||||||
1, 2, 5, 2, 4, 4, 1, 4, 0, 6, 2, 5, 1, 2, 2, 0, 7, 0, 3, 1, 2, 5, 6, 1,
|
|
||||||
0, 3, 5, 1, 5, 6, 2, 5, 3, 0, 5, 1, 7, 5, 7, 8, 1, 2, 5, 1, 5, 2, 5, 8,
|
|
||||||
7, 8, 9, 0, 6, 2, 5, 7, 6, 2, 9, 3, 9, 4, 5, 3, 1, 2, 5, 3, 8, 1, 4, 6,
|
|
||||||
9, 7, 2, 6, 5, 6, 2, 5, 1, 9, 0, 7, 3, 4, 8, 6, 3, 2, 8, 1, 2, 5, 9, 5,
|
|
||||||
3, 6, 7, 4, 3, 1, 6, 4, 0, 6, 2, 5, 4, 7, 6, 8, 3, 7, 1, 5, 8, 2, 0, 3,
|
|
||||||
1, 2, 5, 2, 3, 8, 4, 1, 8, 5, 7, 9, 1, 0, 1, 5, 6, 2, 5, 1, 1, 9, 2, 0,
|
|
||||||
9, 2, 8, 9, 5, 5, 0, 7, 8, 1, 2, 5, 5, 9, 6, 0, 4, 6, 4, 4, 7, 7, 5, 3,
|
|
||||||
9, 0, 6, 2, 5, 2, 9, 8, 0, 2, 3, 2, 2, 3, 8, 7, 6, 9, 5, 3, 1, 2, 5, 1,
|
|
||||||
4, 9, 0, 1, 1, 6, 1, 1, 9, 3, 8, 4, 7, 6, 5, 6, 2, 5, 7, 4, 5, 0, 5, 8,
|
|
||||||
0, 5, 9, 6, 9, 2, 3, 8, 2, 8, 1, 2, 5, 3, 7, 2, 5, 2, 9, 0, 2, 9, 8, 4,
|
|
||||||
6, 1, 9, 1, 4, 0, 6, 2, 5, 1, 8, 6, 2, 6, 4, 5, 1, 4, 9, 2, 3, 0, 9, 5,
|
|
||||||
7, 0, 3, 1, 2, 5, 9, 3, 1, 3, 2, 2, 5, 7, 4, 6, 1, 5, 4, 7, 8, 5, 1, 5,
|
|
||||||
6, 2, 5, 4, 6, 5, 6, 6, 1, 2, 8, 7, 3, 0, 7, 7, 3, 9, 2, 5, 7, 8, 1, 2,
|
|
||||||
5, 2, 3, 2, 8, 3, 0, 6, 4, 3, 6, 5, 3, 8, 6, 9, 6, 2, 8, 9, 0, 6, 2, 5,
|
|
||||||
1, 1, 6, 4, 1, 5, 3, 2, 1, 8, 2, 6, 9, 3, 4, 8, 1, 4, 4, 5, 3, 1, 2, 5,
|
|
||||||
5, 8, 2, 0, 7, 6, 6, 0, 9, 1, 3, 4, 6, 7, 4, 0, 7, 2, 2, 6, 5, 6, 2, 5,
|
|
||||||
2, 9, 1, 0, 3, 8, 3, 0, 4, 5, 6, 7, 3, 3, 7, 0, 3, 6, 1, 3, 2, 8, 1, 2,
|
|
||||||
5, 1, 4, 5, 5, 1, 9, 1, 5, 2, 2, 8, 3, 6, 6, 8, 5, 1, 8, 0, 6, 6, 4, 0,
|
|
||||||
6, 2, 5, 7, 2, 7, 5, 9, 5, 7, 6, 1, 4, 1, 8, 3, 4, 2, 5, 9, 0, 3, 3, 2,
|
|
||||||
0, 3, 1, 2, 5, 3, 6, 3, 7, 9, 7, 8, 8, 0, 7, 0, 9, 1, 7, 1, 2, 9, 5, 1,
|
|
||||||
6, 6, 0, 1, 5, 6, 2, 5, 1, 8, 1, 8, 9, 8, 9, 4, 0, 3, 5, 4, 5, 8, 5, 6,
|
|
||||||
4, 7, 5, 8, 3, 0, 0, 7, 8, 1, 2, 5, 9, 0, 9, 4, 9, 4, 7, 0, 1, 7, 7, 2,
|
|
||||||
9, 2, 8, 2, 3, 7, 9, 1, 5, 0, 3, 9, 0, 6, 2, 5, 4, 5, 4, 7, 4, 7, 3, 5,
|
|
||||||
0, 8, 8, 6, 4, 6, 4, 1, 1, 8, 9, 5, 7, 5, 1, 9, 5, 3, 1, 2, 5, 2, 2, 7,
|
|
||||||
3, 7, 3, 6, 7, 5, 4, 4, 3, 2, 3, 2, 0, 5, 9, 4, 7, 8, 7, 5, 9, 7, 6, 5,
|
|
||||||
6, 2, 5, 1, 1, 3, 6, 8, 6, 8, 3, 7, 7, 2, 1, 6, 1, 6, 0, 2, 9, 7, 3, 9,
|
|
||||||
3, 7, 9, 8, 8, 2, 8, 1, 2, 5, 5, 6, 8, 4, 3, 4, 1, 8, 8, 6, 0, 8, 0, 8,
|
|
||||||
0, 1, 4, 8, 6, 9, 6, 8, 9, 9, 4, 1, 4, 0, 6, 2, 5, 2, 8, 4, 2, 1, 7, 0,
|
|
||||||
9, 4, 3, 0, 4, 0, 4, 0, 0, 7, 4, 3, 4, 8, 4, 4, 9, 7, 0, 7, 0, 3, 1, 2,
|
|
||||||
5, 1, 4, 2, 1, 0, 8, 5, 4, 7, 1, 5, 2, 0, 2, 0, 0, 3, 7, 1, 7, 4, 2, 2,
|
|
||||||
4, 8, 5, 3, 5, 1, 5, 6, 2, 5, 7, 1, 0, 5, 4, 2, 7, 3, 5, 7, 6, 0, 1, 0,
|
|
||||||
0, 1, 8, 5, 8, 7, 1, 1, 2, 4, 2, 6, 7, 5, 7, 8, 1, 2, 5, 3, 5, 5, 2, 7,
|
|
||||||
1, 3, 6, 7, 8, 8, 0, 0, 5, 0, 0, 9, 2, 9, 3, 5, 5, 6, 2, 1, 3, 3, 7, 8,
|
|
||||||
9, 0, 6, 2, 5, 1, 7, 7, 6, 3, 5, 6, 8, 3, 9, 4, 0, 0, 2, 5, 0, 4, 6, 4,
|
|
||||||
6, 7, 7, 8, 1, 0, 6, 6, 8, 9, 4, 5, 3, 1, 2, 5, 8, 8, 8, 1, 7, 8, 4, 1,
|
|
||||||
9, 7, 0, 0, 1, 2, 5, 2, 3, 2, 3, 3, 8, 9, 0, 5, 3, 3, 4, 4, 7, 2, 6, 5,
|
|
||||||
6, 2, 5, 4, 4, 4, 0, 8, 9, 2, 0, 9, 8, 5, 0, 0, 6, 2, 6, 1, 6, 1, 6, 9,
|
|
||||||
4, 5, 2, 6, 6, 7, 2, 3, 6, 3, 2, 8, 1, 2, 5, 2, 2, 2, 0, 4, 4, 6, 0, 4,
|
|
||||||
9, 2, 5, 0, 3, 1, 3, 0, 8, 0, 8, 4, 7, 2, 6, 3, 3, 3, 6, 1, 8, 1, 6, 4,
|
|
||||||
0, 6, 2, 5, 1, 1, 1, 0, 2, 2, 3, 0, 2, 4, 6, 2, 5, 1, 5, 6, 5, 4, 0, 4,
|
|
||||||
2, 3, 6, 3, 1, 6, 6, 8, 0, 9, 0, 8, 2, 0, 3, 1, 2, 5, 5, 5, 5, 1, 1, 1,
|
|
||||||
5, 1, 2, 3, 1, 2, 5, 7, 8, 2, 7, 0, 2, 1, 1, 8, 1, 5, 8, 3, 4, 0, 4, 5,
|
|
||||||
4, 1, 0, 1, 5, 6, 2, 5, 2, 7, 7, 5, 5, 5, 7, 5, 6, 1, 5, 6, 2, 8, 9, 1,
|
|
||||||
3, 5, 1, 0, 5, 9, 0, 7, 9, 1, 7, 0, 2, 2, 7, 0, 5, 0, 7, 8, 1, 2, 5, 1,
|
|
||||||
3, 8, 7, 7, 7, 8, 7, 8, 0, 7, 8, 1, 4, 4, 5, 6, 7, 5, 5, 2, 9, 5, 3, 9,
|
|
||||||
5, 8, 5, 1, 1, 3, 5, 2, 5, 3, 9, 0, 6, 2, 5, 6, 9, 3, 8, 8, 9, 3, 9, 0,
|
|
||||||
3, 9, 0, 7, 2, 2, 8, 3, 7, 7, 6, 4, 7, 6, 9, 7, 9, 2, 5, 5, 6, 7, 6, 2,
|
|
||||||
6, 9, 5, 3, 1, 2, 5, 3, 4, 6, 9, 4, 4, 6, 9, 5, 1, 9, 5, 3, 6, 1, 4, 1,
|
|
||||||
8, 8, 8, 2, 3, 8, 4, 8, 9, 6, 2, 7, 8, 3, 8, 1, 3, 4, 7, 6, 5, 6, 2, 5,
|
|
||||||
1, 7, 3, 4, 7, 2, 3, 4, 7, 5, 9, 7, 6, 8, 0, 7, 0, 9, 4, 4, 1, 1, 9, 2,
|
|
||||||
4, 4, 8, 1, 3, 9, 1, 9, 0, 6, 7, 3, 8, 2, 8, 1, 2, 5, 8, 6, 7, 3, 6, 1,
|
|
||||||
7, 3, 7, 9, 8, 8, 4, 0, 3, 5, 4, 7, 2, 0, 5, 9, 6, 2, 2, 4, 0, 6, 9, 5,
|
|
||||||
9, 5, 3, 3, 6, 9, 1, 4, 0, 6, 2, 5,
|
|
||||||
};
|
|
||||||
const uint8_t *pow5 =
|
|
||||||
&number_of_digits_decimal_left_shift_table_powers_of_5[pow5_a];
|
|
||||||
uint32_t i = 0;
|
|
||||||
uint32_t n = pow5_b - pow5_a;
|
|
||||||
for (; i < n; i++) {
|
|
||||||
if (i >= h.num_digits) {
|
|
||||||
return num_new_digits - 1;
|
|
||||||
} else if (h.digits[i] == pow5[i]) {
|
|
||||||
continue;
|
|
||||||
} else if (h.digits[i] < pow5[i]) {
|
|
||||||
return num_new_digits - 1;
|
|
||||||
} else {
|
|
||||||
return num_new_digits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return num_new_digits;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint64_t round(decimal &h) {
|
|
||||||
if ((h.num_digits == 0) || (h.decimal_point < 0)) {
|
|
||||||
return 0;
|
|
||||||
} else if (h.decimal_point > 18) {
|
|
||||||
return UINT64_MAX;
|
|
||||||
}
|
|
||||||
// at this point, we know that h.decimal_point >= 0
|
|
||||||
uint32_t dp = uint32_t(h.decimal_point);
|
|
||||||
uint64_t n = 0;
|
|
||||||
for (uint32_t i = 0; i < dp; i++) {
|
|
||||||
n = (10 * n) + ((i < h.num_digits) ? h.digits[i] : 0);
|
|
||||||
}
|
|
||||||
bool round_up = false;
|
|
||||||
if (dp < h.num_digits) {
|
|
||||||
round_up = h.digits[dp] >= 5; // normally, we round up
|
|
||||||
// but we may need to round to even!
|
|
||||||
if ((h.digits[dp] == 5) && (dp + 1 == h.num_digits)) {
|
|
||||||
round_up = h.truncated || ((dp > 0) && (1 & h.digits[dp - 1]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (round_up) {
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// computes h * 2^-shift
|
|
||||||
inline void decimal_left_shift(decimal &h, uint32_t shift) {
|
|
||||||
if (h.num_digits == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uint32_t num_new_digits = number_of_digits_decimal_left_shift(h, shift);
|
|
||||||
int32_t read_index = int32_t(h.num_digits - 1);
|
|
||||||
uint32_t write_index = h.num_digits - 1 + num_new_digits;
|
|
||||||
uint64_t n = 0;
|
|
||||||
|
|
||||||
while (read_index >= 0) {
|
|
||||||
n += uint64_t(h.digits[read_index]) << shift;
|
|
||||||
uint64_t quotient = n / 10;
|
|
||||||
uint64_t remainder = n - (10 * quotient);
|
|
||||||
if (write_index < max_digits) {
|
|
||||||
h.digits[write_index] = uint8_t(remainder);
|
|
||||||
} else if (remainder > 0) {
|
|
||||||
h.truncated = true;
|
|
||||||
}
|
|
||||||
n = quotient;
|
|
||||||
write_index--;
|
|
||||||
read_index--;
|
|
||||||
}
|
|
||||||
while (n > 0) {
|
|
||||||
uint64_t quotient = n / 10;
|
|
||||||
uint64_t remainder = n - (10 * quotient);
|
|
||||||
if (write_index < max_digits) {
|
|
||||||
h.digits[write_index] = uint8_t(remainder);
|
|
||||||
} else if (remainder > 0) {
|
|
||||||
h.truncated = true;
|
|
||||||
}
|
|
||||||
n = quotient;
|
|
||||||
write_index--;
|
|
||||||
}
|
|
||||||
h.num_digits += num_new_digits;
|
|
||||||
if (h.num_digits > max_digits) {
|
|
||||||
h.num_digits = max_digits;
|
|
||||||
}
|
|
||||||
h.decimal_point += int32_t(num_new_digits);
|
|
||||||
trim(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
// computes h * 2^shift
|
|
||||||
inline void decimal_right_shift(decimal &h, uint32_t shift) {
|
|
||||||
uint32_t read_index = 0;
|
|
||||||
uint32_t write_index = 0;
|
|
||||||
|
|
||||||
uint64_t n = 0;
|
|
||||||
|
|
||||||
while ((n >> shift) == 0) {
|
|
||||||
if (read_index < h.num_digits) {
|
|
||||||
n = (10 * n) + h.digits[read_index++];
|
|
||||||
} else if (n == 0) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
while ((n >> shift) == 0) {
|
|
||||||
n = 10 * n;
|
|
||||||
read_index++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h.decimal_point -= int32_t(read_index - 1);
|
|
||||||
if (h.decimal_point < -decimal_point_range) { // it is zero
|
|
||||||
h.num_digits = 0;
|
|
||||||
h.decimal_point = 0;
|
|
||||||
h.negative = false;
|
|
||||||
h.truncated = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uint64_t mask = (uint64_t(1) << shift) - 1;
|
|
||||||
while (read_index < h.num_digits) {
|
|
||||||
uint8_t new_digit = uint8_t(n >> shift);
|
|
||||||
n = (10 * (n & mask)) + h.digits[read_index++];
|
|
||||||
h.digits[write_index++] = new_digit;
|
|
||||||
}
|
|
||||||
while (n > 0) {
|
|
||||||
uint8_t new_digit = uint8_t(n >> shift);
|
|
||||||
n = 10 * (n & mask);
|
|
||||||
if (write_index < max_digits) {
|
|
||||||
h.digits[write_index++] = new_digit;
|
|
||||||
} else if (new_digit > 0) {
|
|
||||||
h.truncated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h.num_digits = write_index;
|
|
||||||
trim(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template <typename binary>
|
|
||||||
adjusted_mantissa compute_float(decimal &d) {
|
|
||||||
adjusted_mantissa answer;
|
|
||||||
if (d.num_digits == 0) {
|
|
||||||
// should be zero
|
|
||||||
answer.power2 = 0;
|
|
||||||
answer.mantissa = 0;
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
// At this point, going further, we can assume that d.num_digits > 0.
|
|
||||||
//
|
|
||||||
// We want to guard against excessive decimal point values because
|
|
||||||
// they can result in long running times. Indeed, we do
|
|
||||||
// shifts by at most 60 bits. We have that log(10**400)/log(2**60) ~= 22
|
|
||||||
// which is fine, but log(10**299995)/log(2**60) ~= 16609 which is not
|
|
||||||
// fine (runs for a long time).
|
|
||||||
//
|
|
||||||
if(d.decimal_point < -324) {
|
|
||||||
// We have something smaller than 1e-324 which is always zero
|
|
||||||
// in binary64 and binary32.
|
|
||||||
// It should be zero.
|
|
||||||
answer.power2 = 0;
|
|
||||||
answer.mantissa = 0;
|
|
||||||
return answer;
|
|
||||||
} else if(d.decimal_point >= 310) {
|
|
||||||
// We have something at least as large as 0.1e310 which is
|
|
||||||
// always infinite.
|
|
||||||
answer.power2 = binary::infinite_power();
|
|
||||||
answer.mantissa = 0;
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
constexpr uint32_t max_shift = 60;
|
|
||||||
constexpr uint32_t num_powers = 19;
|
|
||||||
constexpr uint8_t decimal_powers[19] = {
|
|
||||||
0, 3, 6, 9, 13, 16, 19, 23, 26, 29, //
|
|
||||||
33, 36, 39, 43, 46, 49, 53, 56, 59, //
|
|
||||||
};
|
|
||||||
int32_t exp2 = 0;
|
|
||||||
while (d.decimal_point > 0) {
|
|
||||||
uint32_t n = uint32_t(d.decimal_point);
|
|
||||||
uint32_t shift = (n < num_powers) ? decimal_powers[n] : max_shift;
|
|
||||||
detail::decimal_right_shift(d, shift);
|
|
||||||
if (d.decimal_point < -decimal_point_range) {
|
|
||||||
// should be zero
|
|
||||||
answer.power2 = 0;
|
|
||||||
answer.mantissa = 0;
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
exp2 += int32_t(shift);
|
|
||||||
}
|
|
||||||
// We shift left toward [1/2 ... 1].
|
|
||||||
while (d.decimal_point <= 0) {
|
|
||||||
uint32_t shift;
|
|
||||||
if (d.decimal_point == 0) {
|
|
||||||
if (d.digits[0] >= 5) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
shift = (d.digits[0] < 2) ? 2 : 1;
|
|
||||||
} else {
|
|
||||||
uint32_t n = uint32_t(-d.decimal_point);
|
|
||||||
shift = (n < num_powers) ? decimal_powers[n] : max_shift;
|
|
||||||
}
|
|
||||||
detail::decimal_left_shift(d, shift);
|
|
||||||
if (d.decimal_point > decimal_point_range) {
|
|
||||||
// we want to get infinity:
|
|
||||||
answer.power2 = binary::infinite_power();
|
|
||||||
answer.mantissa = 0;
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
exp2 -= int32_t(shift);
|
|
||||||
}
|
|
||||||
// We are now in the range [1/2 ... 1] but the binary format uses [1 ... 2].
|
|
||||||
exp2--;
|
|
||||||
constexpr int32_t minimum_exponent = binary::minimum_exponent();
|
|
||||||
while ((minimum_exponent + 1) > exp2) {
|
|
||||||
uint32_t n = uint32_t((minimum_exponent + 1) - exp2);
|
|
||||||
if (n > max_shift) {
|
|
||||||
n = max_shift;
|
|
||||||
}
|
|
||||||
detail::decimal_right_shift(d, n);
|
|
||||||
exp2 += int32_t(n);
|
|
||||||
}
|
|
||||||
if ((exp2 - minimum_exponent) >= binary::infinite_power()) {
|
|
||||||
answer.power2 = binary::infinite_power();
|
|
||||||
answer.mantissa = 0;
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int mantissa_size_in_bits = binary::mantissa_explicit_bits() + 1;
|
|
||||||
detail::decimal_left_shift(d, mantissa_size_in_bits);
|
|
||||||
|
|
||||||
uint64_t mantissa = detail::round(d);
|
|
||||||
// It is possible that we have an overflow, in which case we need
|
|
||||||
// to shift back.
|
|
||||||
if(mantissa >= (uint64_t(1) << mantissa_size_in_bits)) {
|
|
||||||
detail::decimal_right_shift(d, 1);
|
|
||||||
exp2 += 1;
|
|
||||||
mantissa = detail::round(d);
|
|
||||||
if ((exp2 - minimum_exponent) >= binary::infinite_power()) {
|
|
||||||
answer.power2 = binary::infinite_power();
|
|
||||||
answer.mantissa = 0;
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
answer.power2 = exp2 - binary::minimum_exponent();
|
|
||||||
if(mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) { answer.power2--; }
|
|
||||||
answer.mantissa = mantissa & ((uint64_t(1) << binary::mantissa_explicit_bits()) - 1);
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename binary>
|
|
||||||
adjusted_mantissa parse_long_mantissa(const char *first, const char* last, parse_options options) {
|
|
||||||
decimal d = parse_decimal(first, last, options);
|
|
||||||
return compute_float<binary>(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fast_float
|
|
||||||
#endif
|
|
||||||
@ -31,7 +31,7 @@ for filename in ['LICENSE-MIT', 'LICENSE-APACHE']:
|
|||||||
processed_files[filename] = text
|
processed_files[filename] = text
|
||||||
|
|
||||||
# code
|
# code
|
||||||
for filename in [ 'constexpr_feature_detect.h', 'fast_float.h', 'float_common.h', 'ascii_number.h',
|
for filename in [ 'constexpr_feature_detect.h', 'fast_float.h', 'float_common.h', 'ascii_number.h',
|
||||||
'fast_table.h', 'decimal_to_binary.h', 'bigint.h',
|
'fast_table.h', 'decimal_to_binary.h', 'bigint.h',
|
||||||
'ascii_number.h', 'digit_comparison.h', 'parse_number.h']:
|
'ascii_number.h', 'digit_comparison.h', 'parse_number.h']:
|
||||||
with open('include/fast_float/' + filename, encoding='utf8') as f:
|
with open('include/fast_float/' + filename, encoding='utf8') as f:
|
||||||
@ -73,10 +73,10 @@ def license_content(license_arg):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
text = ''.join([
|
text = ''.join([
|
||||||
processed_files['AUTHORS'], processed_files['CONTRIBUTORS'],
|
processed_files['AUTHORS'], processed_files['CONTRIBUTORS'],
|
||||||
*license_content(args.license),
|
*license_content(args.license),
|
||||||
processed_files['constexpr_feature_detect.h'],
|
processed_files['constexpr_feature_detect.h'],
|
||||||
processed_files['fast_float.h'], processed_files['float_common.h'],
|
processed_files['fast_float.h'], processed_files['float_common.h'],
|
||||||
processed_files['ascii_number.h'], processed_files['fast_table.h'],
|
processed_files['ascii_number.h'], processed_files['fast_table.h'],
|
||||||
processed_files['decimal_to_binary.h'], processed_files['bigint.h'],
|
processed_files['decimal_to_binary.h'], processed_files['bigint.h'],
|
||||||
processed_files['ascii_number.h'], processed_files['digit_comparison.h'],
|
processed_files['ascii_number.h'], processed_files['digit_comparison.h'],
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#
|
#
|
||||||
# Reference :
|
# Reference :
|
||||||
# Noble Mushtak and Daniel Lemire, Fast Number Parsing Without Fallback (to appear)
|
# Noble Mushtak and Daniel Lemire, Fast Number Parsing Without Fallback (to appear)
|
||||||
#
|
#
|
||||||
|
|
||||||
all_tqs = []
|
all_tqs = []
|
||||||
|
|
||||||
# Generates all possible values of T[q]
|
# Generates all possible values of T[q]
|
||||||
# Appendix B of Number parsing at a gigabyte per second.
|
# Appendix B of Number parsing at a gigabyte per second.
|
||||||
# Software: Practice and Experience 2021;51(8):1700–1727.
|
# Software: Practice and Experience 2021;51(8):1700–1727.
|
||||||
for q in range(-342, -27):
|
for q in range(-342, -27):
|
||||||
power5 = 5**-q
|
power5 = 5**-q
|
||||||
@ -44,9 +44,9 @@ def continued_fraction(numer, denom):
|
|||||||
numer, denom = denom, rem
|
numer, denom = denom, rem
|
||||||
return cf
|
return cf
|
||||||
|
|
||||||
# Given a continued fraction [a0; a1, a2, ..., an], returns
|
# Given a continued fraction [a0; a1, a2, ..., an], returns
|
||||||
# all the convergents of that continued fraction
|
# all the convergents of that continued fraction
|
||||||
# as pairs of the form (numer, denom), where numer/denom is
|
# as pairs of the form (numer, denom), where numer/denom is
|
||||||
# a convergent of the continued fraction in simple form.
|
# a convergent of the continued fraction in simple form.
|
||||||
def convergents(cf):
|
def convergents(cf):
|
||||||
p_n_minus_2 = 0
|
p_n_minus_2 = 0
|
||||||
|
|||||||
@ -286,11 +286,11 @@ bool check_file(std::string file_name) {
|
|||||||
// Parse as 32-bit float
|
// Parse as 32-bit float
|
||||||
float parsed_32;
|
float parsed_32;
|
||||||
auto fast_float_r32 = fast_float::from_chars(number_string, end_of_string, parsed_32);
|
auto fast_float_r32 = fast_float::from_chars(number_string, end_of_string, parsed_32);
|
||||||
if(fast_float_r32.ec != std::errc()) { std::cerr << "parsing failure\n"; return false; }
|
if(fast_float_r32.ec != std::errc() && fast_float_r32.ec != std::errc::result_out_of_range) {std::cerr << "32-bit fast_float parsing failure for: " + str + "\n"; return false; }
|
||||||
// Parse as 64-bit float
|
// Parse as 64-bit float
|
||||||
double parsed_64;
|
double parsed_64;
|
||||||
auto fast_float_r64 = fast_float::from_chars(number_string, end_of_string, parsed_64);
|
auto fast_float_r64 = fast_float::from_chars(number_string, end_of_string, parsed_64);
|
||||||
if(fast_float_r64.ec != std::errc()) { std::cerr << "parsing failure\n"; return false; }
|
if(fast_float_r64.ec != std::errc() && fast_float_r32.ec != std::errc::result_out_of_range) { std::cerr << "64-bit fast_float parsing failure: " + str + "\n"; return false; }
|
||||||
// Convert the floats to unsigned ints.
|
// Convert the floats to unsigned ints.
|
||||||
uint32_t float32_parsed;
|
uint32_t float32_parsed;
|
||||||
uint64_t float64_parsed;
|
uint64_t float64_parsed;
|
||||||
@ -509,6 +509,9 @@ TEST_CASE("test_fixed_only") {
|
|||||||
|
|
||||||
|
|
||||||
static const double testing_power_of_ten[] = {
|
static const double testing_power_of_ten[] = {
|
||||||
|
1e-323, 1e-322, 1e-321, 1e-320, 1e-319, 1e-318, 1e-317, 1e-316, 1e-315,
|
||||||
|
1e-314, 1e-313, 1e-312, 1e-311, 1e-310, 1e-309, 1e-308,
|
||||||
|
|
||||||
1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301, 1e-300, 1e-299,
|
1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301, 1e-300, 1e-299,
|
||||||
1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291, 1e-290,
|
1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291, 1e-290,
|
||||||
1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281,
|
1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281,
|
||||||
@ -592,8 +595,9 @@ TEST_CASE("powers_of_ten") {
|
|||||||
REQUIRE(n < sizeof(buf)); // if false, fails the test and exits
|
REQUIRE(n < sizeof(buf)); // if false, fails the test and exits
|
||||||
double actual;
|
double actual;
|
||||||
auto result = fast_float::from_chars(buf, buf + 1000, actual);
|
auto result = fast_float::from_chars(buf, buf + 1000, actual);
|
||||||
CHECK_MESSAGE(result.ec == std::errc(), " I could not parse " << buf);
|
double expected = ((i >= -323) ? testing_power_of_ten[i + 323] : std::pow(10, i));
|
||||||
double expected = ((i >= -307) ? testing_power_of_ten[i + 307] : std::pow(10, i));
|
auto expected_ec = (i < -323 || i > 308) ? std::errc::result_out_of_range : std::errc();
|
||||||
|
CHECK_MESSAGE(result.ec == expected_ec, " I could not parse " << buf);
|
||||||
CHECK_MESSAGE(actual == expected, "String '" << buf << "'parsed to " << actual);
|
CHECK_MESSAGE(actual == expected, "String '" << buf << "'parsed to " << actual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -643,7 +647,7 @@ enum class Diag { runtime, comptime };
|
|||||||
template <Diag diag, class T>
|
template <Diag diag, class T>
|
||||||
constexpr void check_basic_test_result(std::string_view str,
|
constexpr void check_basic_test_result(std::string_view str,
|
||||||
fast_float::from_chars_result result,
|
fast_float::from_chars_result result,
|
||||||
T actual, T expected) {
|
T actual, T expected, std::errc expected_ec) {
|
||||||
if constexpr (diag == Diag::runtime) {
|
if constexpr (diag == Diag::runtime) {
|
||||||
INFO(
|
INFO(
|
||||||
"str=" << str << "\n"
|
"str=" << str << "\n"
|
||||||
@ -689,7 +693,7 @@ constexpr void check_basic_test_result(std::string_view str,
|
|||||||
return x != x;
|
return x != x;
|
||||||
};
|
};
|
||||||
|
|
||||||
FASTFLOAT_CHECK_EQ(result.ec, std::errc());
|
FASTFLOAT_CHECK_EQ(result.ec, expected_ec);
|
||||||
FASTFLOAT_CHECK_EQ(result.ptr, str.data() + str.size());
|
FASTFLOAT_CHECK_EQ(result.ptr, str.data() + str.size());
|
||||||
FASTFLOAT_CHECK_EQ(copysign(1, actual), copysign(1, expected));
|
FASTFLOAT_CHECK_EQ(copysign(1, actual), copysign(1, expected));
|
||||||
FASTFLOAT_CHECK_EQ(isnan(actual), isnan(expected));
|
FASTFLOAT_CHECK_EQ(isnan(actual), isnan(expected));
|
||||||
@ -699,17 +703,24 @@ constexpr void check_basic_test_result(std::string_view str,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<Diag diag, class T>
|
template<Diag diag, class T>
|
||||||
constexpr void basic_test(std::string_view str, T expected) {
|
constexpr void basic_test(std::string_view str, T expected, std::errc expected_ec = std::errc()) {
|
||||||
T actual;
|
T actual;
|
||||||
auto result = fast_float::from_chars(str.data(), str.data() + str.size(), actual);
|
auto result = fast_float::from_chars(str.data(), str.data() + str.size(), actual);
|
||||||
check_basic_test_result<diag>(str, result, actual, expected);
|
check_basic_test_result<diag>(str, result, actual, expected, expected_ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Diag diag, class T>
|
template<Diag diag, class T>
|
||||||
constexpr void basic_test(std::string_view str, T expected, fast_float::parse_options options) {
|
constexpr void basic_test(std::string_view str, T expected, fast_float::parse_options options) {
|
||||||
T actual;
|
T actual;
|
||||||
auto result = fast_float::from_chars_advanced(str.data(), str.data() + str.size(), actual, options);
|
auto result = fast_float::from_chars_advanced(str.data(), str.data() + str.size(), actual, options);
|
||||||
check_basic_test_result<diag>(str, result, actual, expected);
|
check_basic_test_result<diag>(str, result, actual, expected, std::errc());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Diag diag, class T>
|
||||||
|
constexpr void basic_test(std::string_view str, T expected, std::errc expected_ec, fast_float::parse_options options) {
|
||||||
|
T actual;
|
||||||
|
auto result = fast_float::from_chars_advanced(str.data(), str.data() + str.size(), actual, options);
|
||||||
|
check_basic_test_result<diag>(str, result, actual, expected, expected_ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void basic_test(float val) {
|
void basic_test(float val) {
|
||||||
@ -725,29 +736,27 @@ void basic_test(float val) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define verify_runtime(lhs, rhs) \
|
#define verify_runtime(...) \
|
||||||
do { \
|
do { \
|
||||||
INFO(lhs); \
|
basic_test<Diag::runtime>(__VA_ARGS__); \
|
||||||
basic_test<Diag::runtime>(lhs, rhs); \
|
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define verify_comptime(lhs, rhs) \
|
#define verify_comptime(...) \
|
||||||
do { \
|
do { \
|
||||||
constexpr int verify_comptime_var = \
|
constexpr int verify_comptime_var = \
|
||||||
(basic_test<Diag::comptime>(lhs, rhs), 0); \
|
(basic_test<Diag::comptime>(__VA_ARGS__), 0); \
|
||||||
(void)verify_comptime_var; \
|
(void)verify_comptime_var; \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define verify_options_runtime(lhs, rhs) \
|
#define verify_options_runtime(...) \
|
||||||
do { \
|
do { \
|
||||||
INFO(lhs); \
|
basic_test<Diag::runtime>(__VA_ARGS__, options); \
|
||||||
basic_test<Diag::runtime>(lhs, rhs, options); \
|
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define verify_options_comptime(lhs, rhs) \
|
#define verify_options_comptime(...) \
|
||||||
do { \
|
do { \
|
||||||
constexpr int verify_options_comptime_var = \
|
constexpr int verify_options_comptime_var = \
|
||||||
(basic_test<Diag::comptime>(lhs, rhs, options), 0); \
|
(basic_test<Diag::comptime>(__VA_ARGS__, options), 0); \
|
||||||
(void)verify_options_comptime_var; \
|
(void)verify_options_comptime_var; \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
@ -756,16 +765,16 @@ void basic_test(float val) {
|
|||||||
#error "from_chars must be constexpr for constexpr tests"
|
#error "from_chars must be constexpr for constexpr tests"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define verify(lhs, rhs) \
|
#define verify(...) \
|
||||||
do { \
|
do { \
|
||||||
verify_runtime(lhs, rhs); \
|
verify_runtime(__VA_ARGS__); \
|
||||||
verify_comptime(lhs, rhs); \
|
verify_comptime(__VA_ARGS__); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define verify_options(lhs, rhs) \
|
#define verify_options(...) \
|
||||||
do { \
|
do { \
|
||||||
verify_options_runtime(lhs, rhs); \
|
verify_options_runtime(__VA_ARGS__); \
|
||||||
verify_options_comptime(lhs, rhs); \
|
verify_options_comptime(__VA_ARGS__); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -784,19 +793,19 @@ TEST_CASE("64bit.inf") {
|
|||||||
verify("-infinity", -std::numeric_limits<double>::infinity());
|
verify("-infinity", -std::numeric_limits<double>::infinity());
|
||||||
verify("inf", std::numeric_limits<double>::infinity());
|
verify("inf", std::numeric_limits<double>::infinity());
|
||||||
verify("-inf", -std::numeric_limits<double>::infinity());
|
verify("-inf", -std::numeric_limits<double>::infinity());
|
||||||
verify("1234456789012345678901234567890e9999999999999999999999999999", std::numeric_limits<double>::infinity());
|
verify("1234456789012345678901234567890e9999999999999999999999999999", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
verify("-2139879401095466344511101915470454744.9813888656856943E+272", -std::numeric_limits<double>::infinity());
|
verify("-2139879401095466344511101915470454744.9813888656856943E+272", -std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
verify("1.8e308", std::numeric_limits<double>::infinity());
|
verify("1.8e308", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
verify("1.832312213213213232132132143451234453123412321321312e308", std::numeric_limits<double>::infinity());
|
verify("1.832312213213213232132132143451234453123412321321312e308", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
verify("2e30000000000000000", std::numeric_limits<double>::infinity());
|
verify("2e30000000000000000", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
verify("2e3000", std::numeric_limits<double>::infinity());
|
verify("2e3000", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
verify("1.9e308", std::numeric_limits<double>::infinity());
|
verify("1.9e308", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("64bit.general") {
|
TEST_CASE("64bit.general") {
|
||||||
verify("22250738585072012e-324",0x1p-1022); /* limit between normal and subnormal*/
|
verify("22250738585072012e-324",0x1p-1022); /* limit between normal and subnormal*/
|
||||||
verify("-22250738585072012e-324",-0x1p-1022); /* limit between normal and subnormal*/
|
verify("-22250738585072012e-324",-0x1p-1022); /* limit between normal and subnormal*/
|
||||||
verify("-1e-999",-0.0);
|
verify("-1e-999", -0.0, std::errc::result_out_of_range);
|
||||||
verify("-2.2222222222223e-322",-0x1.68p-1069);
|
verify("-2.2222222222223e-322",-0x1.68p-1069);
|
||||||
verify("9007199254740993.0", 0x1p+53);
|
verify("9007199254740993.0", 0x1p+53);
|
||||||
verify("860228122.6654514319E+90", 0x1.92bb20990715fp+328);
|
verify("860228122.6654514319E+90", 0x1.92bb20990715fp+328);
|
||||||
@ -852,7 +861,7 @@ TEST_CASE("64bit.general") {
|
|||||||
verify("45035996.273704985", 45035996.273704985);
|
verify("45035996.273704985", 45035996.273704985);
|
||||||
verify("0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044501477170144022721148195934182639518696390927032912960468522194496444440421538910330590478162701758282983178260792422137401728773891892910553144148156412434867599762821265346585071045737627442980259622449029037796981144446145705102663115100318287949527959668236039986479250965780342141637013812613333119898765515451440315261253813266652951306000184917766328660755595837392240989947807556594098101021612198814605258742579179000071675999344145086087205681577915435923018910334964869420614052182892431445797605163650903606514140377217442262561590244668525767372446430075513332450079650686719491377688478005309963967709758965844137894433796621993967316936280457084866613206797017728916080020698679408551343728867675409720757232455434770912461317493580281734466552734375", 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044501477170144022721148195934182639518696390927032912960468522194496444440421538910330590478162701758282983178260792422137401728773891892910553144148156412434867599762821265346585071045737627442980259622449029037796981144446145705102663115100318287949527959668236039986479250965780342141637013812613333119898765515451440315261253813266652951306000184917766328660755595837392240989947807556594098101021612198814605258742579179000071675999344145086087205681577915435923018910334964869420614052182892431445797605163650903606514140377217442262561590244668525767372446430075513332450079650686719491377688478005309963967709758965844137894433796621993967316936280457084866613206797017728916080020698679408551343728867675409720757232455434770912461317493580281734466552734375);
|
verify("0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044501477170144022721148195934182639518696390927032912960468522194496444440421538910330590478162701758282983178260792422137401728773891892910553144148156412434867599762821265346585071045737627442980259622449029037796981144446145705102663115100318287949527959668236039986479250965780342141637013812613333119898765515451440315261253813266652951306000184917766328660755595837392240989947807556594098101021612198814605258742579179000071675999344145086087205681577915435923018910334964869420614052182892431445797605163650903606514140377217442262561590244668525767372446430075513332450079650686719491377688478005309963967709758965844137894433796621993967316936280457084866613206797017728916080020698679408551343728867675409720757232455434770912461317493580281734466552734375", 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044501477170144022721148195934182639518696390927032912960468522194496444440421538910330590478162701758282983178260792422137401728773891892910553144148156412434867599762821265346585071045737627442980259622449029037796981144446145705102663115100318287949527959668236039986479250965780342141637013812613333119898765515451440315261253813266652951306000184917766328660755595837392240989947807556594098101021612198814605258742579179000071675999344145086087205681577915435923018910334964869420614052182892431445797605163650903606514140377217442262561590244668525767372446430075513332450079650686719491377688478005309963967709758965844137894433796621993967316936280457084866613206797017728916080020698679408551343728867675409720757232455434770912461317493580281734466552734375);
|
||||||
verify("0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375", 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375);
|
verify("0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375", 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375);
|
||||||
verify("1438456663141390273526118207642235581183227845246331231162636653790368152091394196930365828634687637948157940776599182791387527135353034738357134110310609455693900824193549772792016543182680519740580354365467985440183598701312257624545562331397018329928613196125590274187720073914818062530830316533158098624984118889298281371812288789537310599037529113415438738954894752124724983067241108764488346454376699018673078404751121414804937224240805993123816932326223683090770561597570457793932985826162604255884529134126396282202126526253389383421806727954588525596114379801269094096329805054803089299736996870951258573010877404407451953846698609198213926882692078557033228265259305481198526059813164469187586693257335779522020407645498684263339921905227556616698129967412891282231685504660671277927198290009824680186319750978665734576683784255802269708917361719466043175201158849097881370477111850171579869056016061666173029059588433776015644439705050377554277696143928278093453792803846252715966016733222646442382892123940052441346822429721593884378212558701004356924243030059517489346646577724622498919752597382095222500311124181823512251071356181769376577651390028297796156208815375089159128394945710515861334486267101797497111125909272505194792870889617179758703442608016143343262159998149700606597792535574457560429226974273443630323818747730771316763398572110874959981923732463076884528677392654150010269822239401993427482376513231389212353583573566376915572650916866553612366187378959554983566712767093372906030188976220169058025354973622211666504549316958271880975697143546564469806791358707318873075708383345004090151974068325838177531266954177406661392229801349994695941509935655355652985723782153570084089560139142231.738475042362596875449154552392299548947138162081694168675340677843807613129780449323363759027012972466987370921816813162658754726545121090545507240267000456594786540949605260722461937870630634874991729398208026467698131898691830012167897399682179601734569071423681e-733", std::numeric_limits<double>::infinity());
|
verify("1438456663141390273526118207642235581183227845246331231162636653790368152091394196930365828634687637948157940776599182791387527135353034738357134110310609455693900824193549772792016543182680519740580354365467985440183598701312257624545562331397018329928613196125590274187720073914818062530830316533158098624984118889298281371812288789537310599037529113415438738954894752124724983067241108764488346454376699018673078404751121414804937224240805993123816932326223683090770561597570457793932985826162604255884529134126396282202126526253389383421806727954588525596114379801269094096329805054803089299736996870951258573010877404407451953846698609198213926882692078557033228265259305481198526059813164469187586693257335779522020407645498684263339921905227556616698129967412891282231685504660671277927198290009824680186319750978665734576683784255802269708917361719466043175201158849097881370477111850171579869056016061666173029059588433776015644439705050377554277696143928278093453792803846252715966016733222646442382892123940052441346822429721593884378212558701004356924243030059517489346646577724622498919752597382095222500311124181823512251071356181769376577651390028297796156208815375089159128394945710515861334486267101797497111125909272505194792870889617179758703442608016143343262159998149700606597792535574457560429226974273443630323818747730771316763398572110874959981923732463076884528677392654150010269822239401993427482376513231389212353583573566376915572650916866553612366187378959554983566712767093372906030188976220169058025354973622211666504549316958271880975697143546564469806791358707318873075708383345004090151974068325838177531266954177406661392229801349994695941509935655355652985723782153570084089560139142231.738475042362596875449154552392299548947138162081694168675340677843807613129780449323363759027012972466987370921816813162658754726545121090545507240267000456594786540949605260722461937870630634874991729398208026467698131898691830012167897399682179601734569071423681e-733", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
verify("-2240084132271013504.131248280843119943687942846658579428", -0x1.f1660a65b00bfp+60);
|
verify("-2240084132271013504.131248280843119943687942846658579428", -0x1.f1660a65b00bfp+60);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -864,11 +873,11 @@ TEST_CASE("64bit.decimal_point") {
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
// infinities
|
// infinities
|
||||||
verify_options("1,8e308", std::numeric_limits<double>::infinity());
|
verify_options("1,8e308", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
verify_options("1,832312213213213232132132143451234453123412321321312e308", std::numeric_limits<double>::infinity());
|
verify_options("1,832312213213213232132132143451234453123412321321312e308", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
verify_options("2e30000000000000000", std::numeric_limits<double>::infinity());
|
verify_options("2e30000000000000000", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
verify_options("2e3000", std::numeric_limits<double>::infinity());
|
verify_options("2e3000", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
verify_options("1,9e308", std::numeric_limits<double>::infinity());
|
verify_options("1,9e308", std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
|
||||||
|
|
||||||
// finites
|
// finites
|
||||||
verify_options("-2,2222222222223e-322",-0x1.68p-1069);
|
verify_options("-2,2222222222223e-322",-0x1.68p-1069);
|
||||||
@ -928,13 +937,13 @@ TEST_CASE("32bit.inf") {
|
|||||||
verify("-infinity", -std::numeric_limits<float>::infinity());
|
verify("-infinity", -std::numeric_limits<float>::infinity());
|
||||||
verify("inf", std::numeric_limits<float>::infinity());
|
verify("inf", std::numeric_limits<float>::infinity());
|
||||||
verify("-inf", -std::numeric_limits<float>::infinity());
|
verify("-inf", -std::numeric_limits<float>::infinity());
|
||||||
verify("1234456789012345678901234567890e9999999999999999999999999999", std::numeric_limits<float>::infinity());
|
verify("1234456789012345678901234567890e9999999999999999999999999999", std::numeric_limits<float>::infinity(), std::errc::result_out_of_range);
|
||||||
verify("2e3000", std::numeric_limits<float>::infinity());
|
verify("2e3000", std::numeric_limits<float>::infinity(), std::errc::result_out_of_range);
|
||||||
verify("3.5028234666e38", std::numeric_limits<float>::infinity());
|
verify("3.5028234666e38", std::numeric_limits<float>::infinity(), std::errc::result_out_of_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("32bit.general") {
|
TEST_CASE("32bit.general") {
|
||||||
verify("-1e-999",-0.0f);
|
verify("-1e-999", -0.0f, std::errc::result_out_of_range);
|
||||||
verify("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125", 0x1.2ced3p+0f);
|
verify("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125", 0x1.2ced3p+0f);
|
||||||
verify("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125e-38", 0x1.fffff8p-127f);
|
verify("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125e-38", 0x1.fffff8p-127f);
|
||||||
verify_runtime(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655), 0x1.2ced3p+0f);
|
verify_runtime(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655), 0x1.2ced3p+0f);
|
||||||
@ -1000,7 +1009,7 @@ TEST_CASE("32bit.general") {
|
|||||||
verify("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679", 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f);
|
verify("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679", 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f);
|
||||||
verify("2.3509887016445750159374730744444913556373311135441750430175034126e-38", 2.3509887016445750159374730744444913556373311135441750430175034126e-38f);
|
verify("2.3509887016445750159374730744444913556373311135441750430175034126e-38", 2.3509887016445750159374730744444913556373311135441750430175034126e-38f);
|
||||||
verify("1", 1.f);
|
verify("1", 1.f);
|
||||||
verify("7.0060e-46", 0.f);
|
verify("7.0060e-46", 0.f, std::errc::result_out_of_range);
|
||||||
verify("3.4028234664e38", 0x1.fffffep+127f);
|
verify("3.4028234664e38", 0x1.fffffep+127f);
|
||||||
verify("3.4028234665e38", 0x1.fffffep+127f);
|
verify("3.4028234665e38", 0x1.fffffep+127f);
|
||||||
verify("3.4028234666e38", 0x1.fffffep+127f);
|
verify("3.4028234666e38", 0x1.fffffep+127f);
|
||||||
@ -1018,7 +1027,7 @@ TEST_CASE("32bit.decimal_point") {
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
// infinity
|
// infinity
|
||||||
verify_options("3,5028234666e38", std::numeric_limits<float>::infinity());
|
verify_options("3,5028234666e38", std::numeric_limits<float>::infinity(), std::errc::result_out_of_range);
|
||||||
|
|
||||||
// finites
|
// finites
|
||||||
verify_options("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125", 0x1.2ced3p+0f);
|
verify_options("1,1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125", 0x1.2ced3p+0f);
|
||||||
@ -1043,7 +1052,7 @@ TEST_CASE("32bit.decimal_point") {
|
|||||||
verify_options("3,1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679", 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f);
|
verify_options("3,1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679", 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f);
|
||||||
verify_options("2,3509887016445750159374730744444913556373311135441750430175034126e-38", 2.3509887016445750159374730744444913556373311135441750430175034126e-38f);
|
verify_options("2,3509887016445750159374730744444913556373311135441750430175034126e-38", 2.3509887016445750159374730744444913556373311135441750430175034126e-38f);
|
||||||
verify_options("1", 1.f);
|
verify_options("1", 1.f);
|
||||||
verify_options("7,0060e-46", 0.f);
|
verify_options("7,0060e-46", 0.f, std::errc::result_out_of_range);
|
||||||
verify_options("3,4028234664e38", 0x1.fffffep+127f);
|
verify_options("3,4028234664e38", 0x1.fffffep+127f);
|
||||||
verify_options("3,4028234665e38", 0x1.fffffep+127f);
|
verify_options("3,4028234665e38", 0x1.fffffep+127f);
|
||||||
verify_options("3,4028234666e38", 0x1.fffffep+127f);
|
verify_options("3,4028234666e38", 0x1.fffffep+127f);
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
const std::string input = "3,1416 xyz ";
|
const std::string input = "3,1416 xyz ";
|
||||||
double result;
|
double result;
|
||||||
|
|||||||
@ -30,7 +30,10 @@ void allvalues() {
|
|||||||
const char *string_end = to_string(v, buffer);
|
const char *string_end = to_string(v, buffer);
|
||||||
float result_value;
|
float result_value;
|
||||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||||
if (result.ec != std::errc()) {
|
// Starting with version 4.0 for fast_float, we return result_out_of_range if the
|
||||||
|
// value is either too small (too close to zero) or too large (effectively infinity).
|
||||||
|
// So std::errc::result_out_of_range is normal for well-formed input strings.
|
||||||
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@ -46,7 +49,7 @@ void allvalues() {
|
|||||||
} else if (result_value != v) {
|
} else if (result_value != v) {
|
||||||
std::cerr << "no match ? " << buffer << std::endl;
|
std::cerr << "no match ? " << buffer << std::endl;
|
||||||
std::cout << "started with " << std::hexfloat << v << std::endl;
|
std::cout << "started with " << std::hexfloat << v << std::endl;
|
||||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||||
std::cout << std::dec;
|
std::cout << std::dec;
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ bool basic_test_64bit(std::string vals, double val) {
|
|||||||
double result_value;
|
double result_value;
|
||||||
auto result = fast_float::from_chars(vals.data(), vals.data() + vals.size(),
|
auto result = fast_float::from_chars(vals.data(), vals.data() + vals.size(),
|
||||||
result_value);
|
result_value);
|
||||||
if (result.ec != std::errc()) {
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
std::cerr << " I could not parse " << vals << std::endl;
|
std::cerr << " I could not parse " << vals << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -30,11 +30,11 @@ bool basic_test_64bit(std::string vals, double val) {
|
|||||||
std::cerr << vals << std::endl;
|
std::cerr << vals << std::endl;
|
||||||
std::cerr << "not nan" << result_value << std::endl;
|
std::cerr << "not nan" << result_value << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if(copysign(1,result_value) != copysign(1,val)) {
|
} else if(copysign(1,result_value) != copysign(1,val)) {
|
||||||
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
|
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
return false;
|
return false;
|
||||||
} else if (result_value != val) {
|
} else if (result_value != val) {
|
||||||
std::cerr << vals << std::endl;
|
std::cerr << vals << std::endl;
|
||||||
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
|
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__)
|
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
// Anything at all that is related to cygwin, msys and so forth will
|
// Anything at all that is related to cygwin, msys and so forth will
|
||||||
// always use this fallback because we cannot rely on it behaving as normal
|
// always use this fallback because we cannot rely on it behaving as normal
|
||||||
// gcc.
|
// gcc.
|
||||||
@ -73,7 +73,7 @@ bool allvalues() {
|
|||||||
}
|
}
|
||||||
uint32_t word = uint32_t(w);
|
uint32_t word = uint32_t(w);
|
||||||
memcpy(&v, &word, sizeof(v));
|
memcpy(&v, &word, sizeof(v));
|
||||||
if(std::isfinite(v)) {
|
if(std::isfinite(v)) {
|
||||||
float nextf = std::nextafterf(v, INFINITY);
|
float nextf = std::nextafterf(v, INFINITY);
|
||||||
if(copysign(1,v) != copysign(1,nextf)) { continue; }
|
if(copysign(1,v) != copysign(1,nextf)) { continue; }
|
||||||
if(!std::isfinite(nextf)) { continue; }
|
if(!std::isfinite(nextf)) { continue; }
|
||||||
@ -90,7 +90,10 @@ bool allvalues() {
|
|||||||
|
|
||||||
float result_value;
|
float result_value;
|
||||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||||
if (result.ec != std::errc()) {
|
// Starting with version 4.0 for fast_float, we return result_out_of_range if the
|
||||||
|
// value is either too small (too close to zero) or too large (effectively infinity).
|
||||||
|
// So std::errc::result_out_of_range is normal for well-formed input strings.
|
||||||
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -120,7 +123,7 @@ bool allvalues() {
|
|||||||
std::cerr << "expected_midv " << std::hexfloat << expected_midv << std::endl;
|
std::cerr << "expected_midv " << std::hexfloat << expected_midv << std::endl;
|
||||||
std::cout << "started with " << std::hexfloat << midv << std::endl;
|
std::cout << "started with " << std::hexfloat << midv << std::endl;
|
||||||
std::cout << "round down to " << std::hexfloat << str_answer << std::endl;
|
std::cout << "round down to " << std::hexfloat << str_answer << std::endl;
|
||||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||||
std::cout << std::dec;
|
std::cout << std::dec;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -133,7 +136,7 @@ bool allvalues() {
|
|||||||
inline void Assert(bool Assertion) {
|
inline void Assert(bool Assertion) {
|
||||||
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(sun) || defined(__sun)
|
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(sun) || defined(__sun)
|
||||||
if (!Assertion) { std::cerr << "Omitting hard failure on msys/cygwin/sun systems."; }
|
if (!Assertion) { std::cerr << "Omitting hard failure on msys/cygwin/sun systems."; }
|
||||||
#else
|
#else
|
||||||
if (!Assertion) { throw std::runtime_error("bug"); }
|
if (!Assertion) { throw std::runtime_error("bug"); }
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ find_package(FastFloat REQUIRED)
|
|||||||
file(WRITE main.cpp "
|
file(WRITE main.cpp "
|
||||||
#include \"fast_float/fast_float.h\"
|
#include \"fast_float/fast_float.h\"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
const std::string input = \"3.1416 xyz \";
|
const std::string input = \"3.1416 xyz \";
|
||||||
double result;
|
double result;
|
||||||
|
|||||||
@ -29,7 +29,10 @@ void allvalues() {
|
|||||||
const char *string_end = to_string(v, buffer);
|
const char *string_end = to_string(v, buffer);
|
||||||
float result_value;
|
float result_value;
|
||||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||||
if (result.ec != std::errc()) {
|
// Starting with version 4.0 for fast_float, we return result_out_of_range if the
|
||||||
|
// value is either too small (too close to zero) or too large (effectively infinity).
|
||||||
|
// So std::errc::result_out_of_range is normal for well-formed input strings.
|
||||||
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@ -46,7 +49,7 @@ void allvalues() {
|
|||||||
} else if (result_value != v) {
|
} else if (result_value != v) {
|
||||||
std::cerr << "no match ? " << buffer << " got " << result_value << " expected " << v << std::endl;
|
std::cerr << "no match ? " << buffer << " got " << result_value << " expected " << v << std::endl;
|
||||||
std::cout << "started with " << std::hexfloat << v << std::endl;
|
std::cout << "started with " << std::hexfloat << v << std::endl;
|
||||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||||
std::cout << std::dec;
|
std::cout << std::dec;
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,10 @@ void all_32bit_values() {
|
|||||||
const char *string_end = to_string(v, buffer);
|
const char *string_end = to_string(v, buffer);
|
||||||
double result_value;
|
double result_value;
|
||||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||||
if (result.ec != std::errc()) {
|
// Starting with version 4.0 for fast_float, we return result_out_of_range if the
|
||||||
|
// value is either too small (too close to zero) or too large (effectively infinity).
|
||||||
|
// So std::errc::result_out_of_range is normal for well-formed input strings.
|
||||||
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@ -49,7 +52,7 @@ void all_32bit_values() {
|
|||||||
} else if (result_value != v) {
|
} else if (result_value != v) {
|
||||||
std::cerr << "no match ? " << buffer << std::endl;
|
std::cerr << "no match ? " << buffer << std::endl;
|
||||||
std::cout << "started with " << std::hexfloat << v << std::endl;
|
std::cout << "started with " << std::hexfloat << v << std::endl;
|
||||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||||
std::cout << std::dec;
|
std::cout << std::dec;
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,9 +27,9 @@ static fast_float::value128 g_lehmer64_state;
|
|||||||
* Society 68.225 (1999): 249-260.
|
* Society 68.225 (1999): 249-260.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline void lehmer64_seed(uint64_t seed) {
|
static inline void lehmer64_seed(uint64_t seed) {
|
||||||
g_lehmer64_state.high = 0;
|
g_lehmer64_state.high = 0;
|
||||||
g_lehmer64_state.low = seed;
|
g_lehmer64_state.low = seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t lehmer64() {
|
static inline uint64_t lehmer64() {
|
||||||
@ -56,7 +56,10 @@ void random_values(size_t N) {
|
|||||||
const char *string_end = to_string(v, buffer);
|
const char *string_end = to_string(v, buffer);
|
||||||
double result_value;
|
double result_value;
|
||||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||||
if (result.ec != std::errc()) {
|
// Starting with version 4.0 for fast_float, we return result_out_of_range if the
|
||||||
|
// value is either too small (too close to zero) or too large (effectively infinity).
|
||||||
|
// So std::errc::result_out_of_range is normal for well-formed input strings.
|
||||||
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||||
errors++;
|
errors++;
|
||||||
if (errors > 10) {
|
if (errors > 10) {
|
||||||
@ -80,7 +83,7 @@ void random_values(size_t N) {
|
|||||||
} else if (result_value != v) {
|
} else if (result_value != v) {
|
||||||
std::cerr << "no match ? '" << buffer << "'" << std::endl;
|
std::cerr << "no match ? '" << buffer << "'" << std::endl;
|
||||||
std::cout << "started with " << std::hexfloat << v << std::endl;
|
std::cout << "started with " << std::hexfloat << v << std::endl;
|
||||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||||
std::cout << std::dec;
|
std::cout << std::dec;
|
||||||
errors++;
|
errors++;
|
||||||
if (errors > 10) {
|
if (errors > 10) {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ bool test() {
|
|||||||
while((begin < end) && (std::isspace(*begin))) { begin++; }
|
while((begin < end) && (std::isspace(*begin))) { begin++; }
|
||||||
auto result = fast_float::from_chars(begin, end,
|
auto result = fast_float::from_chars(begin, end,
|
||||||
result_value);
|
result_value);
|
||||||
if (result.ec != std::errc()) {
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
printf("parsing %.*s\n", int(end - begin), begin);
|
printf("parsing %.*s\n", int(end - begin), begin);
|
||||||
std::cerr << " I could not parse " << std::endl;
|
std::cerr << " I could not parse " << std::endl;
|
||||||
return false;
|
return false;
|
||||||
@ -40,7 +40,7 @@ bool test() {
|
|||||||
}
|
}
|
||||||
if(begin != end) {
|
if(begin != end) {
|
||||||
std::cerr << " bad ending " << std::endl;
|
std::cerr << " bad ending " << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,7 +105,7 @@ bool tester() {
|
|||||||
double result_value;
|
double result_value;
|
||||||
auto result =
|
auto result =
|
||||||
fast_float::from_chars(to_be_parsed.data(), to_be_parsed.data() + to_be_parsed.size(), result_value);
|
fast_float::from_chars(to_be_parsed.data(), to_be_parsed.data() + to_be_parsed.size(), result_value);
|
||||||
if (result.ec != std::errc()) {
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
std::cout << to_be_parsed << std::endl;
|
std::cout << to_be_parsed << std::endl;
|
||||||
std::cerr << " I could not parse " << std::endl;
|
std::cerr << " I could not parse " << std::endl;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -29,9 +29,9 @@ static fast_float::value128 g_lehmer64_state;
|
|||||||
* Society 68.225 (1999): 249-260.
|
* Society 68.225 (1999): 249-260.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline void lehmer64_seed(uint64_t seed) {
|
static inline void lehmer64_seed(uint64_t seed) {
|
||||||
g_lehmer64_state.high = 0;
|
g_lehmer64_state.high = 0;
|
||||||
g_lehmer64_state.low = seed;
|
g_lehmer64_state.low = seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t lehmer64() {
|
static inline uint64_t lehmer64() {
|
||||||
@ -59,7 +59,10 @@ void random_values(size_t N) {
|
|||||||
const char *string_end = to_string(v, buffer);
|
const char *string_end = to_string(v, buffer);
|
||||||
double result_value;
|
double result_value;
|
||||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||||
if (result.ec != std::errc()) {
|
// Starting with version 4.0 for fast_float, we return result_out_of_range if the
|
||||||
|
// value is either too small (too close to zero) or too large (effectively infinity).
|
||||||
|
// So std::errc::result_out_of_range is normal for well-formed input strings.
|
||||||
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||||
errors++;
|
errors++;
|
||||||
if (errors > 10) {
|
if (errors > 10) {
|
||||||
@ -83,7 +86,7 @@ void random_values(size_t N) {
|
|||||||
} else if (result_value != v) {
|
} else if (result_value != v) {
|
||||||
std::cerr << "no match ? " << buffer << std::endl;
|
std::cerr << "no match ? " << buffer << std::endl;
|
||||||
std::cout << "started with " << std::hexfloat << v << std::endl;
|
std::cout << "started with " << std::hexfloat << v << std::endl;
|
||||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||||
std::cout << std::dec;
|
std::cout << std::dec;
|
||||||
errors++;
|
errors++;
|
||||||
if (errors > 10) {
|
if (errors > 10) {
|
||||||
|
|||||||
@ -101,7 +101,12 @@ size_t build_random_string(RandomEngine &rand, char *buffer) {
|
|||||||
if (i == size_t(location_of_decimal_separator)) {
|
if (i == size_t(location_of_decimal_separator)) {
|
||||||
buffer[pos++] = '.';
|
buffer[pos++] = '.';
|
||||||
}
|
}
|
||||||
buffer[pos++] = char(rand.next_digit() + '0');
|
buffer[pos] = char(rand.next_digit() + '0');
|
||||||
|
// We can have a leading zero only if location_of_decimal_separator = 1.
|
||||||
|
while(i == 0 && 1 != size_t(location_of_decimal_separator) && buffer[pos] == '0') {
|
||||||
|
buffer[pos] = char(rand.next_digit() + '0');
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
}
|
}
|
||||||
if (rand.next_bool()) {
|
if (rand.next_bool()) {
|
||||||
if (rand.next_bool()) {
|
if (rand.next_bool()) {
|
||||||
@ -178,7 +183,7 @@ bool tester(uint64_t seed, size_t volume) {
|
|||||||
double result_value;
|
double result_value;
|
||||||
auto result =
|
auto result =
|
||||||
fast_float::from_chars(buffer, buffer + length, result_value);
|
fast_float::from_chars(buffer, buffer + length, result_value);
|
||||||
if (result.ec != std::errc()) {
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
printf("parsing %.*s\n", int(length), buffer);
|
printf("parsing %.*s\n", int(length), buffer);
|
||||||
std::cerr << " I could not parse " << std::endl;
|
std::cerr << " I could not parse " << std::endl;
|
||||||
return false;
|
return false;
|
||||||
@ -201,7 +206,7 @@ bool tester(uint64_t seed, size_t volume) {
|
|||||||
float result_value;
|
float result_value;
|
||||||
auto result =
|
auto result =
|
||||||
fast_float::from_chars(buffer, buffer + length, result_value);
|
fast_float::from_chars(buffer, buffer + length, result_value);
|
||||||
if (result.ec != std::errc()) {
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
printf("parsing %.*s\n", int(length), buffer);
|
printf("parsing %.*s\n", int(length), buffer);
|
||||||
std::cerr << " I could not parse " << std::endl;
|
std::cerr << " I could not parse " << std::endl;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -97,7 +97,12 @@ size_t build_random_string(RandomEngine &rand, char *buffer) {
|
|||||||
if (i == size_t(location_of_decimal_separator)) {
|
if (i == size_t(location_of_decimal_separator)) {
|
||||||
buffer[pos++] = '.';
|
buffer[pos++] = '.';
|
||||||
}
|
}
|
||||||
buffer[pos++] = char(rand.next_digit() + '0');
|
buffer[pos] = char(rand.next_digit() + '0');
|
||||||
|
// We can have a leading zero only if location_of_decimal_separator = 1.
|
||||||
|
while(i == 0 && 1 != size_t(location_of_decimal_separator) && buffer[pos] == '0') {
|
||||||
|
buffer[pos] = char(rand.next_digit() + '0');
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
}
|
}
|
||||||
if (rand.next_bool()) {
|
if (rand.next_bool()) {
|
||||||
if (rand.next_bool()) {
|
if (rand.next_bool()) {
|
||||||
@ -174,7 +179,7 @@ bool tester(uint64_t seed, size_t volume) {
|
|||||||
double result_value;
|
double result_value;
|
||||||
auto result =
|
auto result =
|
||||||
fast_float::from_chars(buffer, buffer + length, result_value);
|
fast_float::from_chars(buffer, buffer + length, result_value);
|
||||||
if (result.ec != std::errc()) {
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
printf("parsing %.*s\n", int(length), buffer);
|
printf("parsing %.*s\n", int(length), buffer);
|
||||||
std::cerr << " I could not parse " << std::endl;
|
std::cerr << " I could not parse " << std::endl;
|
||||||
return false;
|
return false;
|
||||||
@ -197,7 +202,7 @@ bool tester(uint64_t seed, size_t volume) {
|
|||||||
float result_value;
|
float result_value;
|
||||||
auto result =
|
auto result =
|
||||||
fast_float::from_chars(buffer, buffer + length, result_value);
|
fast_float::from_chars(buffer, buffer + length, result_value);
|
||||||
if (result.ec != std::errc()) {
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
printf("parsing %.*s\n", int(length), buffer);
|
printf("parsing %.*s\n", int(length), buffer);
|
||||||
std::cerr << " I could not parse " << std::endl;
|
std::cerr << " I could not parse " << std::endl;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -62,6 +62,7 @@ template <typename T>
|
|||||||
bool test() {
|
bool test() {
|
||||||
std::string input = "0.1 1e1000 100000 3.14159265359 -1e-500 001 1e01 1e0000001 -inf";
|
std::string input = "0.1 1e1000 100000 3.14159265359 -1e-500 001 1e01 1e0000001 -inf";
|
||||||
std::vector<T> answers = {T(0.1), std::numeric_limits<T>::infinity(), 100000, T(3.14159265359), -0.0, 1, 10, 10, -std::numeric_limits<T>::infinity()};
|
std::vector<T> answers = {T(0.1), std::numeric_limits<T>::infinity(), 100000, T(3.14159265359), -0.0, 1, 10, 10, -std::numeric_limits<T>::infinity()};
|
||||||
|
std::vector<std::errc> expected_ec = {std::errc(), std::errc::result_out_of_range, std::errc(), std::errc(), std::errc::result_out_of_range, std::errc(), std::errc(), std::errc(), std::errc()};
|
||||||
const char * begin = input.data();
|
const char * begin = input.data();
|
||||||
const char * end = input.data() + input.size();
|
const char * end = input.data() + input.size();
|
||||||
for(size_t i = 0; i < answers.size(); i++) {
|
for(size_t i = 0; i < answers.size(); i++) {
|
||||||
@ -69,7 +70,7 @@ bool test() {
|
|||||||
while((begin < end) && (std::isspace(*begin))) { begin++; }
|
while((begin < end) && (std::isspace(*begin))) { begin++; }
|
||||||
auto result = fast_float::from_chars(begin, end,
|
auto result = fast_float::from_chars(begin, end,
|
||||||
result_value);
|
result_value);
|
||||||
if (result.ec != std::errc()) {
|
if (result.ec != expected_ec[i]) {
|
||||||
printf("parsing %.*s\n", int(end - begin), begin);
|
printf("parsing %.*s\n", int(end - begin), begin);
|
||||||
std::cerr << " I could not parse " << std::endl;
|
std::cerr << " I could not parse " << std::endl;
|
||||||
return false;
|
return false;
|
||||||
@ -84,7 +85,7 @@ bool test() {
|
|||||||
}
|
}
|
||||||
if(begin != end) {
|
if(begin != end) {
|
||||||
std::cerr << " bad ending " << std::endl;
|
std::cerr << " bad ending " << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -238,7 +239,7 @@ bool partow_test() {
|
|||||||
T result_value;
|
T result_value;
|
||||||
auto result = fast_float::from_chars(st.data(), st.data() + st.size(),
|
auto result = fast_float::from_chars(st.data(), st.data() + st.size(),
|
||||||
result_value);
|
result_value);
|
||||||
if (result.ec != std::errc()) {
|
if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) {
|
||||||
printf("parsing %.*s\n", int(st.size()), st.data());
|
printf("parsing %.*s\n", int(st.size()), st.data());
|
||||||
std::cerr << " I could not parse " << std::endl;
|
std::cerr << " I could not parse " << std::endl;
|
||||||
return false;
|
return false;
|
||||||
@ -269,7 +270,7 @@ int main() {
|
|||||||
std::cout << "32 bits checks" << std::endl;
|
std::cout << "32 bits checks" << std::endl;
|
||||||
Assert(partow_test<float>());
|
Assert(partow_test<float>());
|
||||||
Assert(test<float>());
|
Assert(test<float>());
|
||||||
|
|
||||||
std::cout << "64 bits checks" << std::endl;
|
std::cout << "64 bits checks" << std::endl;
|
||||||
Assert(partow_test<double>());
|
Assert(partow_test<double>());
|
||||||
Assert(test<double>());
|
Assert(test<double>());
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user