Compare commits

..

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

36 changed files with 142 additions and 1046 deletions

View File

@ -18,7 +18,7 @@ jobs:
- riscv64 - riscv64
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v4
- name: Install latest Alpine Linux for ${{ matrix.arch }} - name: Install latest Alpine Linux for ${{ matrix.arch }}
uses: jirutka/setup-alpine@v1 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] on: [push, pull_request]
jobs: jobs:
ubuntu-build: ubuntu-build:
runs-on: ubuntu-24.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: Compile with amalgamation - name: Compile with amalgamation
run: | run: |
mkdir build && mkdir build &&

View File

@ -20,14 +20,14 @@ jobs:
fuzz-seconds: 300 fuzz-seconds: 300
output-sarif: true output-sarif: true
- name: Upload Crash - name: Upload Crash
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success' if: failure() && steps.build.outcome == 'success'
with: with:
name: artifacts name: artifacts
path: ./out/artifacts path: ./out/artifacts
- name: Upload Sarif - name: Upload Sarif
if: always() && steps.build.outcome == 'success' if: always() && steps.build.outcome == 'success'
uses: github/codeql-action/upload-sarif@v4 uses: github/codeql-action/upload-sarif@v3
with: with:
# Path to SARIF file relative to the root of the repository # Path to SARIF file relative to the root of the repository
sarif_file: cifuzz-sarif/results.sarif 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: lint-and-format:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.1.7 - uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 # v4.1.7
- name: Run clang-format - name: Run clang-format
uses: jidicula/clang-format-action@4726374d1aa3c6aecf132e5197e498979588ebc8 # v4.15.0 uses: jidicula/clang-format-action@d05cecd4a1a5b7e64c22f5a468456135a43f13f6 # v4.14.0
with: with:
clang-format-version: '17' clang-format-version: '17'

View File

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

View File

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

View File

@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: Amalgamate fast_float.h - name: Amalgamate fast_float.h
run: | 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: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v3 - uses: uraimo/run-on-arch-action@v3
name: Test name: Test
id: runcmd id: runcmd

View File

@ -1,14 +1,14 @@
name: Ubuntu 24.04 CI name: Ubuntu 20.04 CI (C++20)
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
ubuntu-build: ubuntu-build:
runs-on: ubuntu-24.04 runs-on: ubuntu-20.04
strategy: strategy:
fail-fast: false fail-fast: false
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: Use cmake - name: Use cmake
run: | run: |
mkdir build && 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: ubuntu-build:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: Install clang++-14 - name: Install clang++-14
run: sudo apt-get install -y clang++-14 run: sudo apt-get install -y clang++-14
- name: Use cmake - name: Use cmake

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,7 +16,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v5 uses: actions/checkout@v4
- name: configure - name: configure
run: >- run: >-
cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} 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.0.1 LANGUAGES CXX)
project(fast_float VERSION 8.1.0 LANGUAGES CXX)
set(FASTFLOAT_CXX_STANDARD 11 CACHE STRING "the C++ standard to use for fastfloat") set(FASTFLOAT_CXX_STANDARD 11 CACHE STRING "the C++ standard to use for fastfloat")
set(CMAKE_CXX_STANDARD ${FASTFLOAT_CXX_STANDARD}) set(CMAKE_CXX_STANDARD ${FASTFLOAT_CXX_STANDARD})
option(FASTFLOAT_TEST "Enable tests" OFF) option(FASTFLOAT_TEST "Enable tests" OFF)

View File

