diff --git a/3rdparty/fast_float/README.md b/3rdparty/fast_float/README.md index 06c30c3de8..8fdddbc5bf 100644 --- a/3rdparty/fast_float/README.md +++ b/3rdparty/fast_float/README.md @@ -57,6 +57,7 @@ Example: ```C++ #include "fast_float/fast_float.h" #include +#include int main() { std::string input = "3.1416 xyz "; @@ -68,6 +69,25 @@ int main() { } ``` +Though the C++17 standard has you do a comparison with `std::errc()` to check whether the conversion worked, you can avoid it by casting the result to a `bool` like so: + +```cpp +#include "fast_float/fast_float.h" +#include +#include + +int main() { + std::string input = "3.1416 xyz "; + double result; + if(auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result)) { + std::cout << "parsed the number " << result << std::endl; + return EXIT_SUCCESS; + } + std::cerr << "failed to parse " << result << std::endl; + return EXIT_FAILURE; +} +``` + You can parse delimited numbers: ```C++ @@ -357,6 +377,34 @@ int main() { } ``` +## Multiplication of an integer by a power of 10 +An integer `W` can be multiplied by a power of ten `10^Q` and +converted to `double` with correctly rounded value +(in "round to nearest, tie to even" fashion) using +`fast_float::integer_times_pow10()`, e.g.: +```C++ +const uint64_t W = 12345678901234567; +const int Q = 23; +const double result = fast_float::integer_times_pow10(W, Q); +std::cout.precision(17); +std::cout << W << " * 10^" << Q << " = " << result << " (" + << (result == 12345678901234567e23 ? "==" : "!=") << "expected)\n"; +``` +outputs +``` +12345678901234567 * 10^23 = 1.2345678901234567e+39 (==expected) +``` +`fast_float::integer_times_pow10()` gives the same result as +using `fast_float::from_chars()` when parsing the string `"WeQ"` +(in this example `"12345678901234567e23"`), +except `fast_float::integer_times_pow10()` does not report out-of-range errors, and +underflows to zero or overflows to infinity when the resulting value is +out of range. + +Overloads of `fast_float::integer_times_pow10()` are provided for +signed and unsigned integer types: `int64_t`, `uint64_t`, etc. + + ## Users and Related Work The fast_float library is part of: @@ -364,6 +412,8 @@ The fast_float library is part of: * GCC (as of version 12): the `from_chars` function in GCC relies on fast_float, * [Chromium](https://github.com/Chromium/Chromium), the engine behind Google Chrome, Microsoft Edge, and Opera, +* Boost JSON, MySQL, etc. +* Blender * [WebKit](https://github.com/WebKit/WebKit), the engine behind Safari (Apple's web browser), * [DuckDB](https://duckdb.org), @@ -376,7 +426,10 @@ The fast_float library is part of: The fastfloat algorithm is part of the [LLVM standard libraries](https://github.com/llvm/llvm-project/commit/87c016078ad72c46505461e4ff8bfa04819fe7ba). There is a [derived implementation part of -AdaCore](https://github.com/AdaCore/VSS). +AdaCore](https://github.com/AdaCore/VSS). The [SerenityOS operating +system](https://github.com/SerenityOS/serenity/commit/53b7f5e6a11e663c83df8030c3171c5945cb75ec) +has a derived implementation that is inherited by the [Ladybird +Browser](https://github.com/LadybirdBrowser/ladybird). The fast_float library provides a performance similar to that of the [fast_double_parser](https://github.com/lemire/fast_double_parser) library but @@ -385,6 +438,14 @@ API more in line with the expectations of C++ programmers. The fast_double_parser library is part of the [Microsoft LightGBM machine-learning framework](https://github.com/microsoft/LightGBM). + + +Packages +------ + +[![Packaging status](https://repology.org/badge/vertical-allrepos/fastfloat.svg)](https://repology.org/project/fastfloat/versions) + + ## References * Daniel Lemire, [Number Parsing at a Gigabyte per @@ -455,7 +516,7 @@ sufficiently recent version of CMake (3.11 or better at least): FetchContent_Declare( fast_float GIT_REPOSITORY https://github.com/fastfloat/fast_float.git - GIT_TAG tags/v8.0.2 + GIT_TAG tags/v8.1.0 GIT_SHALLOW TRUE) FetchContent_MakeAvailable(fast_float) @@ -471,7 +532,7 @@ You may also use [CPM](https://github.com/cpm-cmake/CPM.cmake), like so: CPMAddPackage( NAME fast_float GITHUB_REPOSITORY "fastfloat/fast_float" - GIT_TAG v8.0.2) + GIT_TAG v8.1.0) ``` ## Using as single header @@ -483,7 +544,7 @@ if desired as described in the command line help. You may directly download automatically generated single-header files: - + ## Benchmarking @@ -522,6 +583,7 @@ cmake --build build manager](https://conan.io/center/recipes/fast_float). * It is part of the [brew package manager](https://formulae.brew.sh/formula/fast_float). +* fast_float is available on [xmake](https://xmake.io) repository. * Some Linux distribution like Fedora include fast_float (e.g., as `fast_float-devel`). diff --git a/3rdparty/fast_float/include/fast_float/ascii_number.h b/3rdparty/fast_float/include/fast_float/ascii_number.h index 97f0681077..5683cd47af 100644 --- a/3rdparty/fast_float/include/fast_float/ascii_number.h +++ b/3rdparty/fast_float/include/fast_float/ascii_number.h @@ -441,7 +441,7 @@ parse_number_string(UC const *p, UC const *pend, if (digit_count > 19) { answer.too_many_digits = true; // Let us start again, this time, avoiding overflows. - // We don't need to check if is_integer, since we use the + // We don't need to call if is_integer, since we use the // pre-tokenized spans from above. i = 0; p = answer.integer.ptr; @@ -451,7 +451,7 @@ parse_number_string(UC const *p, UC const *pend, i = i * 10 + uint64_t(*p - UC('0')); ++p; } - if (i >= minimal_nineteen_digit_integer) { // We have a big integers + if (i >= minimal_nineteen_digit_integer) { // We have a big integer exponent = end_of_integer_part - p + exp_number; } else { // We have a value with a fractional component. p = answer.fraction.ptr; diff --git a/3rdparty/fast_float/include/fast_float/fast_float.h b/3rdparty/fast_float/include/fast_float/fast_float.h index af65c96bde..a190d7c823 100644 --- a/3rdparty/fast_float/include/fast_float/fast_float.h +++ b/3rdparty/fast_float/include/fast_float/fast_float.h @@ -45,6 +45,24 @@ FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(UC const *first, UC const *last, T &value, parse_options_t options) noexcept; +/** + * This function multiplies an integer number by a power of 10 and returns + * the result as a double precision floating-point value that is correctly + * rounded. The resulting floating-point value is the closest floating-point + * value, using the "round to nearest, tie to even" convention for values that + * would otherwise fall right in-between two values. That is, we provide exact + * conversion according to the IEEE standard. + * + * On overflow infinity is returned, on underflow 0 is returned. + * + * The implementation does not throw and does not allocate memory (e.g., with + * `new` or `malloc`). + */ +FASTFLOAT_CONSTEXPR20 inline double +integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept; +FASTFLOAT_CONSTEXPR20 inline double +integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept; + /** * from_chars for integer types. */ diff --git a/3rdparty/fast_float/include/fast_float/float_common.h b/3rdparty/fast_float/include/fast_float/float_common.h index 8fd0560296..62d199ca82 100644 --- a/3rdparty/fast_float/include/fast_float/float_common.h +++ b/3rdparty/fast_float/include/fast_float/float_common.h @@ -16,8 +16,8 @@ #include "constexpr_feature_detect.h" #define FASTFLOAT_VERSION_MAJOR 8 -#define FASTFLOAT_VERSION_MINOR 0 -#define FASTFLOAT_VERSION_PATCH 2 +#define FASTFLOAT_VERSION_MINOR 1 +#define FASTFLOAT_VERSION_PATCH 0 #define FASTFLOAT_STRINGIZE_IMPL(x) #x #define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x) @@ -58,6 +58,11 @@ enum class chars_format : uint64_t { template struct from_chars_result_t { UC const *ptr; std::errc ec; + + // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2497r0.html + constexpr explicit operator bool() const noexcept { + return ec == std::errc(); + } }; using from_chars_result = from_chars_result_t; @@ -88,11 +93,12 @@ using parse_options = parse_options_t; defined(__MINGW64__) || defined(__s390x__) || \ (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \ defined(__PPC64LE__)) || \ - defined(__loongarch64)) + defined(__loongarch64) || (defined(__riscv) && __riscv_xlen == 64)) #define FASTFLOAT_64BIT 1 #elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__arm__) || defined(_M_ARM) || defined(__ppc__) || \ - defined(__MINGW32__) || defined(__EMSCRIPTEN__)) + defined(__MINGW32__) || defined(__EMSCRIPTEN__) || \ + (defined(__riscv) && __riscv_xlen == 32)) #define FASTFLOAT_32BIT 1 #else // Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow. @@ -1126,7 +1132,12 @@ template constexpr uint64_t int_luts::min_safe_u64[]; template fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { - return int_luts<>::chdigit[static_cast(c)]; + // wchar_t and char can be signed, so we need to be careful. + using UnsignedUC = typename std::make_unsigned::type; + return int_luts<>::chdigit[static_cast( + static_cast(c) & + static_cast( + -((static_cast(c) & ~0xFFull) == 0)))]; } fastfloat_really_inline constexpr size_t max_digits_u64(int base) { diff --git a/3rdparty/fast_float/include/fast_float/parse_number.h b/3rdparty/fast_float/include/fast_float/parse_number.h index e74c478f5d..a44fef0b56 100644 --- a/3rdparty/fast_float/include/fast_float/parse_number.h +++ b/3rdparty/fast_float/include/fast_float/parse_number.h @@ -188,32 +188,17 @@ from_chars(UC const *first, UC const *last, T &value, parse_options_t(fmt)); } -/** - * This function overload takes parsed_number_string_t structure that is created - * and populated either by from_chars_advanced function taking chars range and - * parsing options or other parsing custom function implemented by user. - */ -template -FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { - - static_assert(is_supported_float_type::value, - "only some floating-point types are supported"); - static_assert(is_supported_char_type::value, - "only char, wchar_t, char16_t and char32_t are supported"); - - from_chars_result_t answer; - - answer.ec = std::errc(); // be optimistic - answer.ptr = pns.lastmatch; +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool +clinger_fast_path_impl(uint64_t mantissa, int64_t exponent, bool is_negative, + T &value) noexcept { // The implementation of the Clinger's fast path is convoluted because // we want round-to-nearest in all cases, irrespective of the rounding mode // selected on the thread. // We proceed optimistically, assuming that detail::rounds_to_nearest() // returns true. - if (binary_format::min_exponent_fast_path() <= pns.exponent && - pns.exponent <= binary_format::max_exponent_fast_path() && - !pns.too_many_digits) { + if (binary_format::min_exponent_fast_path() <= exponent && + exponent <= binary_format::max_exponent_fast_path()) { // Unfortunately, the conventional Clinger's fast path is only possible // when the system rounds to the nearest float. // @@ -224,41 +209,64 @@ from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) { // We have that fegetround() == FE_TONEAREST. // Next is Clinger's fast path. - if (pns.mantissa <= binary_format::max_mantissa_fast_path()) { - value = T(pns.mantissa); - if (pns.exponent < 0) { - value = value / binary_format::exact_power_of_ten(-pns.exponent); + if (mantissa <= binary_format::max_mantissa_fast_path()) { + value = T(mantissa); + if (exponent < 0) { + value = value / binary_format::exact_power_of_ten(-exponent); } else { - value = value * binary_format::exact_power_of_ten(pns.exponent); + value = value * binary_format::exact_power_of_ten(exponent); } - if (pns.negative) { + if (is_negative) { value = -value; } - return answer; + return true; } } else { // We do not have that fegetround() == FE_TONEAREST. // Next is a modified Clinger's fast path, inspired by Jakub JelĂ­nek's // proposal - if (pns.exponent >= 0 && - pns.mantissa <= - binary_format::max_mantissa_fast_path(pns.exponent)) { + if (exponent >= 0 && + mantissa <= binary_format::max_mantissa_fast_path(exponent)) { #if defined(__clang__) || defined(FASTFLOAT_32BIT) // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD - if (pns.mantissa == 0) { - value = pns.negative ? T(-0.) : T(0.); - return answer; + if (mantissa == 0) { + value = is_negative ? T(-0.) : T(0.); + return true; } #endif - value = T(pns.mantissa) * - binary_format::exact_power_of_ten(pns.exponent); - if (pns.negative) { + value = T(mantissa) * binary_format::exact_power_of_ten(exponent); + if (is_negative) { value = -value; } - return answer; + return true; } } } + return false; +} + +/** + * This function overload takes parsed_number_string_t structure that is created + * and populated either by from_chars_advanced function taking chars range and + * parsing options or other parsing custom function implemented by user. + */ +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { + static_assert(is_supported_float_type::value, + "only some floating-point types are supported"); + static_assert(is_supported_char_type::value, + "only char, wchar_t, char16_t and char32_t are supported"); + + from_chars_result_t answer; + + answer.ec = std::errc(); // be optimistic + answer.ptr = pns.lastmatch; + + if (!pns.too_many_digits && + clinger_fast_path_impl(pns.mantissa, pns.exponent, pns.negative, value)) + return answer; + adjusted_mantissa am = compute_float>(pns.exponent, pns.mantissa); if (pns.too_many_digits && am.power2 >= 0) { @@ -336,6 +344,49 @@ from_chars(UC const *first, UC const *last, T &value, int base) noexcept { return from_chars_advanced(first, last, value, options); } +FASTFLOAT_CONSTEXPR20 inline double +integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept { + double value; + if (clinger_fast_path_impl(mantissa, decimal_exponent, false, value)) + return value; + + adjusted_mantissa am = + compute_float>(decimal_exponent, mantissa); + to_float(false, am, value); + return value; +} + +FASTFLOAT_CONSTEXPR20 inline double +integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept { + const bool is_negative = mantissa < 0; + const uint64_t m = static_cast(is_negative ? -mantissa : mantissa); + + double value; + if (clinger_fast_path_impl(m, decimal_exponent, is_negative, value)) + return value; + + adjusted_mantissa am = + compute_float>(decimal_exponent, m); + to_float(is_negative, am, value); + return value; +} + +// the following overloads are here to avoid surprising ambiguity for int, +// unsigned, etc. +template +FASTFLOAT_CONSTEXPR20 inline typename std::enable_if< + std::is_integral::value && !std::is_signed::value, double>::type +integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { + return integer_times_pow10(static_cast(mantissa), decimal_exponent); +} + +template +FASTFLOAT_CONSTEXPR20 inline typename std::enable_if< + std::is_integral::value && std::is_signed::value, double>::type +integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { + return integer_times_pow10(static_cast(mantissa), decimal_exponent); +} + template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_int_advanced(UC const *first, UC const *last, T &value,