Compare commits

...

43 Commits

Author SHA1 Message Date
Thomas Beutlich
c553930104
Merge e6867f54b978ff992f4855ce7026a21c0f1a78b4 into 7b21183a93c4a8943a2d384f207537d7330547e1 2025-11-04 15:33:36 +01:00
Daniel Lemire
7b21183a93
Merge pull request #336 from fastfloat/dependabot/github_actions/github-actions-625a8519cf
Bump the github-actions group across 1 directory with 4 updates
2025-10-30 22:04:57 -04:00
dependabot[bot]
8ac72791a9
Bump the github-actions group across 1 directory with 4 updates
Bumps the github-actions group with 4 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [actions/upload-artifact](https://github.com/actions/upload-artifact), [github/codeql-action](https://github.com/github/codeql-action) and [actions/setup-node](https://github.com/actions/setup-node).


Updates `actions/checkout` from 4 to 5
- [Release notes](https://github.com/actions/checkout/releases)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

Updates `actions/upload-artifact` from 4 to 5
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

Updates `github/codeql-action` from 3 to 4
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v3...v4)

Updates `actions/setup-node` from 4.4.0 to 6.0.0
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](49933ea528...2028fbc5c2)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: github/codeql-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/setup-node
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 00:14:47 +00:00
Daniel Lemire
e77e2bca7e
Update README.md 2025-10-10 09:23:01 -04:00
Daniel Lemire
24fa687d45
Merge pull request #334 from toughengineer/max-infinity_corner_cases
Added corner cases around max value/infinity
2025-10-04 09:50:30 -04:00
Pavel Novikov
88f6c5e367
Added corner cases around max value/infinity 2025-10-04 14:39:00 +03:00
Daniel Lemire
83a4f696d7
Merge pull request #333 from toughengineer/made_function_non-template
Made function non-template
2025-09-30 10:25:59 -04:00
Pavel Novikov
1ea4d2563e
made function non-template
+fixed a couple of typos
2025-09-30 12:18:29 +03:00
Daniel Lemire
7262d9454e lint 2025-09-29 15:08:24 -04:00
Daniel Lemire
23f16adad4
Merge pull request #328 from toughengineer/int_multiplication_by_power_of_10
Added template overloads for `integer_times_pow10()`
2025-09-29 15:07:54 -04:00
Daniel Lemire
fd98fd6689
specialize for std::float32_t and std::float64_t explicitly
credit: @lemire
2025-09-29 21:43:36 +03:00
Pavel Novikov
197c0ffca7
clang format 2025-09-29 21:43:35 +03:00
Pavel Novikov
e9438e64ba
fixed copy&paste error and minor mess 2025-09-29 19:54:25 +03:00
Pavel Novikov
7abb574ffc
added doc to README and examples 2025-09-29 13:00:40 +03:00
Anders Dalvander
04e8e545d8
Merge pull request #330 from jbicha/repology-badge
README.md: update repology badge
2025-09-24 22:34:00 +02:00
Jeremy Bícha
e4b949e55b README.md: update repology badge 2025-09-24 16:08:34 -04:00
Pavel Novikov
01e505797b
added tests + some refactoring 2025-09-18 21:29:25 +03:00
Pavel Novikov
13345cab65
added template overload for integer_times_pow10() 2025-09-18 21:29:25 +03:00
Daniel Lemire
88b1e5321c version 8.1.0 2025-09-18 09:38:45 -06:00
Daniel Lemire
2aa6d0ba72
Merge pull request #326 from fastfloat/patch803
Release candidate 8.0.3
2025-09-18 09:37:20 -06:00
Daniel Lemire
0b6d911220 format 2025-09-18 08:30:28 -06:00
Daniel Lemire
2d6574483d
Merge pull request #327 from toughengineer/int_multiplication_by_power_of_10
Minor fix of forward declaration
2025-09-18 08:29:57 -06:00
Pavel Novikov
7a77227521
minor fix of forward declaration 2025-09-18 17:02:29 +03:00
Daniel Lemire
e20c952456
Merge pull request #320 from toughengineer/int_multiplication_by_power_of_10
Implemented multiplication of integer by a power of 10
2025-09-18 07:48:09 -06:00
Daniel Lemire
bb956b29db release candidate 8.0.3 2025-09-18 07:44:53 -06:00
Daniel Lemire
48fc5404d4 compatibility fix 2025-09-18 07:44:05 -06:00
Daniel Lemire
e5612e9f72
Merge pull request #325 from InvalidUsernameException/emoji-parses-as-int
Do not mis-parse certain wide-character emojis as integer
2025-09-18 07:39:59 -06:00
Daniel Lemire
fb384a4205
Add Blender to the list of projects using fast_float 2025-09-17 23:09:25 -06:00
InvalidUsernameException
9d81c71aef Do not mis-parse certain wide-character emojis as integer
When calling ch_to_digit() with a UTF-16 or UTF-32 code unit, it simply
truncates away any data stored in the non-low byte(s) of the code unit.
It then uses a lookup table to determine whether the low byte
corresponds to an ASCII digit. This is incorrect because as soon as any
bit outside the low byte is set, the number will never correspond to a
ASCII digit anymore.