@ -57,7 +57,6 @@ Example:
```C++ ```C++
#include "fast_float/fast_float.h" #include "fast_float/fast_float.h"
#include <iostream> #include <iostream>
#include <string>
int main() { int main() {
std::string input = "3.1416 xyz "; 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: You can parse delimited numbers:
```C++ ```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 ## Users and Related Work
The fast_float library is part of: 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, * 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 * [Chromium](https://github.com/Chromium/Chromium), the engine behind Google
Chrome, Microsoft Edge, and Opera, Chrome, Microsoft Edge, and Opera,
* Boost JSON, MySQL, etc.
* Blender
* [WebKit](https://github.com/WebKit/WebKit), the engine behind Safari (Apple's * [WebKit](https://github.com/WebKit/WebKit), the engine behind Safari (Apple's
web browser), web browser),
* [DuckDB](https://duckdb.org), * [DuckDB](https://duckdb.org),
@ -443,10 +376,7 @@ The fast_float library is part of:
The fastfloat algorithm is part of the [LLVM standard The fastfloat algorithm is part of the [LLVM standard
libraries](https://github.com/llvm/llvm-project/commit/87c016078ad72c46505461e4ff8bfa04819fe7ba). libraries](https://github.com/llvm/llvm-project/commit/87c016078ad72c46505461e4ff8bfa04819fe7ba).
There is a [derived implementation part of There is a [derived implementation part of
AdaCore](https://github.com/AdaCore/VSS). The [SerenityOS operating AdaCore](https://github.com/AdaCore/VSS).
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 The fast_float library provides a performance similar to that of the
[fast_double_parser](https://github.com/lemire/fast_double_parser) library but [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 fast_double_parser library is part of the [Microsoft LightGBM machine-learning
framework](https://github.com/microsoft/LightGBM). 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 ## References
* Daniel Lemire, [Number Parsing at a Gigabyte per * 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( FetchContent_Declare(
fast_float fast_float
GIT_REPOSITORY https://github.com/fastfloat/fast_float.git GIT_REPOSITORY https://github.com/fastfloat/fast_float.git
GIT_TAG tags/v8.1.0 GIT_TAG tags/v8.0.1
GIT_SHALLOW TRUE) GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(fast_float) FetchContent_MakeAvailable(fast_float)
@ -549,7 +471,7 @@ You may also use [CPM](https://github.com/cpm-cmake/CPM.cmake), like so:
CPMAddPackage( CPMAddPackage(
NAME fast_float NAME fast_float
GITHUB_REPOSITORY "fastfloat/fast_float" GITHUB_REPOSITORY "fastfloat/fast_float"
GIT_TAG v8.1.0) GIT_TAG v8.0.1)
``` ```
## Using as single header ## 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: 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.1/fast_float.h>
## Benchmarking ## Benchmarking
@ -600,7 +522,6 @@ cmake --build build
manager](https://conan.io/center/recipes/fast_float). manager](https://conan.io/center/recipes/fast_float).
* It is part of the [brew package * It is part of the [brew package
manager](https://formulae.brew.sh/formula/fast_float). 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 * Some Linux distribution like Fedora include fast_float (e.g., as
`fast_float-devel`). `fast_float-devel`).
@ -615,11 +536,6 @@ long digits.
The library includes code adapted from Google Wuffs (written by Nigel Tao) which The library includes code adapted from Google Wuffs (written by Nigel Tao) which
was originally published under the Apache 2.0 license. 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 ## License
<sup> <sup>

View File

@ -1,7 +1,7 @@
#if defined(__linux__) || (__APPLE__ && __aarch64__) #if defined(__linux__) || (__APPLE__ && __aarch64__)
#define USING_COUNTERS #define USING_COUNTERS
#endif
#include "event_counter.h" #include "event_counter.h"
#endif
#include <algorithm> #include <algorithm>
#include "fast_float/fast_float.h" #include "fast_float/fast_float.h"
#include <chrono> #include <chrono>

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) { if (digit_count > 19) {
answer.too_many_digits = true; answer.too_many_digits = true;
// Let us start again, this time, avoiding overflows. // 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. // pre-tokenized spans from above.
i = 0; i = 0;
p = answer.integer.ptr; 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')); i = i * 10 + uint64_t(*p - UC('0'));
++p; ++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; exponent = end_of_integer_part - p + exp_number;
} else { // We have a value with a fractional component. } else { // We have a value with a fractional component.
p = answer.fraction.ptr; 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 // 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 // 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. // to slow down performance for faster algorithms, and this is still fast.
template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t 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) { while (mantissa >= 10000) {
mantissa /= 10000; mantissa /= 10000;
exponent += 4; exponent += 4;
@ -395,7 +398,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp))); 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); int ord = real_digits.compare(theor_digits);
adjusted_mantissa answer = am; adjusted_mantissa answer = am;
round<T>(answer, [ord](adjusted_mantissa &a, int32_t shift) { round<T>(answer, [ord](adjusted_mantissa &a, int32_t shift) {
@ -416,7 +419,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
return answer; 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 // the significant digits. here, we are trying to determine how to round
// an extended float representation close to `b+h`, halfway between `b` // an extended float representation close to `b+h`, halfway between `b`
// (the float rounded-down) and `b+u`, the next positive float. this // (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 // remove the invalid exponent bias
am.power2 -= invalid_am_bias; am.power2 -= invalid_am_bias;
int32_t sci_exp = int32_t sci_exp = scientific_exponent(num);
scientific_exponent(num.mantissa, static_cast<int32_t>(num.exponent));
size_t max_digits = binary_format<T>::max_digits(); size_t max_digits = binary_format<T>::max_digits();
size_t digits = 0; size_t digits = 0;
bigint bigmant; 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, from_chars_advanced(UC const *first, UC const *last, T &value,
parse_options_t<UC> options) noexcept; 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. * from_chars for integer types.
*/ */

View File

@ -16,8 +16,8 @@
#include "constexpr_feature_detect.h" #include "constexpr_feature_detect.h"
#define FASTFLOAT_VERSION_MAJOR 8 #define FASTFLOAT_VERSION_MAJOR 8
#define FASTFLOAT_VERSION_MINOR 1 #define FASTFLOAT_VERSION_MINOR 0
#define FASTFLOAT_VERSION_PATCH 0 #define FASTFLOAT_VERSION_PATCH 1
#define FASTFLOAT_STRINGIZE_IMPL(x) #x #define FASTFLOAT_STRINGIZE_IMPL(x) #x
#define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(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 { template <typename UC> struct from_chars_result_t {
UC const *ptr; UC const *ptr;
std::errc ec; 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>; 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(__MINGW64__) || defined(__s390x__) || \
(defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \ (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \
defined(__PPC64LE__)) || \ defined(__PPC64LE__)) || \
defined(__loongarch64) || (defined(__riscv) && __riscv_xlen == 64)) defined(__loongarch64))
#define FASTFLOAT_64BIT 1 #define FASTFLOAT_64BIT 1
#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ #elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
defined(__arm__) || defined(_M_ARM) || defined(__ppc__) || \ defined(__arm__) || defined(_M_ARM) || defined(__ppc__) || \
defined(__MINGW32__) || defined(__EMSCRIPTEN__) || \ defined(__MINGW32__) || defined(__EMSCRIPTEN__))
(defined(__riscv) && __riscv_xlen == 32))
#define FASTFLOAT_32BIT 1 #define FASTFLOAT_32BIT 1
#else #else
// Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow. // 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 // But MinGW on ARM64 doesn't have native support for 64-bit multiplications
answer.high = __umulh(a, b); answer.high = __umulh(a, b);
answer.low = a * b; answer.low = a * b;
#elif defined(FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__) && \ #elif defined(FASTFLOAT_32BIT) || \
!defined(_M_ARM64) && !defined(__GNUC__)) (defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64))
answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64 answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64
#elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__) #elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__)
__uint128_t r = ((__uint128_t)a) * b; __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> template <typename UC>
fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) {
// wchar_t and char can be signed, so we need to be careful. return int_luts<>::chdigit[static_cast<unsigned char>(c)];
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)))];
} }
fastfloat_really_inline constexpr size_t max_digits_u64(int base) { 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( static_assert(
std::numeric_limits<std::float64_t>::is_iec559, std::numeric_limits<std::float64_t>::is_iec559,
"std::float64_t must fulfill the requirements of IEC 559 (IEEE 754)"); "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__ #endif // __STDCPP_FLOAT64_T__
#ifdef __STDCPP_FLOAT32_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( static_assert(
std::numeric_limits<std::float32_t>::is_iec559, std::numeric_limits<std::float32_t>::is_iec559,
"std::float32_t must fulfill the requirements of IEC 559 (IEEE 754)"); "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__ #endif // __STDCPP_FLOAT32_T__
#ifdef __STDCPP_FLOAT16_T__ #ifdef __STDCPP_FLOAT16_T__
@ -1251,6 +1234,7 @@ constexpr chars_format adjust_for_feature_macros(chars_format fmt) {
; ;
} }
} // namespace detail } // namespace detail
} // namespace fast_float } // namespace fast_float
#endif #endif

