Compare commits

..

No commits in common. "main" and "v8.0.2" have entirely different histories.
main ... v8.0.2

35 changed files with 139 additions and 1043 deletions

View File

@ -18,7 +18,7 @@ jobs:
- riscv64
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
- name: Install latest Alpine Linux for ${{ matrix.arch }}
uses: jirutka/setup-alpine@v1

View File

@ -1,12 +1,12 @@
name: Amalgamate Ubuntu 24.04 CI
name: Amalgamate Ubuntu 20.04 CI (GCC 9)
on: [push, pull_request]
jobs:
ubuntu-build:
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Compile with amalgamation
run: |
mkdir build &&

View File

@ -20,14 +20,14 @@ jobs:
fuzz-seconds: 300
output-sarif: true
- name: Upload Crash
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts
- name: Upload Sarif
if: always() && steps.build.outcome == 'success'
uses: github/codeql-action/upload-sarif@v4
uses: github/codeql-action/upload-sarif@v3
with:
# Path to SARIF file relative to the root of the repository
sarif_file: cifuzz-sarif/results.sarif

View File

@ -1,17 +0,0 @@
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14
- name: Verify
run: emcc -v
- name: Checkout
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v3.6.0
- name: Configure
run: emcmake cmake -B build
- name: Build # We build but do not test
run: cmake --build build

View File

@ -24,10 +24,10 @@ jobs:
lint-and-format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.1.7
- uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 # v4.1.7
- name: Run clang-format
uses: jidicula/clang-format-action@4726374d1aa3c6aecf132e5197e498979588ebc8 # v4.15.0
uses: jidicula/clang-format-action@d05cecd4a1a5b7e64c22f5a468456135a43f13f6 # v4.14.0
with:
clang-format-version: '17'

View File

@ -23,7 +23,7 @@ jobs:
CMAKE_GENERATOR: Ninja
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
with:
update: true

View File

@ -29,7 +29,7 @@ jobs:
CMAKE_GENERATOR: Ninja
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
with:
update: true

View File

@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Amalgamate fast_float.h
run: |

View File

@ -1,23 +0,0 @@
name: Ubuntu RISC-V rvv VLEN=128 (clang 17)
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- name: Install packages
run: |
sudo apt-get update -q -y
sudo apt-get install -y cmake make g++-riscv64-linux-gnu qemu-user-static clang-17
- name: Build
run: |
CXX=clang++-17 CXXFLAGS="--target=riscv64-linux-gnu -march=rv64gcv" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build/ -j$(nproc)
- name: Test VLEN=128
run: |
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
export QEMU_CPU="rv64,v=on,vlen=128,rvv_ta_all_1s=on,rvv_ma_all_1s=on"
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)

View File

@ -12,7 +12,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v3
name: Test
id: runcmd

View File

@ -1,14 +1,14 @@
name: Ubuntu 24.04 CI
name: Ubuntu 20.04 CI (C++20)
on: [push, pull_request]
jobs:
ubuntu-build:
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Use cmake
run: |
mkdir build &&

16
.github/workflows/ubuntu20-fastmath.yml vendored Normal file
View File

@ -0,0 +1,16 @@
name: Ubuntu 20.04 CI (GCC 9, fast-math)
on: [push, pull_request]
jobs:
ubuntu-build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Use cmake
run: |
mkdir build &&
cd build &&
cmake -DCMAKE_CXX_FLAGS="-ffast-math" -DFASTFLOAT_TEST=ON .. &&
cmake --build . &&
ctest --output-on-failure

21
.github/workflows/ubuntu20.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: Ubuntu 20.04 CI (GCC 9)
on: [push, pull_request]
jobs:
ubuntu-build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Use cmake
run: |
mkdir build &&
cd build &&
cmake ${{matrix.cxx}} ${{matrix.arch}} -DFASTFLOAT_TEST=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest --output-on-failure &&
cmake --install . &&
cd ../tests/installation_tests/find &&
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build . &&
cd ../../issue72_installation &&
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .

View File

@ -6,7 +6,7 @@ jobs:
ubuntu-build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Install clang++-14
run: sudo apt-get install -y clang++-14
- name: Use cmake

View File

@ -6,7 +6,7 @@ jobs:
ubuntu-build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Use cmake
run: |
mkdir build &&

View File

@ -6,7 +6,7 @@ jobs:
ubuntu-build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Use cmake
run: |
mkdir build &&

View File

@ -6,7 +6,7 @@ jobs:
ubuntu-build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Use cmake
run: |
mkdir build &&

View File

@ -6,7 +6,7 @@ jobs:
ubuntu-build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Use cmake
run: |
set -xe

View File

@ -14,7 +14,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: ARM64, cfg: Debug}
steps:
- name: checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
- name: configure
run: |
cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DCMAKE_CROSSCOMPILING=1 -DFASTFLOAT_TEST=ON

View File

@ -16,7 +16,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: x64, cfg: Debug}
steps:
- name: checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
- name: configure
run: |
cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -DFASTFLOAT_TEST=ON -DCMAKE_INSTALL_PREFIX:PATH=destination

View File

@ -16,7 +16,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: x64, cfg: Debug}
steps:
- name: checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
- name: Configure
run: |
cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -T ClangCL -DFASTFLOAT_TEST=ON

View File

@ -16,7 +16,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: x64, cfg: Debug}
steps:
- name: checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
- name: configure
run: >-
cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}}

View File

@ -1,7 +1,6 @@
cmake_minimum_required(VERSION 3.14)
cmake_minimum_required(VERSION 3.9)
project(fast_float VERSION 8.1.0 LANGUAGES CXX)
project(fast_float VERSION 8.0.2 LANGUAGES CXX)
set(FASTFLOAT_CXX_STANDARD 11 CACHE STRING "the C++ standard to use for fastfloat")
set(CMAKE_CXX_STANDARD ${FASTFLOAT_CXX_STANDARD})
option(FASTFLOAT_TEST "Enable tests" OFF)

View File

