mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-06 08:46:49 +08:00
We need to update some of our exhaustive tests to the new API
This commit is contained in:
parent
843fb97064
commit
ca43e6722e
2
.github/workflows/ubuntu22-clang.yml
vendored
2
.github/workflows/ubuntu22-clang.yml
vendored
@ -22,4 +22,4 @@ jobs:
|
||||
cd build20 &&
|
||||
CXX=clang++-14 cmake -DFASTFLOAT_CONSTEXPR_TESTS=ON -DCMAKE_CXX_STANDARD=20 -DFASTFLOAT_TEST=ON .. &&
|
||||
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 &&
|
||||
CXX=g++-12 CXXFLAGS=-Werror cmake -DFASTFLOAT_CONSTEXPR_TESTS=ON -DCMAKE_CXX_STANDARD=20 -DFASTFLOAT_TEST=ON .. &&
|
||||
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 &&
|
||||
cmake -DFASTFLOAT_TEST=ON .. &&
|
||||
cmake --build . &&
|
||||
ctest --output-on-failure
|
||||
ctest --output-on-failure
|
||||
10
README.md
10
README.md
@ -189,11 +189,11 @@ It can parse random floating-point numbers at a speed of 1 GB/s on some systems.
|
||||
$ ./build/benchmarks/benchmark
|
||||
# parsing random integers in the range [0,1)
|
||||
volume = 2.09808 MB
|
||||
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
|
||||
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
|
||||
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
|
||||
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
|
||||
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
|
||||
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
|
||||
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
|
||||
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
|
||||
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 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.
|
||||
|
||||
@ -48,9 +48,9 @@ namespace detail {
|
||||
* where
|
||||
* 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);
|
||||
* is equal to
|
||||
* is equal to
|
||||
* -ceil(p) + q
|
||||
* where
|
||||
* p = log(5**-q)/log(2) = -q * log(5)/log(2)
|
||||
|
||||
@ -31,7 +31,7 @@ for filename in ['LICENSE-MIT', 'LICENSE-APACHE']:
|
||||
processed_files[filename] = text
|
||||
|
||||
# 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',
|
||||
'ascii_number.h', 'digit_comparison.h', 'parse_number.h']:
|
||||
with open('include/fast_float/' + filename, encoding='utf8') as f:
|
||||
@ -73,10 +73,10 @@ def license_content(license_arg):
|
||||
return result
|
||||
|
||||
text = ''.join([
|
||||
processed_files['AUTHORS'], processed_files['CONTRIBUTORS'],
|
||||
processed_files['AUTHORS'], processed_files['CONTRIBUTORS'],
|
||||
*license_content(args.license),
|
||||
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['decimal_to_binary.h'], processed_files['bigint.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)
|
||||
#
|
||||
|
||||
all_tqs = []
|
||||
|
||||
# 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.
|
||||
for q in range(-342, -27):
|
||||
power5 = 5**-q
|
||||
@ -44,9 +44,9 @@ def continued_fraction(numer, denom):
|
||||
numer, denom = denom, rem
|
||||
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
|
||||
# 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.
|
||||
def convergents(cf):
|
||||
p_n_minus_2 = 0
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
|
||||
int main() {
|
||||
const std::string input = "3,1416 xyz ";
|
||||
double result;
|
||||
|
||||
@ -30,7 +30,10 @@ void allvalues() {
|
||||
const char *string_end = to_string(v, buffer);
|
||||
float 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;
|
||||
abort();
|
||||
}
|
||||
@ -46,7 +49,7 @@ void allvalues() {
|
||||
} else if (result_value != v) {
|
||||
std::cerr << "no match ? " << buffer << 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;
|
||||
abort();
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ bool basic_test_64bit(std::string vals, double val) {
|
||||
double result_value;
|
||||
auto result = fast_float::from_chars(vals.data(), vals.data() + vals.size(),
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
@ -30,11 +30,11 @@ bool basic_test_64bit(std::string vals, double val) {
|
||||
std::cerr << vals << std::endl;
|
||||
std::cerr << "not nan" << result_value << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if(copysign(1,result_value) != copysign(1,val)) {
|
||||
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
|
||||
<< std::endl;
|
||||
return false;
|
||||
return false;
|
||||
} else if (result_value != val) {
|
||||
std::cerr << vals << std::endl;
|
||||
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include <limits>
|
||||
#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
|
||||
// always use this fallback because we cannot rely on it behaving as normal
|
||||
// gcc.
|
||||
@ -73,7 +73,7 @@ bool allvalues() {
|
||||
}
|
||||
uint32_t word = uint32_t(w);
|
||||
memcpy(&v, &word, sizeof(v));
|
||||
if(std::isfinite(v)) {
|
||||
if(std::isfinite(v)) {
|
||||
float nextf = std::nextafterf(v, INFINITY);
|
||||
if(copysign(1,v) != copysign(1,nextf)) { continue; }
|
||||
if(!std::isfinite(nextf)) { continue; }
|
||||
@ -90,7 +90,10 @@ bool allvalues() {
|
||||
|
||||
float 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;
|
||||
return false;
|
||||
}
|
||||
@ -120,7 +123,7 @@ bool allvalues() {
|
||||
std::cerr << "expected_midv " << std::hexfloat << expected_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 << "got back " << std::hexfloat << result_value << std::endl;
|
||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||
std::cout << std::dec;
|
||||
return false;
|
||||
}
|
||||
@ -133,7 +136,7 @@ bool allvalues() {
|
||||
inline void Assert(bool Assertion) {
|
||||
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(sun) || defined(__sun)
|
||||
if (!Assertion) { std::cerr << "Omitting hard failure on msys/cygwin/sun systems."; }
|
||||
#else
|
||||
#else
|
||||
if (!Assertion) { throw std::runtime_error("bug"); }
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ find_package(FastFloat REQUIRED)
|
||||
file(WRITE main.cpp "
|
||||
#include \"fast_float/fast_float.h\"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
int main() {
|
||||
const std::string input = \"3.1416 xyz \";
|
||||
double result;
|
||||
|
||||
@ -29,7 +29,10 @@ void allvalues() {
|
||||
const char *string_end = to_string(v, buffer);
|
||||
float 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;
|
||||
abort();
|
||||
}
|
||||
@ -46,7 +49,7 @@ void allvalues() {
|
||||
} else if (result_value != v) {
|
||||
std::cerr << "no match ? " << buffer << " got " << result_value << " expected " << 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;
|
||||
abort();
|
||||
}
|
||||
|
||||
@ -28,7 +28,10 @@ void all_32bit_values() {
|
||||
const char *string_end = to_string(v, buffer);
|
||||
double 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;
|
||||
abort();
|
||||
}
|
||||
@ -49,7 +52,7 @@ void all_32bit_values() {
|
||||
} else if (result_value != v) {
|
||||
std::cerr << "no match ? " << buffer << 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;
|
||||
abort();
|
||||
}
|
||||
|
||||
@ -27,9 +27,9 @@ static fast_float::value128 g_lehmer64_state;
|
||||
* 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.low = seed;
|
||||
g_lehmer64_state.low = seed;
|
||||
}
|
||||
|
||||
static inline uint64_t lehmer64() {
|
||||
@ -56,7 +56,10 @@ void random_values(size_t N) {
|
||||
const char *string_end = to_string(v, buffer);
|
||||
double 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;
|
||||
errors++;
|
||||
if (errors > 10) {
|
||||
@ -80,7 +83,7 @@ void random_values(size_t N) {
|
||||
} else if (result_value != v) {
|
||||
std::cerr << "no match ? '" << buffer << "'" << 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;
|
||||
errors++;
|
||||
if (errors > 10) {
|
||||
|
||||
@ -22,7 +22,7 @@ bool test() {
|
||||
while((begin < end) && (std::isspace(*begin))) { begin++; }
|
||||
auto result = fast_float::from_chars(begin, end,
|
||||
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);
|
||||
std::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
@ -40,7 +40,7 @@ bool test() {
|
||||
}
|
||||
if(begin != end) {
|
||||
std::cerr << " bad ending " << std::endl;
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ bool tester() {
|
||||
double result_value;
|
||||
auto result =
|
||||
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::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
|
||||
@ -29,9 +29,9 @@ static fast_float::value128 g_lehmer64_state;
|
||||
* 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.low = seed;
|
||||
g_lehmer64_state.low = seed;
|
||||
}
|
||||
|
||||
static inline uint64_t lehmer64() {
|
||||
@ -59,7 +59,10 @@ void random_values(size_t N) {
|
||||
const char *string_end = to_string(v, buffer);
|
||||
double 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;
|
||||
errors++;
|
||||
if (errors > 10) {
|
||||
@ -83,7 +86,7 @@ void random_values(size_t N) {
|
||||
} else if (result_value != v) {
|
||||
std::cerr << "no match ? " << buffer << 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;
|
||||
errors++;
|
||||
if (errors > 10) {
|
||||
|
||||
@ -101,7 +101,12 @@ size_t build_random_string(RandomEngine &rand, char *buffer) {
|
||||
if (i == size_t(location_of_decimal_separator)) {
|
||||
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()) {
|
||||
@ -178,7 +183,7 @@ bool tester(uint64_t seed, size_t volume) {
|
||||
double result_value;
|
||||
auto result =
|
||||
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);
|
||||
std::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
@ -201,7 +206,7 @@ bool tester(uint64_t seed, size_t volume) {
|
||||
float result_value;
|
||||
auto result =
|
||||
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);
|
||||
std::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
|
||||
@ -97,7 +97,12 @@ size_t build_random_string(RandomEngine &rand, char *buffer) {
|
||||
if (i == size_t(location_of_decimal_separator)) {
|
||||
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()) {
|
||||
@ -174,7 +179,7 @@ bool tester(uint64_t seed, size_t volume) {
|
||||
double result_value;
|
||||
auto result =
|
||||
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);
|
||||
std::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
@ -197,7 +202,7 @@ bool tester(uint64_t seed, size_t volume) {
|
||||
float result_value;
|
||||
auto result =
|
||||
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);
|
||||
std::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
|
||||
@ -85,7 +85,7 @@ bool test() {
|
||||
}
|
||||
if(begin != end) {
|
||||
std::cerr << " bad ending " << std::endl;
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -239,7 +239,7 @@ bool partow_test() {
|
||||
T result_value;
|
||||
auto result = fast_float::from_chars(st.data(), st.data() + st.size(),
|
||||
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());
|
||||
std::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
@ -270,7 +270,7 @@ int main() {
|
||||
std::cout << "32 bits checks" << std::endl;
|
||||
Assert(partow_test<float>());
|
||||
Assert(test<float>());
|
||||
|
||||
|
||||
std::cout << "64 bits checks" << std::endl;
|
||||
Assert(partow_test<double>());
|
||||
Assert(test<double>());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user