To fix this, we produce a mask that is all zeroes if any bit outside the
low byte is set in the code unit, all ones otherwise. Anding this mask
with the original code unit forces the table lookup to return the
sentinel value from the zero-index if any high bit was set and causes
the code unit not to be parsed as integer.

This bug was discovered when loading Mastodon posts inside the Ladybird
browser where some of Mastodon's JavaScript would trigger the code path
that erroneously parsed the emoji as integer. It had the visible effect
that some digits inside the posts would get rendered as one of the
emojis that parsed to that digit. For more details see this issue:
https://github.com/LadybirdBrowser/ladybird/issues/6205

The emojis in the test case are simply all the emojis used on Mastodon
that caused the bug. They can be found here:
06803422da/app/javascript/mastodon/features/emoji/emoji_map.json
2025-09-15 23:12:28 +02:00
Daniel Lemire
fec4082f01
Merge pull request #322 from leiwen2025/rv-support
float_common.h: Support RISC-V
2025-09-12 15:11:45 -04:00
Daniel Lemire
e89e248bd7
Update risc.yml 2025-09-11 22:14:59 -04:00
Daniel Lemire
96fc38fb5a adding risc ci 2025-09-11 22:11:05 -04:00
WenLei
6677924083 float_common.h: Support RISC-V 2025-09-11 11:11:30 +08:00
Pavel Novikov
0a230326ab
now finally got the anti-ambiguity overloads right, right? 2025-09-06 02:22:43 +03:00
Pavel Novikov
7ae62ee0d5
finally got the anti-ambiguity overloads right? 2025-09-06 02:10:55 +03:00
Pavel Novikov
e12463583f
added lacking overloads to avoid potential ambiguity 2025-09-06 00:12:41 +03:00
Pavel Novikov
6702cd4244
added doc section in the README,
added example code test executable
2025-09-05 13:36:23 +03:00
Pavel Novikov
20a7383442
renamed the function, cleaned up return type 2025-09-05 13:36:23 +03:00
Pavel Novikov
763558b9ac
cleaned up tests 2025-09-05 13:34:48 +03:00
Pavel Novikov
6be07d66a8
inlining Clinger's fast path because why not,
and it seems to bring performance to the level before the changes somewhat
2025-09-03 16:59:40 +03:00
Pavel Novikov
cc90f240ee
added some tests 2025-09-02 23:03:38 +03:00
Pavel Novikov
a134561e4b
added missing inline specifiers 2025-09-02 23:03:38 +03:00
Pavel Novikov
7b8f04500a
implemented multiplication of integer by power of 10 2025-09-02 13:20:36 +03:00
14 changed files with 939 additions and 60 deletions

View File