@ -57,7 +57,6 @@ Example:
```C++
#include "fast_float/fast_float.h"
#include <iostream>
#include <string>
int main() {
std::string input = "3.1416 xyz ";
@ -69,25 +68,6 @@ 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 <iostream>
#include <string>
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++
@ -377,51 +357,6 @@ 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.
You can use template overloads to get the result converted to different
supported floating-point types: `float`, `double`, etc.
For example, to get result as `float` use
`fast_float::integer_times_pow10<float>()` specialization:
```C++
const uint64_t W = 12345678;
const int Q = 23;
const float result = fast_float::integer_times_pow10<float>(W, Q);
std::cout.precision(9);
std::cout << "float: " << W << " * 10^" << Q << " = " << result << " ("
<< (result == 12345678e23f ? "==" : "!=") << "expected)\n";
```
outputs
```
float: 12345678 * 10^23 = 1.23456782e+30 (==expected)
```
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:
@ -429,8 +364,6 @@ 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),
@ -443,10 +376,7 @@ 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). 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).
AdaCore](https://github.com/AdaCore/VSS).
The fast_float library provides a performance similar to that of the
[fast_double_parser](https://github.com/lemire/fast_double_parser) library but
@ -455,14 +385,6 @@ 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/fast-float.svg)](https://repology.org/project/fast-float/versions)
## References
* Daniel Lemire, [Number Parsing at a Gigabyte per
@ -533,7 +455,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.1.0
GIT_TAG tags/v8.0.2
GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(fast_float)
@ -549,7 +471,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.1.0)
GIT_TAG v8.0.2)
```
## Using as single header
@ -561,7 +483,7 @@ if desired as described in the command line help.
You may directly download automatically generated single-header files:
<https://github.com/fastfloat/fast_float/releases/download/v8.1.0/fast_float.h>
<https://github.com/fastfloat/fast_float/releases/download/v8.0.2/fast_float.h>
## Benchmarking
@ -600,7 +522,6 @@ 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`).
@ -615,11 +536,6 @@ long digits.
The library includes code adapted from Google Wuffs (written by Nigel Tao) which
was originally published under the Apache 2.0 license.
## Stars
[![Star History Chart](https://api.star-history.com/svg?repos=fastfloat/fast_float&type=Date)](https://www.star-history.com/#fastfloat/fast_float&Date)
## License
<sup>

View File

@ -1,4 +0,0 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR riscv64)
set(CMAKE_CROSSCOMPILING_EMULATOR "qemu-riscv64-static")

View File

@ -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 call if is_integer, since we use the
// We don't need to check 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 integer
if (i >= minimal_nineteen_digit_integer) { // We have a big integers
exponent = end_of_integer_part - p + exp_number;
} else { // We have a value with a fractional component.
p = answer.fraction.ptr;

View File

@ -38,8 +38,11 @@ constexpr static uint64_t powers_of_ten_uint64[] = {1UL,
// this algorithm is not even close to optimized, but it has no practical
// effect on performance: in order to have a faster algorithm, we'd need
// to slow down performance for faster algorithms, and this is still fast.
template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t
scientific_exponent(uint64_t mantissa, int32_t exponent) noexcept {
scientific_exponent(parsed_number_string_t<UC> &num) noexcept {
uint64_t mantissa = num.mantissa;
int32_t exponent = int32_t(num.exponent);
while (mantissa >= 10000) {
mantissa /= 10000;
exponent += 4;
@ -395,7 +398,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp)));
}
// compare digits, and use it to direct rounding
// compare digits, and use it to director rounding
int ord = real_digits.compare(theor_digits);
adjusted_mantissa answer = am;
round<T>(answer, [ord](adjusted_mantissa &a, int32_t shift) {
@ -416,7 +419,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
return answer;
}
// parse the significant digits as a big integer to unambiguously round
// parse the significant digits as a big integer to unambiguously round the
// the significant digits. here, we are trying to determine how to round
// an extended float representation close to `b+h`, halfway between `b`
// (the float rounded-down) and `b+u`, the next positive float. this
@ -435,8 +438,7 @@ digit_comp(parsed_number_string_t<UC> &num, adjusted_mantissa am) noexcept {
// remove the invalid exponent bias
am.power2 -= invalid_am_bias;
int32_t sci_exp =
scientific_exponent(num.mantissa, static_cast<int32_t>(num.exponent));
int32_t sci_exp = scientific_exponent(num);
size_t max_digits = binary_format<T>::max_digits();
size_t digits = 0;
bigint bigmant;

View File

@ -45,38 +45,6 @@ FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
from_chars_advanced(UC const *first, UC const *last, T &value,
parse_options_t<UC> 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;
/**
* This function is a template overload of `integer_times_pow10()`
* that returns a floating-point value of type `T` that is one of
* supported floating-point types (e.g. `double`, `float`).
*/
template <typename T>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept;
template <typename T>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept;
/**
* from_chars for integer types.
*/

View File

@ -16,8 +16,8 @@
#include "constexpr_feature_detect.h"
#define FASTFLOAT_VERSION_MAJOR 8
#define FASTFLOAT_VERSION_MINOR 1
#define FASTFLOAT_VERSION_PATCH 0
#define FASTFLOAT_VERSION_MINOR 0
#define FASTFLOAT_VERSION_PATCH 2
#define FASTFLOAT_STRINGIZE_IMPL(x) #x
#define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x)
@ -58,11 +58,6 @@ enum class chars_format : uint64_t {
template <typename UC> 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<char>;
@ -93,12 +88,11 @@ using parse_options = parse_options_t<char>;
defined(__MINGW64__) || defined(__s390x__) || \
(defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \
defined(__PPC64LE__)) || \
defined(__loongarch64) || (defined(__riscv) && __riscv_xlen == 64))
defined(__loongarch64))
#define FASTFLOAT_64BIT 1
#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
defined(__arm__) || defined(_M_ARM) || defined(__ppc__) || \
defined(__MINGW32__) || defined(__EMSCRIPTEN__) || \
(defined(__riscv) && __riscv_xlen == 32))
defined(__MINGW32__) || defined(__EMSCRIPTEN__))
#define FASTFLOAT_32BIT 1
#else
// Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow.
@ -406,8 +400,8 @@ full_multiplication(uint64_t a, uint64_t b) {
// But MinGW on ARM64 doesn't have native support for 64-bit multiplications
answer.high = __umulh(a, b);
answer.low = a * b;
#elif defined(FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__) && \
!defined(_M_ARM64) && !defined(__GNUC__))
#elif defined(FASTFLOAT_32BIT) || \
(defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64))
answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64
#elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__)
__uint128_t r = ((__uint128_t)a) * b;
@ -1132,12 +1126,7 @@ template <typename T> constexpr uint64_t int_luts<T>::min_safe_u64[];
template <typename UC>
fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) {
// wchar_t and char can be signed, so we need to be careful.
using UnsignedUC = typename std::make_unsigned<UC>::type;
return int_luts<>::chdigit[static_cast<unsigned char>(
static_cast<UnsignedUC>(c) &
static_cast<UnsignedUC>(
-((static_cast<UnsignedUC>(c) & ~0xFFull) == 0)))];
return int_luts<>::chdigit[static_cast<unsigned char>(c)];
}
fastfloat_really_inline constexpr size_t max_digits_u64(int base) {
@ -1166,9 +1155,6 @@ static_assert(std::is_same<equiv_uint_t<std::float64_t>, uint64_t>::value,
static_assert(
std::numeric_limits<std::float64_t>::is_iec559,
"std::float64_t must fulfill the requirements of IEC 559 (IEEE 754)");
template <>
struct binary_format<std::float64_t> : public binary_format<double> {};
#endif // __STDCPP_FLOAT64_T__
#ifdef __STDCPP_FLOAT32_T__
@ -1177,9 +1163,6 @@ static_assert(std::is_same<equiv_uint_t<std::float32_t>, uint32_t>::value,
static_assert(
std::numeric_limits<std::float32_t>::is_iec559,
"std::float32_t must fulfill the requirements of IEC 559 (IEEE 754)");
template <>
struct binary_format<std::float32_t> : public binary_format<float> {};
#endif // __STDCPP_FLOAT32_T__
#ifdef __STDCPP_FLOAT16_T__
@ -1251,6 +1234,7 @@ constexpr chars_format adjust_for_feature_macros(chars_format fmt) {
;
}
} // namespace detail
} // namespace fast_float
#endif

View File

@ -188,17 +188,32 @@ from_chars(UC const *first, UC const *last, T &value,
parse_options_t<UC>(fmt));
}
template <typename T>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
clinger_fast_path_impl(uint64_t mantissa, int64_t exponent, bool is_negative,
T &value) noexcept {
/**
* 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 <typename T, typename UC>
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
static_assert(is_supported_float_type<T>::value,
"only some floating-point types are supported");
static_assert(is_supported_char_type<UC>::value,
"only char, wchar_t, char16_t and char32_t are supported");
from_chars_result_t<UC> answer;
answer.ec = std::errc(); // be optimistic
answer.ptr = pns.lastmatch;
// 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<T>::min_exponent_fast_path() <= exponent &&
exponent <= binary_format<T>::max_exponent_fast_path()) {
if (binary_format<T>::min_exponent_fast_path() <= pns.exponent &&
pns.exponent <= binary_format<T>::max_exponent_fast_path() &&
!pns.too_many_digits) {
// Unfortunately, the conventional Clinger's fast path is only possible
// when the system rounds to the nearest float.
//
@ -209,64 +224,41 @@ clinger_fast_path_impl(uint64_t mantissa, int64_t exponent, bool is_negative,
if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
// We have that fegetround() == FE_TONEAREST.
// Next is Clinger's fast path.
if (mantissa <= binary_format<T>::max_mantissa_fast_path()) {
value = T(mantissa);
if (exponent < 0) {
value = value / binary_format<T>::exact_power_of_ten(-exponent);
if (pns.mantissa <= binary_format<T>::max_mantissa_fast_path()) {
value = T(pns.mantissa);
if (pns.exponent < 0) {
value = value / binary_format<T>::exact_power_of_ten(-pns.exponent);
} else {
value = value * binary_format<T>::exact_power_of_ten(exponent);
value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
}
if (is_negative) {
if (pns.negative) {
value = -value;
}
return true;
return answer;
}
} 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 (exponent >= 0 &&
mantissa <= binary_format<T>::max_mantissa_fast_path(exponent)) {
if (pns.exponent >= 0 &&
pns.mantissa <=
binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
#if defined(__clang__) || defined(FASTFLOAT_32BIT)
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
if (mantissa == 0) {
value = is_negative ? T(-0.) : T(0.);
return true;
if (pns.mantissa == 0) {
value = pns.negative ? T(-0.) : T(0.);
return answer;
}
#endif
value = T(mantissa) * binary_format<T>::exact_power_of_ten(exponent);
if (is_negative) {
value = T(pns.mantissa) *
binary_format<T>::exact_power_of_ten(pns.exponent);
if (pns.negative) {
value = -value;
}
return true;
return answer;
}
}
}
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 <typename T, typename UC>
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
static_assert(is_supported_float_type<T>::value,
"only some floating-point types are supported");
static_assert(is_supported_char_type<UC>::value,
"only char, wchar_t, char16_t and char32_t are supported");
from_chars_result_t<UC> 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<binary_format<T>>(pns.exponent, pns.mantissa);
if (pns.too_many_digits && am.power2 >= 0) {
@ -344,84 +336,6 @@ from_chars(UC const *first, UC const *last, T &value, int base) noexcept {
return from_chars_advanced(first, last, value, options);
}
template <typename T>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept {
T value;
if (clinger_fast_path_impl(mantissa, decimal_exponent, false, value))
return value;
adjusted_mantissa am =
compute_float<binary_format<T>>(decimal_exponent, mantissa);
to_float(false, am, value);
return value;
}
template <typename T>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept {
const bool is_negative = mantissa < 0;
const uint64_t m = static_cast<uint64_t>(is_negative ? -mantissa : mantissa);
T value;
if (clinger_fast_path_impl(m, decimal_exponent, is_negative, value))
return value;
adjusted_mantissa am = compute_float<binary_format<T>>(decimal_exponent, m);
to_float(is_negative, am, value);
return value;
}
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<double>(mantissa, decimal_exponent);
}
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<double>(mantissa, decimal_exponent);
}
// the following overloads are here to avoid surprising ambiguity for int,
// unsigned, etc.
template <typename T, typename Int>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value &&
std::is_integral<Int>::value &&
!std::is_signed<Int>::value,
T>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<T>(static_cast<uint64_t>(mantissa),
decimal_exponent);
}
template <typename T, typename Int>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value &&
std::is_integral<Int>::value &&
std::is_signed<Int>::value,
T>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<T>(static_cast<int64_t>(mantissa),
decimal_exponent);
}
template <typename Int>
FASTFLOAT_CONSTEXPR20 typename std::enable_if<
std::is_integral<Int>::value && !std::is_signed<Int>::value, double>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10(static_cast<uint64_t>(mantissa), decimal_exponent);
}
template <typename Int>
FASTFLOAT_CONSTEXPR20 typename std::enable_if<
std::is_integral<Int>::value && std::is_signed<Int>::value, double>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10(static_cast<int64_t>(mantissa), decimal_exponent);
}
template <typename T, typename UC>
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
from_chars_int_advanced(UC const *first, UC const *last, T &value,

View File

@ -9,7 +9,8 @@ option(FASTFLOAT_SUPPLEMENTAL_TESTS "Run supplemental tests" ON)
if (NOT SYSTEM_DOCTEST)
FetchContent_Declare(doctest
GIT_REPOSITORY https://github.com/lemire/doctest.git)
GIT_REPOSITORY https://github.com/onqtam/doctest.git
GIT_TAG v2.4.11)
else ()
find_package(doctest REQUIRED)
endif()
@ -22,15 +23,24 @@ endif()
# FetchContent_MakeAvailable() was only introduced in 3.14
# https://cmake.org/cmake/help/v3.14/release/3.14.html#modules
# FetchContent_MakeAvailable(doctest)
if (NOT SYSTEM_DOCTEST)
FetchContent_MakeAvailable(doctest)
FetchContent_GetProperties(doctest)
if(NOT doctest_POPULATED)
FetchContent_Populate(doctest)
add_subdirectory(${doctest_SOURCE_DIR} ${doctest_BINARY_DIR})
endif()
endif()
add_library(supplemental-data INTERFACE)
if (FASTFLOAT_SUPPLEMENTAL_TESTS)
message(STATUS "Supplemental tests enabled. Retrieving test files.")
FetchContent_MakeAvailable(supplemental_test_files)
message(STATUS "Supplemental test files retrieved.")
FetchContent_GetProperties(supplemental_test_files)
if(NOT supplemental_test_files_POPULATED)
message(STATUS "Supplemental tests enabled. Retrieving test files.")
FetchContent_Populate(supplemental_test_files)
message(STATUS "Supplemental test files retrieved.")
add_subdirectory(${supplemental_test_files_SOURCE_DIR} ${supplemental_test_files_BINARY_DIR})
endif()
target_compile_definitions(supplemental-data INTERFACE SUPPLEMENTAL_TEST_DATA_DIR="${supplemental_test_files_BINARY_DIR}/data")
endif()
@ -61,7 +71,6 @@ fast_float_add_cpp_test(wide_char_test)
fast_float_add_cpp_test(supported_chars_test)
fast_float_add_cpp_test(example_test)
fast_float_add_cpp_test(example_comma_test)
fast_float_add_cpp_test(example_integer_times_pow10)
fast_float_add_cpp_test(basictest)
option(FASTFLOAT_CONSTEXPR_TESTS "Require constexpr tests (build will fail if the compiler won't support it)" OFF)
if (FASTFLOAT_CONSTEXPR_TESTS)
@ -73,7 +82,7 @@ endif()
if (FASTFLOAT_SUPPLEMENTAL_TESTS)
target_compile_definitions(basictest PRIVATE FASTFLOAT_SUPPLEMENTAL_TESTS)
endif()
fast_float_add_cpp_test(p2497)
fast_float_add_cpp_test(long_test)
fast_float_add_cpp_test(powersoffive_hardround)
fast_float_add_cpp_test(string_test)

View File

@ -1134,23 +1134,6 @@ TEST_CASE("double.inf") {
std::errc::result_out_of_range);
verify("1.9e308", std::numeric_limits<double>::infinity(),
std::errc::result_out_of_range);
// DBL_MAX + 0.00000000000000001e308
verify("1.79769313486231581e308", std::numeric_limits<double>::infinity(),
std::errc::result_out_of_range);
// DBL_MAX + 0.0000000000000001e308
verify("1.7976931348623159e308", std::numeric_limits<double>::infinity(),
std::errc::result_out_of_range);
// ( (2 - 0.5*2^(52)) * 2^1023 ) smallest number that overflows to infinity
verify("179769313486231580793728971405303415079934132710037826936173778980444"
"968292764750946649017977587207096330286416692887910946555547851940402"
"630657488671505820681908902000708383676273854845817711531764475730270"
"069855571366959622842914819860834936475292719074168444365510704342711"
"559699508093042880177904174497792",
std::numeric_limits<double>::infinity(),
std::errc::result_out_of_range);
}
TEST_CASE("double.general") {
@ -1160,13 +1143,6 @@ TEST_CASE("double.general") {
verify("-22250738585072012e-324",
-0x1p-1022); /* limit between normal and subnormal*/
verify("-1e-999", -0.0, std::errc::result_out_of_range);
// DBL_TRUE_MIN / 2
verify("2.4703282292062327e-324", 0.0, std::errc::result_out_of_range);
// DBL_TRUE_MIN / 2 + 0.0000000000000001e-324
verify("2.4703282292062328e-324", 0x0.0000000000001p-1022);
verify("-2.2222222222223e-322", -0x1.68p-1069);
verify("9007199254740993.0", 0x1p+53);
verify("860228122.6654514319E+90", 0x1.92bb20990715fp+328);
@ -1342,15 +1318,6 @@ TEST_CASE("double.general") {
std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
verify("-2240084132271013504.131248280843119943687942846658579428",
-0x1.f1660a65b00bfp+60);
// ( (2 - 0.5*2^(52)) * 2^1023 - 1 ) largest 309 decimal digit number
// that rounds to DBL_MAX
verify("179769313486231580793728971405303415079934132710037826936173778980444"
"968292764750946649017977587207096330286416692887910946555547851940402"
"630657488671505820681908902000708383676273854845817711531764475730270"
"069855571366959622842914819860834936475292719074168444365510704342711"
"559699508093042880177904174497791",
std::numeric_limits<double>::max());
}
TEST_CASE("double.decimal_point") {
@ -1525,35 +1492,14 @@ TEST_CASE("float.inf") {
std::errc::result_out_of_range);
verify("3.5028234666e38", std::numeric_limits<float>::infinity(),
std::errc::result_out_of_range);
// FLT_MAX + 0.00000007e38
verify("3.40282357e38", std::numeric_limits<float>::infinity(),
std::errc::result_out_of_range);
// FLT_MAX + 0.0000001e38
verify("3.4028236e38", std::numeric_limits<float>::infinity(),
std::errc::result_out_of_range);
// ( (2 - 0.5*2^(-23)) * 2^127 ) smallest number that overflows to infinity
verify("340282356779733661637539395458142568448",
std::numeric_limits<float>::infinity(),
std::errc::result_out_of_range);
}
TEST_CASE("float.general") {
// FLT_TRUE_MIN / 2
verify("0.7006492e-45", 0.f, std::errc::result_out_of_range);
// FLT_TRUE_MIN / 2 + 0.0000001e-45
verify("0.7006493e-45", 0x1p-149f);
// max
verify("340282346638528859811704183484516925440", 0x1.fffffep+127f);
// -max
verify("-340282346638528859811704183484516925440", -0x1.fffffep+127f);
// ( (2 - 0.5*2^(-23)) * 2^127 - 1 ) largest 39 decimal digits number
// that rounds to FLT_MAX
verify("340282356779733661637539395458142568447",
std::numeric_limits<float>::max());
verify("-1e-999", -0.0f, std::errc::result_out_of_range);
verify("1."
"175494140627517859246175898662808184331245864732796240031385942718174"
@ -2124,317 +2070,3 @@ TEST_CASE("bfloat16.general") {
// 0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875bf16);
}
#endif
template <typename Int, typename T, typename U>
void verify_integer_times_pow10_result(Int mantissa, int decimal_exponent,
T actual, U expected) {
static_assert(std::is_same<T, U>::value,
"expected and actual types must match");
INFO("m * 10^e=" << mantissa << " * 10^" << decimal_exponent
<< "\n"
" expected="
<< fHexAndDec(expected) << "\n"
<< " ..actual=" << fHexAndDec(actual) << "\n"
<< " expected mantissa="
<< iHexAndDec(get_mantissa(expected)) << "\n"
<< " ..actual mantissa=" << iHexAndDec(get_mantissa(actual))
<< "\n");
CHECK_EQ(actual, expected);
}
template <typename T, typename Int>
T calculate_integer_times_pow10_expected_result(Int mantissa,
int decimal_exponent) {
std::string constructed_string =
std::to_string(mantissa) + "e" + std::to_string(decimal_exponent);
T expected_result;
const auto result = fast_float::from_chars(
constructed_string.data(),
constructed_string.data() + constructed_string.size(), expected_result);
if (result.ec != std::errc())
INFO("Failed to parse: " << constructed_string);
return expected_result;
}
template <typename Int>
void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent,
double expected) {
static_assert(std::is_integral<Int>::value);
// the "default" overload
const double actual =
fast_float::integer_times_pow10(mantissa, decimal_exponent);
verify_integer_times_pow10_result(mantissa, decimal_exponent, actual,
expected);
}
template <typename Int>
void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent) {
static_assert(std::is_integral<Int>::value);
const auto expected_result =
calculate_integer_times_pow10_expected_result<double>(mantissa,
decimal_exponent);
verify_integer_times_pow10_dflt(mantissa, decimal_exponent, expected_result);
}
template <typename T, typename Int>
void verify_integer_times_pow10(Int mantissa, int decimal_exponent,
T expected) {
static_assert(std::is_floating_point<T>::value);
static_assert(std::is_integral<Int>::value);
// explicit specialization
const auto actual =
fast_float::integer_times_pow10<T>(mantissa, decimal_exponent);
verify_integer_times_pow10_result(mantissa, decimal_exponent, actual,
expected);
}
template <typename T, typename Int>
void verify_integer_times_pow10(Int mantissa, int decimal_exponent) {
static_assert(std::is_floating_point<T>::value);
static_assert(std::is_integral<Int>::value);
const auto expected_result = calculate_integer_times_pow10_expected_result<T>(
mantissa, decimal_exponent);
verify_integer_times_pow10(mantissa, decimal_exponent, expected_result);
}
namespace all_supported_types {
template <typename Int>
void verify_integer_times_pow10(Int mantissa, int decimal_exponent) {
static_assert(std::is_integral<Int>::value);
// verify the "default" overload
verify_integer_times_pow10_dflt(mantissa, decimal_exponent);
// verify explicit specializations
::verify_integer_times_pow10<double>(mantissa, decimal_exponent);
::verify_integer_times_pow10<float>(mantissa, decimal_exponent);
#if defined(__STDCPP_FLOAT64_T__)
::verify_integer_times_pow10<std::float64_t>(mantissa, decimal_exponent);
#endif
#if defined(__STDCPP_FLOAT32_T__)
::verify_integer_times_pow10<std::float32_t>(mantissa, decimal_exponent);
#endif
#if defined(__STDCPP_FLOAT16_T__)
::verify_integer_times_pow10<std::float16_t>(mantissa, decimal_exponent);
#endif
#if defined(__STDCPP_BFLOAT16_T__)
::verify_integer_times_pow10<std::bfloat16_t>(mantissa, decimal_exponent);
#endif
}
} // namespace all_supported_types
TEST_CASE("integer_times_pow10") {
/* explicitly verifying API with different types of integers */
// double (the "default" overload)
verify_integer_times_pow10_dflt<int8_t>(31, -1, 3.1);
verify_integer_times_pow10_dflt<int8_t>(-31, -1, -3.1);
verify_integer_times_pow10_dflt<uint8_t>(31, -1, 3.1);
verify_integer_times_pow10_dflt<int16_t>(31415, -4, 3.1415);
verify_integer_times_pow10_dflt<int16_t>(-31415, -4, -3.1415);
verify_integer_times_pow10_dflt<uint16_t>(31415, -4, 3.1415);
verify_integer_times_pow10_dflt<int32_t>(314159265, -8, 3.14159265);
verify_integer_times_pow10_dflt<int32_t>(-314159265, -8, -3.14159265);
verify_integer_times_pow10_dflt<uint32_t>(3141592653, -9, 3.141592653);
verify_integer_times_pow10_dflt<long>(314159265, -8, 3.14159265);
verify_integer_times_pow10_dflt<long>(-314159265, -8, -3.14159265);
verify_integer_times_pow10_dflt<unsigned long>(3141592653, -9, 3.141592653);
verify_integer_times_pow10_dflt<int64_t>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10_dflt<int64_t>(-3141592653589793238, -18,
-3.141592653589793238);
verify_integer_times_pow10_dflt<uint64_t>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10_dflt<long long>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10_dflt<long long>(-3141592653589793238, -18,
-3.141592653589793238);
verify_integer_times_pow10_dflt<unsigned long long>(3141592653589793238, -18,
3.141592653589793238);
// double (explicit specialization)
verify_integer_times_pow10<double, int8_t>(31, -1, 3.1);
verify_integer_times_pow10<double, int8_t>(-31, -1, -3.1);
verify_integer_times_pow10<double, uint8_t>(31, -1, 3.1);
verify_integer_times_pow10<double, int16_t>(31415, -4, 3.1415);
verify_integer_times_pow10<double, int16_t>(-31415, -4, -3.1415);
verify_integer_times_pow10<double, uint16_t>(31415, -4, 3.1415);
verify_integer_times_pow10<double, int32_t>(314159265, -8, 3.14159265);
verify_integer_times_pow10<double, int32_t>(-314159265, -8, -3.14159265);
verify_integer_times_pow10<double, uint32_t>(3141592653, -9, 3.141592653);
verify_integer_times_pow10<double, long>(314159265, -8, 3.14159265);
verify_integer_times_pow10<double, long>(-314159265, -8, -3.14159265);
verify_integer_times_pow10<double, unsigned long>(3141592653, -9,
3.141592653);
verify_integer_times_pow10<double, int64_t>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10<double, int64_t>(-3141592653589793238, -18,
-3.141592653589793238);
verify_integer_times_pow10<double, uint64_t>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10<double, long long>(3141592653589793238, -18,
3.141592653589793238);
verify_integer_times_pow10<double, long long>(-3141592653589793238, -18,
-3.141592653589793238);
verify_integer_times_pow10<double, unsigned long long>(
3141592653589793238, -18, 3.141592653589793238);
// float (explicit specialization)
verify_integer_times_pow10<float, int8_t>(31, -1, 3.1f);
verify_integer_times_pow10<float, int8_t>(-31, -1, -3.1f);
verify_integer_times_pow10<float, uint8_t>(31, -1, 3.1f);
verify_integer_times_pow10<float, int16_t>(31415, -4, 3.1415f);
verify_integer_times_pow10<float, int16_t>(-31415, -4, -3.1415f);
verify_integer_times_pow10<float, uint16_t>(31415, -4, 3.1415f);
verify_integer_times_pow10<float, int32_t>(314159265, -8, 3.14159265f);
verify_integer_times_pow10<float, int32_t>(-314159265, -8, -3.14159265f);
verify_integer_times_pow10<float, uint32_t>(3141592653, -9, 3.14159265f);
verify_integer_times_pow10<float, long>(314159265, -8, 3.14159265f);
verify_integer_times_pow10<float, long>(-314159265, -8, -3.14159265f);
verify_integer_times_pow10<float, unsigned long>(3141592653, -9, 3.14159265f);
verify_integer_times_pow10<float, int64_t>(3141592653589793238, -18,
3.141592653589793238f);
verify_integer_times_pow10<float, int64_t>(-3141592653589793238, -18,
-3.141592653589793238f);
verify_integer_times_pow10<float, uint64_t>(3141592653589793238, -18,
3.141592653589793238f);
verify_integer_times_pow10<float, long long>(3141592653589793238, -18,
3.141592653589793238f);
verify_integer_times_pow10<float, long long>(-3141592653589793238, -18,
-3.141592653589793238f);
verify_integer_times_pow10<float, unsigned long long>(
3141592653589793238, -18, 3.141592653589793238f);
for (int mode : {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, FE_TONEAREST}) {
fesetround(mode);
INFO("fesetround(): " << std::string{round_name(mode)});
struct Guard {
~Guard() { fesetround(FE_TONEAREST); }
} guard;
namespace all = all_supported_types;
all::verify_integer_times_pow10(0, 0);
all::verify_integer_times_pow10(1, 0);
all::verify_integer_times_pow10(0, 1);
all::verify_integer_times_pow10(1, 1);
all::verify_integer_times_pow10(-1, 0);
all::verify_integer_times_pow10(0, -1);
all::verify_integer_times_pow10(-1, -1);
all::verify_integer_times_pow10(-1, 1);
all::verify_integer_times_pow10(1, -1);
/* denormal min */
verify_integer_times_pow10_dflt(49406564584124654, -340,
std::numeric_limits<double>::denorm_min());
verify_integer_times_pow10<double>(
49406564584124654, -340, std::numeric_limits<double>::denorm_min());
verify_integer_times_pow10<float>(14012984, -52,
std::numeric_limits<float>::denorm_min());
/* normal min */
verify_integer_times_pow10_dflt(22250738585072014, -324,
std::numeric_limits<double>::min());
verify_integer_times_pow10<double>(22250738585072014, -324,
std::numeric_limits<double>::min());
verify_integer_times_pow10<float>(11754944, -45,
std::numeric_limits<float>::min());
/* max */
verify_integer_times_pow10_dflt(17976931348623158, 292,
std::numeric_limits<double>::max());
verify_integer_times_pow10<double>(17976931348623158, 292,
std::numeric_limits<double>::max());
verify_integer_times_pow10<float>(34028235, 31,
std::numeric_limits<float>::max());
/* underflow */
// (DBL_TRUE_MIN / 2) underflows to 0
verify_integer_times_pow10_dflt(49406564584124654 / 2, -340, 0.);
verify_integer_times_pow10<double>(49406564584124654 / 2, -340, 0.);
// (FLT_TRUE_MIN / 2) underflows to 0
verify_integer_times_pow10<float>(14012984 / 2, -52, 0.f);
/* rounding to denormal min */
// (DBL_TRUE_MIN / 2 + 0.0000000000000001e-324) rounds to DBL_TRUE_MIN
verify_integer_times_pow10_dflt(49406564584124654 / 2 + 1, -340,
std::numeric_limits<double>::denorm_min());
verify_integer_times_pow10<double>(
49406564584124654 / 2 + 1, -340,
std::numeric_limits<double>::denorm_min());
// (FLT_TRUE_MIN / 2 + 0.0000001e-45) rounds to FLT_TRUE_MIN
verify_integer_times_pow10<float>(14012984 / 2 + 1, -52,
std::numeric_limits<float>::denorm_min());
/* overflow */
// (DBL_MAX + 0.0000000000000001e308) overflows to infinity
verify_integer_times_pow10_dflt(17976931348623158 + 1, 292,
std::numeric_limits<double>::infinity());
verify_integer_times_pow10<double>(17976931348623158 + 1, 292,
std::numeric_limits<double>::infinity());
// (DBL_MAX + 0.00000000000000001e308) overflows to infinity
verify_integer_times_pow10_dflt(179769313486231580 + 1, 291,
std::numeric_limits<double>::infinity());
verify_integer_times_pow10<double>(179769313486231580 + 1, 291,
std::numeric_limits<double>::infinity());
// (FLT_MAX + 0.0000001e38) overflows to infinity
verify_integer_times_pow10<float>(34028235 + 1, 31,
std::numeric_limits<float>::infinity());
// (FLT_MAX + 0.00000007e38) overflows to infinity
verify_integer_times_pow10<float>(340282350 + 7, 30,
std::numeric_limits<float>::infinity());
// loosely verifying correct rounding of 1 to 64 bits
// worth of significant digits
all::verify_integer_times_pow10(1, 42);
all::verify_integer_times_pow10(1, -42);
all::verify_integer_times_pow10(12, 42);
all::verify_integer_times_pow10(12, -42);
all::verify_integer_times_pow10(123, 42);
all::verify_integer_times_pow10(123, -42);
all::verify_integer_times_pow10(1234, 42);
all::verify_integer_times_pow10(1234, -42);
all::verify_integer_times_pow10(12345, 42);
all::verify_integer_times_pow10(12345, -42);
all::verify_integer_times_pow10(123456, 42);
all::verify_integer_times_pow10(123456, -42);
all::verify_integer_times_pow10(1234567, 42);
all::verify_integer_times_pow10(1234567, -42);
all::verify_integer_times_pow10(12345678, 42);
all::verify_integer_times_pow10(12345678, -42);
all::verify_integer_times_pow10(123456789, 42);
all::verify_integer_times_pow10(1234567890, 42);
all::verify_integer_times_pow10(1234567890, -42);
all::verify_integer_times_pow10(12345678901, 42);
all::verify_integer_times_pow10(12345678901, -42);
all::verify_integer_times_pow10(123456789012, 42);
all::verify_integer_times_pow10(123456789012, -42);
all::verify_integer_times_pow10(1234567890123, 42);
all::verify_integer_times_pow10(1234567890123, -42);
all::verify_integer_times_pow10(12345678901234, 42);
all::verify_integer_times_pow10(12345678901234, -42);
all::verify_integer_times_pow10(123456789012345, 42);
all::verify_integer_times_pow10(123456789012345, -42);
all::verify_integer_times_pow10(1234567890123456, 42);
all::verify_integer_times_pow10(1234567890123456, -42);
all::verify_integer_times_pow10(12345678901234567, 42);
all::verify_integer_times_pow10(12345678901234567, -42);
all::verify_integer_times_pow10(123456789012345678, 42);
all::verify_integer_times_pow10(123456789012345678, -42);
all::verify_integer_times_pow10(1234567890123456789, 42);
all::verify_integer_times_pow10(1234567890123456789, -42);
all::verify_integer_times_pow10(12345678901234567890ull, 42);
all::verify_integer_times_pow10(12345678901234567890ull, -42);
all::verify_integer_times_pow10(std::numeric_limits<int64_t>::max(), 42);
all::verify_integer_times_pow10(std::numeric_limits<int64_t>::max(), -42);
all::verify_integer_times_pow10(std::numeric_limits<uint64_t>::max(), 42);
all::verify_integer_times_pow10(std::numeric_limits<uint64_t>::max(), -42);
}
}

View File

@ -1,36 +0,0 @@
#include "fast_float/fast_float.h"
#include <iostream>
void default_overload() {
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";
}
void double_specialization() {
const uint64_t W = 12345678901234567;
const int Q = 23;
const double result = fast_float::integer_times_pow10<double>(W, Q);
std::cout.precision(17);
std::cout << "double: " << W << " * 10^" << Q << " = " << result << " ("
<< (result == 12345678901234567e23 ? "==" : "!=") << "expected)\n";
}
void float_specialization() {
const uint64_t W = 12345678;
const int Q = 23;
const float result = fast_float::integer_times_pow10<float>(W, Q);
std::cout.precision(9);
std::cout << "float: " << W << " * 10^" << Q << " = " << result << " ("
<< (result == 12345678e23f ? "==" : "!=") << "expected)\n";
}
int main() {
default_overload();
double_specialization();
float_specialization();
}

View File

@ -831,275 +831,6 @@ int main() {
return EXIT_FAILURE;
}
}
// dont parse UTF-16 code units of emojis as int if low byte is ascii digit
{
const std::u16string emojis[] = {
u"", u"", u"", u"☸️", u"", u"☹️", u"", u"✳️",
u"", u"✴️", u"", u"⤴️", u"", u"⤵️", u"", u"〰️",
};
bool failed = false;
auto array_size = sizeof(emojis) / sizeof(emojis[0]);
for (size_t i = 0; i < array_size; i++) {
auto e = emojis[i];
int foo;
auto answer = fast_float::from_chars(e.data(), e.data() + e.size(), foo);
if (answer.ec == std::errc()) {
failed = true;
std::cerr << "Incorrectly parsed emoji #" << i << " as integer " << foo
<< "." << std::endl;
}
}
if (failed) {
return EXIT_FAILURE;
}
}
// dont parse UTF-32 code points of emojis as int if low byte is ascii digit
{
const std::u32string emojis[] = {
U"",
U"",
U"",
U"☸️",
U"",
U"☹️",
U"",
U"✳️",
U"",
U"✴️",
U"",
U"⤴️",
U"",
U"⤵️",
U"",
U"〰️",
U"🈲",
U"🈳",
U"🈴",
U"🈵",
U"🈶",
U"🈷",
U"🈷️",
U"🈸",
U"🈹",
U"🌰",
U"🌱",
U"🌲",
U"🌳",
U"🌴",
U"🌵",
U"🌶",
U"🌶️",
U"🌷",
U"🌸",
U"🌹",
U"🐰",
U"🐱",
U"🐲",
U"🐳",
U"🐴",
U"🐵",
U"🐶",
U"🐷",
U"🐸",
U"🐹",
U"🔰",
U"🔱",
U"🔲",
U"🔳",
U"🔴",
U"🔵",
U"🔶",
U"🔷",
U"🔸",
U"🔹",
U"😰",
U"😱",
U"😲",
U"😳",
U"😴",
U"😵",
U"😵‍💫",
U"😶",
U"😶‍🌫",
U"😶‍🌫️",
U"😷",
U"😸",
U"😹",
U"🤰",
U"🤰🏻",
U"🤰🏼",
U"🤰🏽",
U"🤰🏾",
U"🤰🏿",
U"🤱",
U"🤱🏻",
U"🤱🏼",
U"🤱🏽",
U"🤱🏾",
U"🤱🏿",
U"🤲",
U"🤲🏻",
U"🤲🏼",
U"🤲🏽",
U"🤲🏾",
U"🤲🏿",
U"🤳",
U"🤳🏻",
U"🤳🏼",
U"🤳🏽",
U"🤳🏾",
U"🤳🏿",
U"🤴",
U"🤴🏻",
U"🤴🏼",
U"🤴🏽",
U"🤴🏾",
U"🤴🏿",
U"🤵",
U"🤵‍♀",
U"🤵‍♀️",
U"🤵‍♂",
U"🤵‍♂️",
U"🤵🏻",
U"🤵🏻‍♀",
U"🤵🏻‍♀️",
U"🤵🏻‍♂",
U"🤵🏻‍♂️",
U"🤵🏼",
U"🤵🏼‍♀",
U"🤵🏼‍♀️",
U"🤵🏼‍♂",
U"🤵🏼‍♂️",
U"🤵🏽",
U"🤵🏽‍♀",
U"🤵🏽‍♀️",
U"🤵🏽‍♂",
U"🤵🏽‍♂️",
U"🤵🏾",
U"🤵🏾‍♀",
U"🤵🏾‍♀️",
U"🤵🏾‍♂",
U"🤵🏾‍♂️",
U"🤵🏿",
U"🤵🏿‍♀",
U"🤵🏿‍♀️",
U"🤵🏿‍♂",
U"🤵🏿‍♂️",
U"🤶",
U"🤶🏻",
U"🤶🏼",
U"🤶🏽",
U"🤶🏾",
U"🤶🏿",
U"🤷",
U"🤷‍♀",
U"🤷‍♀️",
U"🤷‍♂",
U"🤷‍♂️",
U"🤷🏻",
U"🤷🏻‍♀",
U"🤷🏻‍♀️",
U"🤷🏻‍♂",
U"🤷🏻‍♂️",
U"🤷🏼",
U"🤷🏼‍♀",
U"🤷🏼‍♀️",
U"🤷🏼‍♂",
U"🤷🏼‍♂️",
U"🤷🏽",
U"🤷🏽‍♀",
U"🤷🏽‍♀️",
U"🤷🏽‍♂",
U"🤷🏽‍♂️",
U"🤷🏾",
U"🤷🏾‍♀",
U"🤷🏾‍♀️",
U"🤷🏾‍♂",
U"🤷🏾‍♂️",
U"🤷🏿",
U"🤷🏿‍♀",
U"🤷🏿‍♀️",
U"🤷🏿‍♂",
U"🤷🏿‍♂️",
U"🤸",
U"🤸‍♀",
U"🤸‍♀️",
U"🤸‍♂",
U"🤸‍♂️",
U"🤸🏻",
U"🤸🏻‍♀",
U"🤸🏻‍♀️",
U"🤸🏻‍♂",
U"🤸🏻‍♂️",
U"🤸🏼",
U"🤸🏼‍♀",
U"🤸🏼‍♀️",
U"🤸🏼‍♂",
U"🤸🏼‍♂️",
U"🤸🏽",
U"🤸🏽‍♀",
U"🤸🏽‍♀️",
U"🤸🏽‍♂",
U"🤸🏽‍♂️",
U"🤸🏾",
U"🤸🏾‍♀",
U"🤸🏾‍♀️",
U"🤸🏾‍♂",
U"🤸🏾‍♂️",
U"🤸🏿",
U"🤸🏿‍♀",
U"🤸🏿‍♀️",
U"🤸🏿‍♂",
U"🤸🏿‍♂️",
U"🤹",
U"🤹‍♀",
U"🤹‍♀️",
U"🤹‍♂",
U"🤹‍♂️",
U"🤹🏻",
U"🤹🏻‍♀",
U"🤹🏻‍♀️",
U"🤹🏻‍♂",
U"🤹🏻‍♂️",
U"🤹🏼",
U"🤹🏼‍♀",
U"🤹🏼‍♀️",
U"🤹🏼‍♂",
U"🤹🏼‍♂️",
U"🤹🏽",
U"🤹🏽‍♀",
U"🤹🏽‍♀️",
U"🤹🏽‍♂",
U"🤹🏽‍♂️",
U"🤹🏾",
U"🤹🏾‍♀",
U"🤹🏾‍♀️",
U"🤹🏾‍♂",
U"🤹🏾‍♂️",
U"🤹🏿",
U"🤹🏿‍♀",
U"🤹🏿‍♀️",
U"🤹🏿‍♂",
U"🤹🏿‍♂️",
};
bool failed = false;
auto array_size = sizeof(emojis) / sizeof(emojis[0]);
for (size_t i = 0; i < array_size; i++) {
auto e = emojis[i];
int foo;
auto answer = fast_float::from_chars(e.data(), e.data() + e.size(), foo);
if (answer.ec == std::errc()) {
failed = true;
std::cerr << "Incorrectly parsed emoji #" << i << " as integer " << foo
<< "." << std::endl;
}
}
if (failed) {
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
@ -1111,4 +842,4 @@ int main() {
std::cerr << "The test requires C++17." << std::endl;
return EXIT_SUCCESS;
}
#endif
#endif

View File

@ -1,16 +0,0 @@
#include "fast_float/fast_float.h"
#include <iostream>
#include <string>
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;
}