View File

@ -188,17 +188,32 @@ from_chars(UC const *first, UC const *last, T &value,
parse_options_t<UC>(fmt)); parse_options_t<UC>(fmt));
} }
template <typename T> /**
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool * This function overload takes parsed_number_string_t structure that is created
clinger_fast_path_impl(uint64_t mantissa, int64_t exponent, bool is_negative, * and populated either by from_chars_advanced function taking chars range and
T &value) noexcept { * 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 // The implementation of the Clinger's fast path is convoluted because
// we want round-to-nearest in all cases, irrespective of the rounding mode // we want round-to-nearest in all cases, irrespective of the rounding mode
// selected on the thread. // selected on the thread.
// We proceed optimistically, assuming that detail::rounds_to_nearest() // We proceed optimistically, assuming that detail::rounds_to_nearest()
// returns true. // returns true.
if (binary_format<T>::min_exponent_fast_path() <= exponent && if (binary_format<T>::min_exponent_fast_path() <= pns.exponent &&
exponent <= binary_format<T>::max_exponent_fast_path()) { pns.exponent <= binary_format<T>::max_exponent_fast_path() &&
!pns.too_many_digits) {
// Unfortunately, the conventional Clinger's fast path is only possible // Unfortunately, the conventional Clinger's fast path is only possible
// when the system rounds to the nearest float. // 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()) { if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
// We have that fegetround() == FE_TONEAREST. // We have that fegetround() == FE_TONEAREST.
// Next is Clinger's fast path. // Next is Clinger's fast path.
if (mantissa <= binary_format<T>::max_mantissa_fast_path()) { if (pns.mantissa <= binary_format<T>::max_mantissa_fast_path()) {
value = T(mantissa); value = T(pns.mantissa);
if (exponent < 0) { if (pns.exponent < 0) {
value = value / binary_format<T>::exact_power_of_ten(-exponent); value = value / binary_format<T>::exact_power_of_ten(-pns.exponent);
} else { } 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; value = -value;
} }
return true; return answer;
} }
} else { } else {
// We do not have that fegetround() == FE_TONEAREST. // We do not have that fegetround() == FE_TONEAREST.
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's // Next is a modified Clinger's fast path, inspired by Jakub Jelínek's
// proposal // proposal
if (exponent >= 0 && if (pns.exponent >= 0 &&
mantissa <= binary_format<T>::max_mantissa_fast_path(exponent)) { pns.mantissa <=
binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
#if defined(__clang__) || defined(FASTFLOAT_32BIT) #if defined(__clang__) || defined(FASTFLOAT_32BIT)
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
if (mantissa == 0) { if (pns.mantissa == 0) {
value = is_negative ? T(-0.) : T(0.); value = pns.negative ? T(-0.) : T(0.);
return true; return answer;
} }
#endif #endif
value = T(mantissa) * binary_format<T>::exact_power_of_ten(exponent); value = T(pns.mantissa) *
if (is_negative) { binary_format<T>::exact_power_of_ten(pns.exponent);
if (pns.negative) {
value = -value; 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 = adjusted_mantissa am =
compute_float<binary_format<T>>(pns.exponent, pns.mantissa); compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
if (pns.too_many_digits && am.power2 >= 0) { 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); 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> template <typename T, typename UC>
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC> FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
from_chars_int_advanced(UC const *first, UC const *last, T &value, 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) if (NOT SYSTEM_DOCTEST)
FetchContent_Declare(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 () else ()
find_package(doctest REQUIRED) find_package(doctest REQUIRED)
endif() endif()
@ -22,15 +23,24 @@ endif()
# FetchContent_MakeAvailable() was only introduced in 3.14 # FetchContent_MakeAvailable() was only introduced in 3.14
# https://cmake.org/cmake/help/v3.14/release/3.14.html#modules # https://cmake.org/cmake/help/v3.14/release/3.14.html#modules
# FetchContent_MakeAvailable(doctest)
if (NOT SYSTEM_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() endif()
add_library(supplemental-data INTERFACE) add_library(supplemental-data INTERFACE)
if (FASTFLOAT_SUPPLEMENTAL_TESTS) if (FASTFLOAT_SUPPLEMENTAL_TESTS)
message(STATUS "Supplemental tests enabled. Retrieving test files.") FetchContent_GetProperties(supplemental_test_files)
FetchContent_MakeAvailable(supplemental_test_files) if(NOT supplemental_test_files_POPULATED)
message(STATUS "Supplemental test files retrieved.") 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") target_compile_definitions(supplemental-data INTERFACE SUPPLEMENTAL_TEST_DATA_DIR="${supplemental_test_files_BINARY_DIR}/data")
endif() 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(supported_chars_test)
fast_float_add_cpp_test(example_test) fast_float_add_cpp_test(example_test)
fast_float_add_cpp_test(example_comma_test) fast_float_add_cpp_test(example_comma_test)
fast_float_add_cpp_test(example_integer_times_pow10)
fast_float_add_cpp_test(basictest) fast_float_add_cpp_test(basictest)
option(FASTFLOAT_CONSTEXPR_TESTS "Require constexpr tests (build will fail if the compiler won't support it)" OFF) option(FASTFLOAT_CONSTEXPR_TESTS "Require constexpr tests (build will fail if the compiler won't support it)" OFF)
if (FASTFLOAT_CONSTEXPR_TESTS) if (FASTFLOAT_CONSTEXPR_TESTS)
@ -73,7 +82,7 @@ endif()
if (FASTFLOAT_SUPPLEMENTAL_TESTS) if (FASTFLOAT_SUPPLEMENTAL_TESTS)
target_compile_definitions(basictest PRIVATE FASTFLOAT_SUPPLEMENTAL_TESTS) target_compile_definitions(basictest PRIVATE FASTFLOAT_SUPPLEMENTAL_TESTS)
endif() endif()
fast_float_add_cpp_test(p2497)
fast_float_add_cpp_test(long_test) fast_float_add_cpp_test(long_test)
fast_float_add_cpp_test(powersoffive_hardround) fast_float_add_cpp_test(powersoffive_hardround)
fast_float_add_cpp_test(string_test) fast_float_add_cpp_test(string_test)

View File

@ -1134,23 +1134,6 @@ TEST_CASE("double.inf") {
std::errc::result_out_of_range); 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); 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") { TEST_CASE("double.general") {
@ -1160,13 +1143,6 @@ TEST_CASE("double.general") {
verify("-22250738585072012e-324", verify("-22250738585072012e-324",
-0x1p-1022); /* limit between normal and subnormal*/ -0x1p-1022); /* limit between normal and subnormal*/
verify("-1e-999", -0.0, std::errc::result_out_of_range); 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("-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);
@ -1342,15 +1318,6 @@ TEST_CASE("double.general") {
std::numeric_limits<double>::infinity(), std::errc::result_out_of_range); std::numeric_limits<double>::infinity(), std::errc::result_out_of_range);
verify("-2240084132271013504.131248280843119943687942846658579428", verify("-2240084132271013504.131248280843119943687942846658579428",
-0x1.f1660a65b00bfp+60); -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") { TEST_CASE("double.decimal_point") {
@ -1525,35 +1492,14 @@ TEST_CASE("float.inf") {
std::errc::result_out_of_range); 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); 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") { 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 // max
verify("340282346638528859811704183484516925440", 0x1.fffffep+127f); verify("340282346638528859811704183484516925440", 0x1.fffffep+127f);
// -max // -max
verify("-340282346638528859811704183484516925440", -0x1.fffffep+127f); 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("-1e-999", -0.0f, std::errc::result_out_of_range);
verify("1." verify("1."
"175494140627517859246175898662808184331245864732796240031385942718174" "175494140627517859246175898662808184331245864732796240031385942718174"
@ -2124,317 +2070,3 @@ TEST_CASE("bfloat16.general") {
// 0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875bf16); // 0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875bf16);
} }
#endif #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; 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; return EXIT_SUCCESS;
} }

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;
}