@ -20,14 +20,14 @@ jobs:
fuzz-seconds: 300
output-sarif: true
- name: Upload Crash
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
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@v3
uses: github/codeql-action/upload-sarif@v4
with:
# Path to SARIF file relative to the root of the repository
sarif_file: cifuzz-sarif/results.sarif

View File

@ -5,7 +5,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14
- name: Verify
run: emcc -v

23
.github/workflows/risc.yml vendored Normal file
View File

@ -0,0 +1,23 @@
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

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.14)
project(fast_float VERSION 8.0.2 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(CMAKE_CXX_STANDARD ${FASTFLOAT_CXX_STANDARD})
option(FASTFLOAT_TEST "Enable tests" OFF)

View File

@ -381,6 +381,50 @@ 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
@ -389,6 +433,8 @@ The fast_float library is part of:
* GCC (as of version 12): the `from_chars` function in GCC relies on fast_float,
* [Chromium](https://github.com/Chromium/Chromium), the engine behind Google
Chrome, Microsoft Edge, and Opera,
* Boost JSON, MySQL, etc.
* Blender
* [WebKit](https://github.com/WebKit/WebKit), the engine behind Safari (Apple's
web browser),
* [DuckDB](https://duckdb.org),
@ -418,7 +464,7 @@ framework](https://github.com/microsoft/LightGBM).
Packages
------
[![Packaging status](https://repology.org/badge/vertical-allrepos/fastfloat.svg)](https://repology.org/project/fastfloat/versions)
[![Packaging status](https://repology.org/badge/vertical-allrepos/fast-float.svg)](https://repology.org/project/fast-float/versions)
## References
@ -491,7 +537,7 @@ sufficiently recent version of CMake (3.11 or better at least):
FetchContent_Declare(
fast_float
GIT_REPOSITORY https://github.com/fastfloat/fast_float.git
GIT_TAG tags/v8.0.2
GIT_TAG tags/v8.1.0
GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(fast_float)
@ -507,7 +553,7 @@ You may also use [CPM](https://github.com/cpm-cmake/CPM.cmake), like so:
CPMAddPackage(
NAME fast_float
GITHUB_REPOSITORY "fastfloat/fast_float"
GIT_TAG v8.0.2)
GIT_TAG v8.1.0)
```
## Using as single header
@ -519,7 +565,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.0.2/fast_float.h>
<https://github.com/fastfloat/fast_float/releases/download/v8.1.0/fast_float.h>
## Benchmarking
@ -573,6 +619,11 @@ 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

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

View File

@ -38,11 +38,8 @@ 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(parsed_number_string_t<UC> &num) noexcept {
uint64_t mantissa = num.mantissa;
int32_t exponent = int32_t(num.exponent);
scientific_exponent(uint64_t mantissa, int32_t exponent) noexcept {
while (mantissa >= 10000) {
mantissa /= 10000;
exponent += 4;
@ -398,7 +395,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp)));
}
// compare digits, and use it to director rounding
// compare digits, and use it to direct rounding
int ord = real_digits.compare(theor_digits);
adjusted_mantissa answer = am;
round<T>(answer, [ord](adjusted_mantissa &a, int32_t shift) {
@ -419,7 +416,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
return answer;
}
// parse the significant digits as a big integer to unambiguously round the
// parse the significant digits as a big integer to unambiguously round
// 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
@ -438,7 +435,8 @@ 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);
int32_t sci_exp =
scientific_exponent(num.mantissa, static_cast<int32_t>(num.exponent));
size_t max_digits = binary_format<T>::max_digits();
size_t digits = 0;
bigint bigmant;

View File

@ -45,6 +45,38 @@ 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 0
#define FASTFLOAT_VERSION_PATCH 2
#define FASTFLOAT_VERSION_MINOR 1
#define FASTFLOAT_VERSION_PATCH 0
#define FASTFLOAT_STRINGIZE_IMPL(x) #x
#define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x)
@ -93,11 +93,12 @@ using parse_options = parse_options_t<char>;
defined(__MINGW64__) || defined(__s390x__) || \
(defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \
defined(__PPC64LE__)) || \
defined(__loongarch64))
defined(__loongarch64) || (defined(__riscv) && __riscv_xlen == 64))
#define FASTFLOAT_64BIT 1
#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
defined(__arm__) || defined(_M_ARM) || defined(__ppc__) || \
defined(__MINGW32__) || defined(__EMSCRIPTEN__))
defined(__MINGW32__) || defined(__EMSCRIPTEN__) || \
(defined(__riscv) && __riscv_xlen == 32))
#define FASTFLOAT_32BIT 1
#else
// Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow.
@ -1131,7 +1132,12 @@ 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) {
return int_luts<>::chdigit[static_cast<unsigned char>(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)))];
}
fastfloat_really_inline constexpr size_t max_digits_u64(int base) {
@ -1160,6 +1166,9 @@ 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__
@ -1168,6 +1177,9 @@ 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__
@ -1239,7 +1251,6 @@ constexpr chars_format adjust_for_feature_macros(chars_format fmt) {
;
}
} // namespace detail
} // namespace fast_float
#endif

View File

@ -188,32 +188,17 @@ from_chars(UC const *first, UC const *last, T &value,
parse_options_t<UC>(fmt));
}
/**
* This function overload takes parsed_number_string_t structure that is created
* and populated either by from_chars_advanced function taking chars range and
* parsing options or other parsing custom function implemented by user.
*/
template <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;
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 {
// 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() <= pns.exponent &&
pns.exponent <= binary_format<T>::max_exponent_fast_path() &&
!pns.too_many_digits) {
if (binary_format<T>::min_exponent_fast_path() <= exponent &&
exponent <= binary_format<T>::max_exponent_fast_path()) {
// Unfortunately, the conventional Clinger's fast path is only possible
// when the system rounds to the nearest float.
//
@ -224,41 +209,64 @@ from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
// We have that fegetround() == FE_TONEAREST.
// Next is Clinger's fast path.
if (pns.mantissa <= binary_format<T>::max_mantissa_fast_path()) {
value = T(pns.mantissa);
if (pns.exponent < 0) {
value = value / binary_format<T>::exact_power_of_ten(-pns.exponent);
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);
} else {
value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
value = value * binary_format<T>::exact_power_of_ten(exponent);
}
if (pns.negative) {
if (is_negative) {
value = -value;
}
return answer;
return true;
}
} else {
// We do not have that fegetround() == FE_TONEAREST.
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's
// proposal
if (pns.exponent >= 0 &&
pns.mantissa <=
binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
if (exponent >= 0 &&
mantissa <= binary_format<T>::max_mantissa_fast_path(exponent)) {
#if defined(__clang__) || defined(FASTFLOAT_32BIT)
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
if (pns.mantissa == 0) {
value = pns.negative ? T(-0.) : T(0.);
return answer;
if (mantissa == 0) {
value = is_negative ? T(-0.) : T(0.);
return true;
}
#endif
value = T(pns.mantissa) *
binary_format<T>::exact_power_of_ten(pns.exponent);
if (pns.negative) {
value = T(mantissa) * binary_format<T>::exact_power_of_ten(exponent);
if (is_negative) {
value = -value;
}
return true;
}
}
}
return false;
}
/**
* This function overload takes parsed_number_string_t structure that is created
* and populated either by from_chars_advanced function taking chars range and
* parsing options or other parsing custom function implemented by user.
*/
template <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) {
@ -336,6 +344,84 @@ 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

@ -61,6 +61,7 @@ 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)

View File

@ -1134,6 +1134,23 @@ 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") {
@ -1143,6 +1160,13 @@ 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);
@ -1318,6 +1342,15 @@ 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") {
@ -1492,14 +1525,35 @@ 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"
@ -2070,3 +2124,317 @@ 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

@ -0,0 +1,36 @@
#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,6 +831,275 @@ 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;
}