mirror of
https://github.com/fastfloat/fast_float.git
synced 2026-01-01 03:12:18 +08:00
First commit
This commit is contained in:
commit
1701be0224
34
CMakeLists.txt
Normal file
34
CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
project(fast_float VERSION 0.1.0 LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
|
||||
|
||||
option(FASTFLOAT_SANITIZE "Sanitize addresses" OFF)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
if(FASTFLOAT_SANITIZE)
|
||||
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
|
||||
else()
|
||||
message(STATUS "No build type selected, default to Release")
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
add_library(fast_float INTERFACE)
|
||||
target_include_directories(fast_float INTERFACE include/)
|
||||
if(FASTFLOAT_SANITIZE)
|
||||
target_compile_options(fast_float INTERFACE -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=all)
|
||||
target_link_libraries(fast_float INTERFACE -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=all)
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
target_link_libraries(fast_float INTERFACE -fuse-ld=gold)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(FASTFLOAT_TEST)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif(FASTFLOAT_SANITIZE)
|
||||
0
CONTRIBUTORS
Normal file
0
CONTRIBUTORS
Normal file
201
LICENSE
Normal file
201
LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 The fast_float authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
89
README.md
Normal file
89
README.md
Normal file
@ -0,0 +1,89 @@
|
||||
## fast_float number parsing library
|
||||
|
||||
The fast_float library provides fast header-only implementations for the C++ from_chars
|
||||
functions for `float` and `double` types. These functions convert ASCII strings representing
|
||||
decimal values (e.g., `1.3e10`) into binary types. We provide exact rounding (including
|
||||
round to even). In our experience, these `fast_float` functions are faster than any other comparable number-parsing functions. They provide a performance similar to that of the [fast_double_parser](https://github.com/lemire/fast_double_parser) but using an novel algorithm reworked from the ground up, and while offering an API more in line with the expectations of C++ programmers.
|
||||
|
||||
Specifically, `fast_float` provides the following two functions with a C++17-like syntax:
|
||||
|
||||
```C++
|
||||
from_chars_result from_chars(const char* first, const char* last, float& value, ...);
|
||||
from_chars_result from_chars(const char* first, const char* last, double& value, ...);
|
||||
```
|
||||
|
||||
The return type (`from_chars_result`) is defined as the struct:
|
||||
```C++
|
||||
struct from_chars_result {
|
||||
const char* ptr;
|
||||
std::errc ec;
|
||||
};
|
||||
```
|
||||
|
||||
It parses the character sequence [first,last) for a number. It parses floating-point numbers expecting
|
||||
a locale-indepent format equivalent to what is used by `std::strtod` in the default ("C") locale.
|
||||
The resulting floating-point value is the closest floating-point values (using either float or double),
|
||||
using the "round to even" convention for values that would otherwise fall right in-between two values.
|
||||
That is, we provide exact parsing according to the IEEE standard.
|
||||
|
||||
Given a successful parse, the pointer (`ptr`) in the returned value is set to point right after the
|
||||
parsed number, and the `value` referenced is set to the parsed value. In case of error, the returned
|
||||
`ec` contains a representative error, otherwise the default (`std::errc()`) value is stored.
|
||||
|
||||
The implementation does not throw and does not allocate memory (e.g., with `new` or `malloc`).
|
||||
|
||||
Example:
|
||||
|
||||
``` C++
|
||||
#include "fast_float/parse_number.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
const std::string input = "3.1416 xyz ";
|
||||
double result;
|
||||
auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result);
|
||||
if(answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||
std::cout << "parsed the number " << result << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
Like the C++17 standard, the `fast_float::from_chars` functions take an optional last argument of
|
||||
the type `fast_float::chars_format`. It is a bitset value: we check whether
|
||||
`fmt & fast_float::chars_format::fixed` and `fmt & fast_float::chars_format::scientific` are set
|
||||
to determine whether we allow the fixed point and scientific notation respectively.
|
||||
The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||
|
||||
## Using as a CMake dependency
|
||||
|
||||
This library is header-only by design. The CMake file provides the `fast_float` target
|
||||
which is merely a pointer to the `include` directory.
|
||||
|
||||
If you drop the `fast_float` repository in your CMake project, you should be able to use
|
||||
it in this manner:
|
||||
|
||||
```
|
||||
add_subdirectory(fast_float)
|
||||
target_link_libraries(myprogram PUBLIC fast_float)
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Requirements and Limitations
|
||||
|
||||
In many cases, this library can be used as a drop-in replacement for the C++17 `from_chars` function, especially when performance is a concerned. Thus we expect C++17 support. Though it might be reasonable to want C++17 features as part of old compilers, support old systems is not an objective of this library.
|
||||
|
||||
The `from_chars` is meant to be locale-independent. Thus it is not an objective of this library to support
|
||||
locale-sensitive parsing.
|
||||
|
||||
The performance is optimized for 19 or fewer significant digits. In practice, there should
|
||||
never be more than 17 digits since it is enough to identify exactly all possible 64-bit numbers (double).
|
||||
In fact, for many numbers, far fewer than 17 digits are needed.
|
||||
|
||||
## Credit
|
||||
|
||||
Though this work is inspired by many different people, this work benefited especially from exchanges with
|
||||
Michael Eisel, who motivated the original research with his key insights, and with Nigel Tao who provided
|
||||
invaluable feedback.
|
||||
|
||||
The library includes code adapted from Google Wuffs (written by Nigel Tao) which was originally published
|
||||
under the Apache 2.0 license.
|
||||
311
include/fast_float/ascii_number.h
Normal file
311
include/fast_float/ascii_number.h
Normal file
@ -0,0 +1,311 @@
|
||||
#ifndef FASTFLOAT_ASCII_NUMBER_H
|
||||
#define FASTFLOAT_ASCII_NUMBER_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "float_common.h"
|
||||
|
||||
namespace fast_float {
|
||||
|
||||
fastfloat_really_inline bool is_integer(char c) noexcept { return (c >= '0' && c <= '9'); }
|
||||
|
||||
|
||||
// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
|
||||
fastfloat_really_inline uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
|
||||
uint64_t val;
|
||||
memcpy(&val, chars, sizeof(uint64_t));
|
||||
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
|
||||
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
|
||||
return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
|
||||
}
|
||||
|
||||
fastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars) noexcept {
|
||||
uint64_t val;
|
||||
memcpy(&val, chars, 8);
|
||||
return (((val & 0xF0F0F0F0F0F0F0F0) |
|
||||
(((val + 0x0606060606060606) & 0xF0F0F0F0F0F0F0F0) >> 4)) ==
|
||||
0x3333333333333333);
|
||||
}
|
||||
|
||||
|
||||
fastfloat_really_inline uint32_t parse_four_digits_unrolled(const char *chars) noexcept {
|
||||
uint32_t val;
|
||||
memcpy(&val, chars, sizeof(uint32_t));
|
||||
val = (val & 0x0F0F0F0F) * 2561 >> 8;
|
||||
return (val & 0x00FF00FF) * 6553601 >> 16;
|
||||
}
|
||||
|
||||
fastfloat_really_inline bool is_made_of_four_digits_fast(const char *chars) noexcept {
|
||||
uint32_t val;
|
||||
memcpy(&val, chars, 4);
|
||||
return (((val & 0xF0F0F0F0) |
|
||||
(((val + 0x06060606) & 0xF0F0F0F0) >> 4)) ==
|
||||
0x33333333);
|
||||
}
|
||||
|
||||
struct parsed_number_string {
|
||||
int64_t exponent;
|
||||
uint64_t mantissa;
|
||||
const char *lastmatch;
|
||||
bool negative;
|
||||
bool valid;
|
||||
bool too_many_digits;
|
||||
};
|
||||
|
||||
|
||||
// Assuming that you use no more than 17 digits, this will
|
||||
// parse an ASCII string.
|
||||
fastfloat_really_inline
|
||||
parsed_number_string parse_number_string(const char *p, const char *pend, chars_format fmt) noexcept {
|
||||
parsed_number_string answer;
|
||||
answer.valid = false;
|
||||
answer.negative = (*p == '-');
|
||||
if ((*p == '-') || (*p == '+')) {
|
||||
++p;
|
||||
if (p == pend) {
|
||||
return answer;
|
||||
}
|
||||
if (!is_integer(*p) && (*p != '.')) { // a sign must be followed by an integer or the dot
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
const char *const start_digits = p;
|
||||
|
||||
uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
|
||||
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
// a multiplication by 10 is cheaper than an arbitrary integer
|
||||
// multiplication
|
||||
i = 10 * i +
|
||||
(*p - '0'); // might overflow, we will handle the overflow later
|
||||
++p;
|
||||
}
|
||||
int64_t exponent = 0;
|
||||
if ((p != pend) && (*p == '.')) {
|
||||
++p;
|
||||
const char *first_after_period = p;
|
||||
if ((p + 8 <= pend) && is_made_of_eight_digits_fast(p)) {
|
||||
i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
|
||||
p += 8;
|
||||
if ((p + 8 <= pend) && is_made_of_eight_digits_fast(p)) {
|
||||
i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
|
||||
p += 8;
|
||||
}
|
||||
}
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
uint8_t digit = uint8_t(*p - '0');
|
||||
++p;
|
||||
i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
|
||||
}
|
||||
exponent = first_after_period - p;
|
||||
}
|
||||
// we must have encountered at least one integer!
|
||||
if ((start_digits == p) || ((start_digits == p - 1) && (*start_digits == '.') )) {
|
||||
return answer;
|
||||
}
|
||||
|
||||
int32_t digit_count =
|
||||
int32_t(p - start_digits - 1); // used later to guard against overflows
|
||||
|
||||
if ((p != pend) && (('e' == *p) || ('E' == *p))) {
|
||||
if((fmt & chars_format::fixed) && !(fmt & chars_format::scientific)) { return answer; }
|
||||
int64_t exp_number = 0; // exponential part
|
||||
++p;
|
||||
bool neg_exp = false;
|
||||
if ((p != pend) && ('-' == *p)) {
|
||||
neg_exp = true;
|
||||
++p;
|
||||
} else if ((p != pend) && ('+' == *p)) {
|
||||
++p;
|
||||
}
|
||||
if ((p == pend) || !is_integer(*p)) {
|
||||
return answer;
|
||||
}
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
uint8_t digit = uint8_t(*p - '0');
|
||||
if (exp_number < 0x10000) {
|
||||
exp_number = 10 * exp_number + digit;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
exponent += (neg_exp ? -exp_number : exp_number);
|
||||
} else {
|
||||
if((fmt & chars_format::scientific) && !(fmt & chars_format::fixed)) { return answer; }
|
||||
}
|
||||
answer.lastmatch = p;
|
||||
answer.valid = true;
|
||||
|
||||
// If we frequently had to deal with long strings of digits,
|
||||
// we could extend our code by using a 128-bit integer instead
|
||||
// of a 64-bit integer. However, this is uncommon.
|
||||
if (((digit_count >= 19))) { // this is uncommon
|
||||
// It is possible that the integer had an overflow.
|
||||
// We have to handle the case where we have 0.0000somenumber.
|
||||
const char *start = start_digits;
|
||||
while (*start == '0' || (*start == '.')) {
|
||||
start++;
|
||||
}
|
||||
// we over-decrement by one when there is a decimal separator
|
||||
digit_count -= int(start - start_digits);
|
||||
if (digit_count >= 19) {
|
||||
answer.mantissa = 0xFFFFFFFFFFFFFFFF; // important: we don't want the mantissa to be used in a fast path uninitialized.
|
||||
answer.too_many_digits = true;
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
answer.too_many_digits = false;
|
||||
answer.exponent = exponent;
|
||||
answer.mantissa = i;
|
||||
return answer;
|
||||
}
|
||||
|
||||
// This should always succeed since it follows a call to parse_number_string.
|
||||
// It assumes that there are more than 19 mantissa digits to parse.
|
||||
parsed_number_string parse_truncated_decimal(const char *&p, const char *pend) noexcept {
|
||||
parsed_number_string answer;
|
||||
answer.valid = true;
|
||||
answer.negative = (*p == '-');
|
||||
if ((*p == '-') || (*p == '+')) {
|
||||
++p;
|
||||
}
|
||||
size_t number_of_digits{0};
|
||||
|
||||
|
||||
uint64_t i = 0;
|
||||
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
// a multiplication by 10 is cheaper than an arbitrary integer
|
||||
// multiplication
|
||||
if(number_of_digits < 19) {
|
||||
|
||||
uint8_t digit = uint8_t(*p - '0');
|
||||
i = 10 * i + digit;
|
||||
number_of_digits ++;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
int64_t exponent = 0;
|
||||
if ((p != pend) && (*p == '.')) {
|
||||
++p;
|
||||
const char *first_after_period = p;
|
||||
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
if(number_of_digits < 19) {
|
||||
uint8_t digit = uint8_t(*p - '0');
|
||||
i = i * 10 + digit;
|
||||
number_of_digits ++;
|
||||
} else if (exponent == 0) {
|
||||
exponent = first_after_period - p;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
if ((p != pend) && (('e' == *p) || ('E' == *p))) {
|
||||
int64_t exp_number = 0; // exponential part
|
||||
++p;
|
||||
bool neg_exp = false;
|
||||
if ((p != pend) && ('-' == *p)) {
|
||||
neg_exp = true;
|
||||
++p;
|
||||
} else if ((p != pend) && ('+' == *p)) {
|
||||
++p;
|
||||
}
|
||||
if ((p == pend) || !is_integer(*p)) {
|
||||
return answer;
|
||||
}
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
uint8_t digit = uint8_t(*p - '0');
|
||||
if (exp_number < 0x10000) {
|
||||
exp_number = 10 * exp_number + digit;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
exponent += (neg_exp ? -exp_number : exp_number);
|
||||
}
|
||||
answer.lastmatch = p;
|
||||
answer.valid = true;
|
||||
answer.too_many_digits = true; // assumed
|
||||
answer.exponent = exponent;
|
||||
answer.mantissa = i;
|
||||
return answer;
|
||||
}
|
||||
|
||||
|
||||
// This should always succeed since it follows a call to parse_number_string.
|
||||
decimal parse_decimal(const char *&p, const char *pend) noexcept {
|
||||
decimal answer;
|
||||
answer.num_digits = 0;
|
||||
answer.decimal_point = 0;
|
||||
answer.negative = false;
|
||||
answer.truncated = false;
|
||||
// skip leading whitespace
|
||||
while (fast_float::is_space(*p)) {
|
||||
p++;
|
||||
}
|
||||
answer.negative = (*p == '-');
|
||||
if ((*p == '-') || (*p == '+')) {
|
||||
++p;
|
||||
}
|
||||
|
||||
while ((p != pend) && (*p == '0')) {
|
||||
++p;
|
||||
}
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
if (answer.num_digits + 1 < max_digits) {
|
||||
answer.digits[answer.num_digits++] = uint8_t(*p - '0');
|
||||
} else {
|
||||
answer.truncated = true;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
const char *first_after_period{};
|
||||
if ((p != pend) && (*p == '.')) {
|
||||
++p;
|
||||
first_after_period = p;
|
||||
// if we have not yet encountered a zero, we have to skip it as well
|
||||
if(answer.num_digits == 0) {
|
||||
// skip zeros
|
||||
while ((p != pend) && (*p == '0')) {
|
||||
++p;
|
||||
}
|
||||
}
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
if (answer.num_digits + 1 < max_digits) {
|
||||
answer.digits[answer.num_digits++] = uint8_t(*p - '0');
|
||||
} else {
|
||||
answer.truncated = true;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
answer.decimal_point = int32_t(first_after_period - p);
|
||||
}
|
||||
|
||||
if ((p != pend) && (('e' == *p) || ('E' == *p))) {
|
||||
++p;
|
||||
bool neg_exp = false;
|
||||
if ((p != pend) && ('-' == *p)) {
|
||||
neg_exp = true;
|
||||
++p;
|
||||
} else if ((p != pend) && ('+' == *p)) {
|
||||
++p;
|
||||
}
|
||||
int32_t exp_number = 0; // exponential part
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
uint8_t digit = uint8_t(*p - '0');
|
||||
if (exp_number < 0x10000) {
|
||||
exp_number = 10 * exp_number + digit;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
answer.decimal_point += (neg_exp ? -exp_number : exp_number);
|
||||
}
|
||||
answer.decimal_point += answer.num_digits;
|
||||
return answer;
|
||||
}
|
||||
} // namespace fast_float
|
||||
|
||||
#endif
|
||||
165
include/fast_float/decimal_to_binary.h
Normal file
165
include/fast_float/decimal_to_binary.h
Normal file
@ -0,0 +1,165 @@
|
||||
#ifndef FASTFLOAT_DECIMAL_TO_BINARY_H
|
||||
#define FASTFLOAT_DECIMAL_TO_BINARY_H
|
||||
|
||||
#include "float_common.h"
|
||||
#include "fast_table.h"
|
||||
#include <cfloat>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
namespace fast_float {
|
||||
|
||||
|
||||
|
||||
|
||||
// This will compute or rather approximate w * 5**q and return a pair of 64-bit words approximating
|
||||
// the result, with the "high" part corresponding to the most significant bits and the
|
||||
// low part corresponding to the least significant bits.
|
||||
//
|
||||
template <int bit_precision>
|
||||
fastfloat_really_inline
|
||||
value128 compute_product_approximation(int64_t q, uint64_t w) {
|
||||
const int index = 2 * int(q - smallest_power_of_five);
|
||||
// For small values of q, e.g., q in [0,27], the answer is always exact because
|
||||
// The line value128 firstproduct = full_multiplication(w, power_of_five_128[index]);
|
||||
// gives the exact answer.
|
||||
value128 firstproduct = full_multiplication(w, power_of_five_128[index]);
|
||||
static_assert((bit_precision >= 0) && (bit_precision <= 64), " precision should be in (0,64]");
|
||||
constexpr uint64_t precision_mask = (bit_precision < 64) ?
|
||||
(uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision)
|
||||
: uint64_t(0xFFFFFFFFFFFFFFFF);
|
||||
if((firstproduct.high & precision_mask) == precision_mask) { // could further guard with (lower + w < lower)
|
||||
// regarding the second product, we only need secondproduct.high, but our expectation is that the compiler will optimize this extra work away if needed.
|
||||
value128 secondproduct = full_multiplication(w, power_of_five_128[index + 1]);
|
||||
firstproduct.low += secondproduct.high;
|
||||
if(secondproduct.high > firstproduct.low) {
|
||||
firstproduct.high++;
|
||||
}
|
||||
}
|
||||
return firstproduct;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* For q in (-400,350), we have that
|
||||
* f = (((152170 + 65536) * q ) >> 16);
|
||||
* is equal to
|
||||
* floor(p) + q
|
||||
* where
|
||||
* p = log(5**q)/log(2) = q * log(5)/log(2)
|
||||
*
|
||||
*/
|
||||
fastfloat_really_inline unsigned int power(int q) noexcept {
|
||||
return (((152170 + 65536) * q) >> 16) + 63;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// w * 10 ** q
|
||||
// The returned value should be a valid ieee64 number that simply need to be packed.
|
||||
// However, in some very rare cases, the computation will fail. In such cases, we
|
||||
// return an adjusted_mantissa with a negative power of 2: the caller should recompute
|
||||
// in such cases.
|
||||
template <typename binary>
|
||||
fastfloat_really_inline
|
||||
adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
||||
adjusted_mantissa answer;
|
||||
if ((w == 0) || (q < smallest_power_of_five) ){
|
||||
answer.power2 = 0;
|
||||
answer.mantissa = 0;
|
||||
// result should be zero
|
||||
return answer;
|
||||
}
|
||||
if (q > largest_power_of_five) {
|
||||
// we want to get infinity:
|
||||
answer.power2 = binary::infinite_power();
|
||||
answer.mantissa = 0;
|
||||
return answer;
|
||||
}
|
||||
// At this point in time q is in [smallest_power_of_five, largest_power_of_five].
|
||||
|
||||
// We want the most significant bit of i to be 1. Shift if needed.
|
||||
int lz = leading_zeroes(w);
|
||||
w <<= lz;
|
||||
|
||||
// The required precision is binary::mantissa_explicit_bits() + 3 because
|
||||
// 1. We need the implicit bit
|
||||
// 2. We need an extra bit for rounding purposes
|
||||
// 3. We might lose a bit due to the "upperbit" routine (result too small, requiring a shift)
|
||||
value128 product = compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
|
||||
if(product.low == 0xFFFFFFFFFFFFFFFF) { // could guard it further
|
||||
// In some very rare cases, this could happen, in which case we might need a more accurate
|
||||
// computation that what we can provide cheaply. This is very, very unlikely.
|
||||
answer.power2 = -1;
|
||||
return answer;
|
||||
}
|
||||
// The "compute_product_approximation" function can be slightly slower than a branchless approach:
|
||||
// value128 product = compute_product(q, w);
|
||||
// but in practice, we can win big with the compute_product_approximation if its additional branch
|
||||
// is easily predicted. Which is best is data specific.
|
||||
uint64_t upperbit = product.high >> 63;
|
||||
|
||||
answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);
|
||||
lz += int(1 ^ upperbit);
|
||||
answer.power2 = power(int(q)) - lz - binary::minimum_exponent() + 1;
|
||||
|
||||
if (answer.power2 <= 0) { // we have a subnormal?
|
||||
// Here have that answer.power2 <= 0 so -answer.power2 >= 0
|
||||
if(-answer.power2 + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure.
|
||||
answer.power2 = 0;
|
||||
answer.mantissa = 0;
|
||||
// result should be zero
|
||||
return answer;
|
||||
}
|
||||
// next line is safe because -answer.power2 + 1 < 0
|
||||
answer.mantissa >>= -answer.power2 + 1;
|
||||
// Thankfully, we can't have both "round-to-even" and subnormals because
|
||||
// "round-to-even" only occurs for powers close to 0.
|
||||
answer.mantissa += (answer.mantissa & 1); // round up
|
||||
answer.mantissa >>= 1;
|
||||
// There is a weird scenario where we don't have a subnormal but just.
|
||||
// Suppose we start with 2.2250738585072013e-308, we end up
|
||||
// with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal
|
||||
// whereas 0x40000000000000 x 2^-1023-53 is normal. Now, we need to round
|
||||
// up 0x3fffffffffffff x 2^-1023-53 and once we do, we are no longer
|
||||
// subnormal, but we can only know this after rounding.
|
||||
// So we only declare a subnormal if we are smaller than the threshold.
|
||||
answer.power2 = (answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) ? 0 : 1;
|
||||
return answer;
|
||||
}
|
||||
|
||||
// usually, we round *up*, but if we fall right in between and and we have an
|
||||
// even basis, we need to round down
|
||||
// We are only concerned with the cases where 5**q fits in single 64-bit word.
|
||||
if ((product.low <= 1) && (q >= binary::min_exponent_round_to_even()) && (q <= binary::max_exponent_round_to_even()) &&
|
||||
((answer.mantissa & 3) == 1) ) { // we may fall between two floats!
|
||||
// To be in-between two floats we need that in doing
|
||||
// answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);
|
||||
// ... we dropped out only zeroes. But if this happened, then we can go back!!!
|
||||
if((answer.mantissa << (upperbit + 64 - binary::mantissa_explicit_bits() - 3)) == product.high) {
|
||||
answer.mantissa &= ~1; // flip it so that we do not round up
|
||||
}
|
||||
}
|
||||
|
||||
answer.mantissa += (answer.mantissa & 1); // round up
|
||||
answer.mantissa >>= 1;
|
||||
if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) {
|
||||
answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits());
|
||||
answer.power2++; // undo previous addition
|
||||
}
|
||||
|
||||
answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits());
|
||||
if (answer.power2 >= binary::infinite_power()) { // infinity
|
||||
answer.power2 = binary::infinite_power();
|
||||
answer.mantissa = 0;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
} // namespace fast_float
|
||||
|
||||
#endif
|
||||
45
include/fast_float/fast_float.h
Normal file
45
include/fast_float/fast_float.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef FASTFLOAT_FAST_FLOAT_H
|
||||
#define FASTFLOAT_FAST_FLOAT_H
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace fast_float {
|
||||
enum chars_format {
|
||||
scientific = 1<<0,
|
||||
fixed = 1<<2,
|
||||
hex = 1<<3,
|
||||
general = fixed | scientific
|
||||
};
|
||||
|
||||
|
||||
struct from_chars_result {
|
||||
const char *ptr;
|
||||
std::errc ec;
|
||||
};
|
||||
|
||||
/**
|
||||
* This function parses the character sequence [first,last) for a number. It parses floating-point numbers expecting
|
||||
* a locale-indepent format equivalent to what is used by std::strtod in the default ("C") locale.
|
||||
* The resulting floating-point value is the closest floating-point values (using either float or double),
|
||||
* using the "round to even" convention for values that would otherwise fall right in-between two values.
|
||||
* That is, we provide exact parsing according to the IEEE standard.
|
||||
*
|
||||
* Given a successful parse, the pointer (`ptr`) in the returned value is set to point right after the
|
||||
* parsed number, and the `value` referenced is set to the parsed value. In case of error, the returned
|
||||
* `ec` contains a representative error, otherwise the default (`std::errc()`) value is stored.
|
||||
*
|
||||
* The implementation does not throw and does not allocate memory (e.g., with `new` or `malloc`).
|
||||
*
|
||||
* Like the C++17 standard, the `fast_float::from_chars` functions take an optional last argument of
|
||||
* the type `fast_float::chars_format`. It is a bitset value: we check whether
|
||||
* `fmt & fast_float::chars_format::fixed` and `fmt & fast_float::chars_format::scientific` are set
|
||||
* to determine whether we allowe the fixed point and scientific notation respectively.
|
||||
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||
*/
|
||||
template<typename T>
|
||||
from_chars_result from_chars(const char *first, const char *last,
|
||||
T &value, chars_format fmt = chars_format::general) noexcept;
|
||||
|
||||
}
|
||||
#include "fast_float/parse_number.h"
|
||||
#endif // FASTFLOAT_FAST_FLOAT_H
|
||||
689
include/fast_float/fast_table.h
Normal file
689
include/fast_float/fast_table.h
Normal file
@ -0,0 +1,689 @@
|
||||
#ifndef FASTFLOAT_FAST_TABLE_H
|
||||
#define FASTFLOAT_FAST_TABLE_H
|
||||
#include <cstdint>
|
||||
|
||||
namespace fast_float {
|
||||
|
||||
/**
|
||||
* When mapping numbers from decimal to binary,
|
||||
* we go from w * 10^q to m * 2^p but we have
|
||||
* 10^q = 5^q * 2^q, so effectively
|
||||
* we are trying to match
|
||||
* w * 2^q * 5^q to m * 2^p. Thus the powers of two
|
||||
* are not a concern since they can be represented
|
||||
* exactly using the binary notation, only the powers of five
|
||||
* affect the binary significand.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The smallest non-zero float (binary64) is 2^−1074.
|
||||
* We take as input numbers of the form w x 10^q where w < 2^64.
|
||||
* We have that w * 10^-343 < 2^(64-344) 5^-343 < 2^-1076.
|
||||
* However, we have that
|
||||
* (2^64-1) * 10^-342 = (2^64-1) * 2^-342 * 5^-342 > 2^−1074.
|
||||
* Thus it is possible for a number of the form w * 10^-342 where
|
||||
* w is a 64-bit value to be a non-zero floating-point number.
|
||||
*********
|
||||
* Any number of form w * 10^309 where w>= 1 is going to be
|
||||
* infinite in binary64 so we never need to worry about powers
|
||||
* of 5 greater than 308.
|
||||
*/
|
||||
constexpr int smallest_power_of_five = -342;
|
||||
constexpr int largest_power_of_five = 308;
|
||||
// truncated powers of five from 5^-344 all the way to 5^308
|
||||
const uint64_t power_of_five_128[]= {
|
||||
0xeef453d6923bd65a,0x113faa2906a13b3f,
|
||||
0x9558b4661b6565f8,0x4ac7ca59a424c507,
|
||||
0xbaaee17fa23ebf76,0x5d79bcf00d2df649,
|
||||
0xe95a99df8ace6f53,0xf4d82c2c107973dc,
|
||||
0x91d8a02bb6c10594,0x79071b9b8a4be869,
|
||||
0xb64ec836a47146f9,0x9748e2826cdee284,
|
||||
0xe3e27a444d8d98b7,0xfd1b1b2308169b25,
|
||||
0x8e6d8c6ab0787f72,0xfe30f0f5e50e20f7,
|
||||
0xb208ef855c969f4f,0xbdbd2d335e51a935,
|
||||
0xde8b2b66b3bc4723,0xad2c788035e61382,
|
||||
0x8b16fb203055ac76,0x4c3bcb5021afcc31,
|
||||
0xaddcb9e83c6b1793,0xdf4abe242a1bbf3d,
|
||||
0xd953e8624b85dd78,0xd71d6dad34a2af0d,
|
||||
0x87d4713d6f33aa6b,0x8672648c40e5ad68,
|
||||
0xa9c98d8ccb009506,0x680efdaf511f18c2,
|
||||
0xd43bf0effdc0ba48,0x212bd1b2566def2,
|
||||
0x84a57695fe98746d,0x14bb630f7604b57,
|
||||
0xa5ced43b7e3e9188,0x419ea3bd35385e2d,
|
||||
0xcf42894a5dce35ea,0x52064cac828675b9,
|
||||
0x818995ce7aa0e1b2,0x7343efebd1940993,
|
||||
0xa1ebfb4219491a1f,0x1014ebe6c5f90bf8,
|
||||
0xca66fa129f9b60a6,0xd41a26e077774ef6,
|
||||
0xfd00b897478238d0,0x8920b098955522b4,
|
||||
0x9e20735e8cb16382,0x55b46e5f5d5535b0,
|
||||
0xc5a890362fddbc62,0xeb2189f734aa831d,
|
||||
0xf712b443bbd52b7b,0xa5e9ec7501d523e4,
|
||||
0x9a6bb0aa55653b2d,0x47b233c92125366e,
|
||||
0xc1069cd4eabe89f8,0x999ec0bb696e840a,
|
||||
0xf148440a256e2c76,0xc00670ea43ca250d,
|
||||
0x96cd2a865764dbca,0x380406926a5e5728,
|
||||
0xbc807527ed3e12bc,0xc605083704f5ecf2,
|
||||
0xeba09271e88d976b,0xf7864a44c633682e,
|
||||
0x93445b8731587ea3,0x7ab3ee6afbe0211d,
|
||||
0xb8157268fdae9e4c,0x5960ea05bad82964,
|
||||
0xe61acf033d1a45df,0x6fb92487298e33bd,
|
||||
0x8fd0c16206306bab,0xa5d3b6d479f8e056,
|
||||
0xb3c4f1ba87bc8696,0x8f48a4899877186c,
|
||||
0xe0b62e2929aba83c,0x331acdabfe94de87,
|
||||
0x8c71dcd9ba0b4925,0x9ff0c08b7f1d0b14,
|
||||
0xaf8e5410288e1b6f,0x7ecf0ae5ee44dd9,
|
||||
0xdb71e91432b1a24a,0xc9e82cd9f69d6150,
|
||||
0x892731ac9faf056e,0xbe311c083a225cd2,
|
||||
0xab70fe17c79ac6ca,0x6dbd630a48aaf406,
|
||||
0xd64d3d9db981787d,0x92cbbccdad5b108,
|
||||
0x85f0468293f0eb4e,0x25bbf56008c58ea5,
|
||||
0xa76c582338ed2621,0xaf2af2b80af6f24e,
|
||||
0xd1476e2c07286faa,0x1af5af660db4aee1,
|
||||
0x82cca4db847945ca,0x50d98d9fc890ed4d,
|
||||
0xa37fce126597973c,0xe50ff107bab528a0,
|
||||
0xcc5fc196fefd7d0c,0x1e53ed49a96272c8,
|
||||
0xff77b1fcbebcdc4f,0x25e8e89c13bb0f7a,
|
||||
0x9faacf3df73609b1,0x77b191618c54e9ac,
|
||||
0xc795830d75038c1d,0xd59df5b9ef6a2417,
|
||||
0xf97ae3d0d2446f25,0x4b0573286b44ad1d,
|
||||
0x9becce62836ac577,0x4ee367f9430aec32,
|
||||
0xc2e801fb244576d5,0x229c41f793cda73f,
|
||||
0xf3a20279ed56d48a,0x6b43527578c1110f,
|
||||
0x9845418c345644d6,0x830a13896b78aaa9,
|
||||
0xbe5691ef416bd60c,0x23cc986bc656d553,
|
||||
0xedec366b11c6cb8f,0x2cbfbe86b7ec8aa8,
|
||||
0x94b3a202eb1c3f39,0x7bf7d71432f3d6a9,
|
||||
0xb9e08a83a5e34f07,0xdaf5ccd93fb0cc53,
|
||||
0xe858ad248f5c22c9,0xd1b3400f8f9cff68,
|
||||
0x91376c36d99995be,0x23100809b9c21fa1,
|
||||
0xb58547448ffffb2d,0xabd40a0c2832a78a,
|
||||
0xe2e69915b3fff9f9,0x16c90c8f323f516c,
|
||||
0x8dd01fad907ffc3b,0xae3da7d97f6792e3,
|
||||
0xb1442798f49ffb4a,0x99cd11cfdf41779c,
|
||||
0xdd95317f31c7fa1d,0x40405643d711d583,
|
||||
0x8a7d3eef7f1cfc52,0x482835ea666b2572,
|
||||
0xad1c8eab5ee43b66,0xda3243650005eecf,
|
||||
0xd863b256369d4a40,0x90bed43e40076a82,
|
||||
0x873e4f75e2224e68,0x5a7744a6e804a291,
|
||||
0xa90de3535aaae202,0x711515d0a205cb36,
|
||||
0xd3515c2831559a83,0xd5a5b44ca873e03,
|
||||
0x8412d9991ed58091,0xe858790afe9486c2,
|
||||
0xa5178fff668ae0b6,0x626e974dbe39a872,
|
||||
0xce5d73ff402d98e3,0xfb0a3d212dc8128f,
|
||||
0x80fa687f881c7f8e,0x7ce66634bc9d0b99,
|
||||
0xa139029f6a239f72,0x1c1fffc1ebc44e80,
|
||||
0xc987434744ac874e,0xa327ffb266b56220,
|
||||
0xfbe9141915d7a922,0x4bf1ff9f0062baa8,
|
||||
0x9d71ac8fada6c9b5,0x6f773fc3603db4a9,
|
||||
0xc4ce17b399107c22,0xcb550fb4384d21d3,
|
||||
0xf6019da07f549b2b,0x7e2a53a146606a48,
|
||||
0x99c102844f94e0fb,0x2eda7444cbfc426d,
|
||||
0xc0314325637a1939,0xfa911155fefb5308,
|
||||
0xf03d93eebc589f88,0x793555ab7eba27ca,
|
||||
0x96267c7535b763b5,0x4bc1558b2f3458de,
|
||||
0xbbb01b9283253ca2,0x9eb1aaedfb016f16,
|
||||
0xea9c227723ee8bcb,0x465e15a979c1cadc,
|
||||
0x92a1958a7675175f,0xbfacd89ec191ec9,
|
||||
0xb749faed14125d36,0xcef980ec671f667b,
|
||||
0xe51c79a85916f484,0x82b7e12780e7401a,
|
||||
0x8f31cc0937ae58d2,0xd1b2ecb8b0908810,
|
||||
0xb2fe3f0b8599ef07,0x861fa7e6dcb4aa15,
|
||||
0xdfbdcece67006ac9,0x67a791e093e1d49a,
|
||||
0x8bd6a141006042bd,0xe0c8bb2c5c6d24e0,
|
||||
0xaecc49914078536d,0x58fae9f773886e18,
|
||||
0xda7f5bf590966848,0xaf39a475506a899e,
|
||||
0x888f99797a5e012d,0x6d8406c952429603,
|
||||
0xaab37fd7d8f58178,0xc8e5087ba6d33b83,
|
||||
0xd5605fcdcf32e1d6,0xfb1e4a9a90880a64,
|
||||
0x855c3be0a17fcd26,0x5cf2eea09a55067f,
|
||||
0xa6b34ad8c9dfc06f,0xf42faa48c0ea481e,
|
||||
0xd0601d8efc57b08b,0xf13b94daf124da26,
|
||||
0x823c12795db6ce57,0x76c53d08d6b70858,
|
||||
0xa2cb1717b52481ed,0x54768c4b0c64ca6e,
|
||||
0xcb7ddcdda26da268,0xa9942f5dcf7dfd09,
|
||||
0xfe5d54150b090b02,0xd3f93b35435d7c4c,
|
||||
0x9efa548d26e5a6e1,0xc47bc5014a1a6daf,
|
||||
0xc6b8e9b0709f109a,0x359ab6419ca1091b,
|
||||
0xf867241c8cc6d4c0,0xc30163d203c94b62,
|
||||
0x9b407691d7fc44f8,0x79e0de63425dcf1d,
|
||||
0xc21094364dfb5636,0x985915fc12f542e4,
|
||||
0xf294b943e17a2bc4,0x3e6f5b7b17b2939d,
|
||||
0x979cf3ca6cec5b5a,0xa705992ceecf9c42,
|
||||
0xbd8430bd08277231,0x50c6ff782a838353,
|
||||
0xece53cec4a314ebd,0xa4f8bf5635246428,
|
||||
0x940f4613ae5ed136,0x871b7795e136be99,
|
||||
0xb913179899f68584,0x28e2557b59846e3f,
|
||||
0xe757dd7ec07426e5,0x331aeada2fe589cf,
|
||||
0x9096ea6f3848984f,0x3ff0d2c85def7621,
|
||||
0xb4bca50b065abe63,0xfed077a756b53a9,
|
||||
0xe1ebce4dc7f16dfb,0xd3e8495912c62894,
|
||||
0x8d3360f09cf6e4bd,0x64712dd7abbbd95c,
|
||||
0xb080392cc4349dec,0xbd8d794d96aacfb3,
|
||||
0xdca04777f541c567,0xecf0d7a0fc5583a0,
|
||||
0x89e42caaf9491b60,0xf41686c49db57244,
|
||||
0xac5d37d5b79b6239,0x311c2875c522ced5,
|
||||
0xd77485cb25823ac7,0x7d633293366b828b,
|
||||
0x86a8d39ef77164bc,0xae5dff9c02033197,
|
||||
0xa8530886b54dbdeb,0xd9f57f830283fdfc,
|
||||
0xd267caa862a12d66,0xd072df63c324fd7b,
|
||||
0x8380dea93da4bc60,0x4247cb9e59f71e6d,
|
||||
0xa46116538d0deb78,0x52d9be85f074e608,
|
||||
0xcd795be870516656,0x67902e276c921f8b,
|
||||
0x806bd9714632dff6,0xba1cd8a3db53b6,
|
||||
0xa086cfcd97bf97f3,0x80e8a40eccd228a4,
|
||||
0xc8a883c0fdaf7df0,0x6122cd128006b2cd,
|
||||
0xfad2a4b13d1b5d6c,0x796b805720085f81,
|
||||
0x9cc3a6eec6311a63,0xcbe3303674053bb0,
|
||||
0xc3f490aa77bd60fc,0xbedbfc4411068a9c,
|
||||
0xf4f1b4d515acb93b,0xee92fb5515482d44,
|
||||
0x991711052d8bf3c5,0x751bdd152d4d1c4a,
|
||||
0xbf5cd54678eef0b6,0xd262d45a78a0635d,
|
||||
0xef340a98172aace4,0x86fb897116c87c34,
|
||||
0x9580869f0e7aac0e,0xd45d35e6ae3d4da0,
|
||||
0xbae0a846d2195712,0x8974836059cca109,
|
||||
0xe998d258869facd7,0x2bd1a438703fc94b,
|
||||
0x91ff83775423cc06,0x7b6306a34627ddcf,
|
||||
0xb67f6455292cbf08,0x1a3bc84c17b1d542,
|
||||
0xe41f3d6a7377eeca,0x20caba5f1d9e4a93,
|
||||
0x8e938662882af53e,0x547eb47b7282ee9c,
|
||||
0xb23867fb2a35b28d,0xe99e619a4f23aa43,
|
||||
0xdec681f9f4c31f31,0x6405fa00e2ec94d4,
|
||||
0x8b3c113c38f9f37e,0xde83bc408dd3dd04,
|
||||
0xae0b158b4738705e,0x9624ab50b148d445,
|
||||
0xd98ddaee19068c76,0x3badd624dd9b0957,
|
||||
0x87f8a8d4cfa417c9,0xe54ca5d70a80e5d6,
|
||||
0xa9f6d30a038d1dbc,0x5e9fcf4ccd211f4c,
|
||||
0xd47487cc8470652b,0x7647c3200069671f,
|
||||
0x84c8d4dfd2c63f3b,0x29ecd9f40041e073,
|
||||
0xa5fb0a17c777cf09,0xf468107100525890,
|
||||
0xcf79cc9db955c2cc,0x7182148d4066eeb4,
|
||||
0x81ac1fe293d599bf,0xc6f14cd848405530,
|
||||
0xa21727db38cb002f,0xb8ada00e5a506a7c,
|
||||
0xca9cf1d206fdc03b,0xa6d90811f0e4851c,
|
||||
0xfd442e4688bd304a,0x908f4a166d1da663,
|
||||
0x9e4a9cec15763e2e,0x9a598e4e043287fe,
|
||||
0xc5dd44271ad3cdba,0x40eff1e1853f29fd,
|
||||
0xf7549530e188c128,0xd12bee59e68ef47c,
|
||||
0x9a94dd3e8cf578b9,0x82bb74f8301958ce,
|
||||
0xc13a148e3032d6e7,0xe36a52363c1faf01,
|
||||
0xf18899b1bc3f8ca1,0xdc44e6c3cb279ac1,
|
||||
0x96f5600f15a7b7e5,0x29ab103a5ef8c0b9,
|
||||
0xbcb2b812db11a5de,0x7415d448f6b6f0e7,
|
||||
0xebdf661791d60f56,0x111b495b3464ad21,
|
||||
0x936b9fcebb25c995,0xcab10dd900beec34,
|
||||
0xb84687c269ef3bfb,0x3d5d514f40eea742,
|
||||
0xe65829b3046b0afa,0xcb4a5a3112a5112,
|
||||
0x8ff71a0fe2c2e6dc,0x47f0e785eaba72ab,
|
||||
0xb3f4e093db73a093,0x59ed216765690f56,
|
||||
0xe0f218b8d25088b8,0x306869c13ec3532c,
|
||||
0x8c974f7383725573,0x1e414218c73a13fb,
|
||||
0xafbd2350644eeacf,0xe5d1929ef90898fa,
|
||||
0xdbac6c247d62a583,0xdf45f746b74abf39,
|
||||
0x894bc396ce5da772,0x6b8bba8c328eb783,
|
||||
0xab9eb47c81f5114f,0x66ea92f3f326564,
|
||||
0xd686619ba27255a2,0xc80a537b0efefebd,
|
||||
0x8613fd0145877585,0xbd06742ce95f5f36,
|
||||
0xa798fc4196e952e7,0x2c48113823b73704,
|
||||
0xd17f3b51fca3a7a0,0xf75a15862ca504c5,
|
||||
0x82ef85133de648c4,0x9a984d73dbe722fb,
|
||||
0xa3ab66580d5fdaf5,0xc13e60d0d2e0ebba,
|
||||
0xcc963fee10b7d1b3,0x318df905079926a8,
|
||||
0xffbbcfe994e5c61f,0xfdf17746497f7052,
|
||||
0x9fd561f1fd0f9bd3,0xfeb6ea8bedefa633,
|
||||
0xc7caba6e7c5382c8,0xfe64a52ee96b8fc0,
|
||||
0xf9bd690a1b68637b,0x3dfdce7aa3c673b0,
|
||||
0x9c1661a651213e2d,0x6bea10ca65c084e,
|
||||
0xc31bfa0fe5698db8,0x486e494fcff30a62,
|
||||
0xf3e2f893dec3f126,0x5a89dba3c3efccfa,
|
||||
0x986ddb5c6b3a76b7,0xf89629465a75e01c,
|
||||
0xbe89523386091465,0xf6bbb397f1135823,
|
||||
0xee2ba6c0678b597f,0x746aa07ded582e2c,
|
||||
0x94db483840b717ef,0xa8c2a44eb4571cdc,
|
||||
0xba121a4650e4ddeb,0x92f34d62616ce413,
|
||||
0xe896a0d7e51e1566,0x77b020baf9c81d17,
|
||||
0x915e2486ef32cd60,0xace1474dc1d122e,
|
||||
0xb5b5ada8aaff80b8,0xd819992132456ba,
|
||||
0xe3231912d5bf60e6,0x10e1fff697ed6c69,
|
||||
0x8df5efabc5979c8f,0xca8d3ffa1ef463c1,
|
||||
0xb1736b96b6fd83b3,0xbd308ff8a6b17cb2,
|
||||
0xddd0467c64bce4a0,0xac7cb3f6d05ddbde,
|
||||
0x8aa22c0dbef60ee4,0x6bcdf07a423aa96b,
|
||||
0xad4ab7112eb3929d,0x86c16c98d2c953c6,
|
||||
0xd89d64d57a607744,0xe871c7bf077ba8b7,
|
||||
0x87625f056c7c4a8b,0x11471cd764ad4972,
|
||||
0xa93af6c6c79b5d2d,0xd598e40d3dd89bcf,
|
||||
0xd389b47879823479,0x4aff1d108d4ec2c3,
|
||||
0x843610cb4bf160cb,0xcedf722a585139ba,
|
||||
0xa54394fe1eedb8fe,0xc2974eb4ee658828,
|
||||
0xce947a3da6a9273e,0x733d226229feea32,
|
||||
0x811ccc668829b887,0x806357d5a3f525f,
|
||||
0xa163ff802a3426a8,0xca07c2dcb0cf26f7,
|
||||
0xc9bcff6034c13052,0xfc89b393dd02f0b5,
|
||||
0xfc2c3f3841f17c67,0xbbac2078d443ace2,
|
||||
0x9d9ba7832936edc0,0xd54b944b84aa4c0d,
|
||||
0xc5029163f384a931,0xa9e795e65d4df11,
|
||||
0xf64335bcf065d37d,0x4d4617b5ff4a16d5,
|
||||
0x99ea0196163fa42e,0x504bced1bf8e4e45,
|
||||
0xc06481fb9bcf8d39,0xe45ec2862f71e1d6,
|
||||
0xf07da27a82c37088,0x5d767327bb4e5a4c,
|
||||
0x964e858c91ba2655,0x3a6a07f8d510f86f,
|
||||
0xbbe226efb628afea,0x890489f70a55368b,
|
||||
0xeadab0aba3b2dbe5,0x2b45ac74ccea842e,
|
||||
0x92c8ae6b464fc96f,0x3b0b8bc90012929d,
|
||||
0xb77ada0617e3bbcb,0x9ce6ebb40173744,
|
||||
0xe55990879ddcaabd,0xcc420a6a101d0515,
|
||||
0x8f57fa54c2a9eab6,0x9fa946824a12232d,
|
||||
0xb32df8e9f3546564,0x47939822dc96abf9,
|
||||
0xdff9772470297ebd,0x59787e2b93bc56f7,
|
||||
0x8bfbea76c619ef36,0x57eb4edb3c55b65a,
|
||||
0xaefae51477a06b03,0xede622920b6b23f1,
|
||||
0xdab99e59958885c4,0xe95fab368e45eced,
|
||||
0x88b402f7fd75539b,0x11dbcb0218ebb414,
|
||||
0xaae103b5fcd2a881,0xd652bdc29f26a119,
|
||||
0xd59944a37c0752a2,0x4be76d3346f0495f,
|
||||
0x857fcae62d8493a5,0x6f70a4400c562ddb,
|
||||
0xa6dfbd9fb8e5b88e,0xcb4ccd500f6bb952,
|
||||
0xd097ad07a71f26b2,0x7e2000a41346a7a7,
|
||||
0x825ecc24c873782f,0x8ed400668c0c28c8,
|
||||
0xa2f67f2dfa90563b,0x728900802f0f32fa,
|
||||
0xcbb41ef979346bca,0x4f2b40a03ad2ffb9,
|
||||
0xfea126b7d78186bc,0xe2f610c84987bfa8,
|
||||
0x9f24b832e6b0f436,0xdd9ca7d2df4d7c9,
|
||||
0xc6ede63fa05d3143,0x91503d1c79720dbb,
|
||||
0xf8a95fcf88747d94,0x75a44c6397ce912a,
|
||||
0x9b69dbe1b548ce7c,0xc986afbe3ee11aba,
|
||||
0xc24452da229b021b,0xfbe85badce996168,
|
||||
0xf2d56790ab41c2a2,0xfae27299423fb9c3,
|
||||
0x97c560ba6b0919a5,0xdccd879fc967d41a,
|
||||
0xbdb6b8e905cb600f,0x5400e987bbc1c920,
|
||||
0xed246723473e3813,0x290123e9aab23b68,
|
||||
0x9436c0760c86e30b,0xf9a0b6720aaf6521,
|
||||
0xb94470938fa89bce,0xf808e40e8d5b3e69,
|
||||
0xe7958cb87392c2c2,0xb60b1d1230b20e04,
|
||||
0x90bd77f3483bb9b9,0xb1c6f22b5e6f48c2,
|
||||
0xb4ecd5f01a4aa828,0x1e38aeb6360b1af3,
|
||||
0xe2280b6c20dd5232,0x25c6da63c38de1b0,
|
||||
0x8d590723948a535f,0x579c487e5a38ad0e,
|
||||
0xb0af48ec79ace837,0x2d835a9df0c6d851,
|
||||
0xdcdb1b2798182244,0xf8e431456cf88e65,
|
||||
0x8a08f0f8bf0f156b,0x1b8e9ecb641b58ff,
|
||||
0xac8b2d36eed2dac5,0xe272467e3d222f3f,
|
||||
0xd7adf884aa879177,0x5b0ed81dcc6abb0f,
|
||||
0x86ccbb52ea94baea,0x98e947129fc2b4e9,
|
||||
0xa87fea27a539e9a5,0x3f2398d747b36224,
|
||||
0xd29fe4b18e88640e,0x8eec7f0d19a03aad,
|
||||
0x83a3eeeef9153e89,0x1953cf68300424ac,
|
||||
0xa48ceaaab75a8e2b,0x5fa8c3423c052dd7,
|
||||
0xcdb02555653131b6,0x3792f412cb06794d,
|
||||
0x808e17555f3ebf11,0xe2bbd88bbee40bd0,
|
||||
0xa0b19d2ab70e6ed6,0x5b6aceaeae9d0ec4,
|
||||
0xc8de047564d20a8b,0xf245825a5a445275,
|
||||
0xfb158592be068d2e,0xeed6e2f0f0d56712,
|
||||
0x9ced737bb6c4183d,0x55464dd69685606b,
|
||||
0xc428d05aa4751e4c,0xaa97e14c3c26b886,
|
||||
0xf53304714d9265df,0xd53dd99f4b3066a8,
|
||||
0x993fe2c6d07b7fab,0xe546a8038efe4029,
|
||||
0xbf8fdb78849a5f96,0xde98520472bdd033,
|
||||
0xef73d256a5c0f77c,0x963e66858f6d4440,
|
||||
0x95a8637627989aad,0xdde7001379a44aa8,
|
||||
0xbb127c53b17ec159,0x5560c018580d5d52,
|
||||
0xe9d71b689dde71af,0xaab8f01e6e10b4a6,
|
||||
0x9226712162ab070d,0xcab3961304ca70e8,
|
||||
0xb6b00d69bb55c8d1,0x3d607b97c5fd0d22,
|
||||
0xe45c10c42a2b3b05,0x8cb89a7db77c506a,
|
||||
0x8eb98a7a9a5b04e3,0x77f3608e92adb242,
|
||||
0xb267ed1940f1c61c,0x55f038b237591ed3,
|
||||
0xdf01e85f912e37a3,0x6b6c46dec52f6688,
|
||||
0x8b61313bbabce2c6,0x2323ac4b3b3da015,
|
||||
0xae397d8aa96c1b77,0xabec975e0a0d081a,
|
||||
0xd9c7dced53c72255,0x96e7bd358c904a21,
|
||||
0x881cea14545c7575,0x7e50d64177da2e54,
|
||||
0xaa242499697392d2,0xdde50bd1d5d0b9e9,
|
||||
0xd4ad2dbfc3d07787,0x955e4ec64b44e864,
|
||||
0x84ec3c97da624ab4,0xbd5af13bef0b113e,
|
||||
0xa6274bbdd0fadd61,0xecb1ad8aeacdd58e,
|
||||
0xcfb11ead453994ba,0x67de18eda5814af2,
|
||||
0x81ceb32c4b43fcf4,0x80eacf948770ced7,
|
||||
0xa2425ff75e14fc31,0xa1258379a94d028d,
|
||||
0xcad2f7f5359a3b3e,0x96ee45813a04330,
|
||||
0xfd87b5f28300ca0d,0x8bca9d6e188853fc,
|
||||
0x9e74d1b791e07e48,0x775ea264cf55347e,
|
||||
0xc612062576589dda,0x95364afe032a81a0,
|
||||
0xf79687aed3eec551,0x3a83ddbd83f52210,
|
||||
0x9abe14cd44753b52,0xc4926a9672793580,
|
||||
0xc16d9a0095928a27,0x75b7053c0f178400,
|
||||
0xf1c90080baf72cb1,0x5324c68b12dd6800,
|
||||
0x971da05074da7bee,0xd3f6fc16ebca8000,
|
||||
0xbce5086492111aea,0x88f4bb1ca6bd0000,
|
||||
0xec1e4a7db69561a5,0x2b31e9e3d0700000,
|
||||
0x9392ee8e921d5d07,0x3aff322e62600000,
|
||||
0xb877aa3236a4b449,0x9befeb9fad487c3,
|
||||
0xe69594bec44de15b,0x4c2ebe687989a9b4,
|
||||
0x901d7cf73ab0acd9,0xf9d37014bf60a11,
|
||||
0xb424dc35095cd80f,0x538484c19ef38c95,
|
||||
0xe12e13424bb40e13,0x2865a5f206b06fba,
|
||||
0x8cbccc096f5088cb,0xf93f87b7442e45d4,
|
||||
0xafebff0bcb24aafe,0xf78f69a51539d749,
|
||||
0xdbe6fecebdedd5be,0xb573440e5a884d1c,
|
||||
0x89705f4136b4a597,0x31680a88f8953031,
|
||||
0xabcc77118461cefc,0xfdc20d2b36ba7c3e,
|
||||
0xd6bf94d5e57a42bc,0x3d32907604691b4d,
|
||||
0x8637bd05af6c69b5,0xa63f9a49c2c1b110,
|
||||
0xa7c5ac471b478423,0xfcf80dc33721d54,
|
||||
0xd1b71758e219652b,0xd3c36113404ea4a9,
|
||||
0x83126e978d4fdf3b,0x645a1cac083126ea,
|
||||
0xa3d70a3d70a3d70a,0x3d70a3d70a3d70a4,
|
||||
0xcccccccccccccccc,0xcccccccccccccccd,
|
||||
0x8000000000000000,0x0,
|
||||
0xa000000000000000,0x0,
|
||||
0xc800000000000000,0x0,
|
||||
0xfa00000000000000,0x0,
|
||||
0x9c40000000000000,0x0,
|
||||
0xc350000000000000,0x0,
|
||||
0xf424000000000000,0x0,
|
||||
0x9896800000000000,0x0,
|
||||
0xbebc200000000000,0x0,
|
||||
0xee6b280000000000,0x0,
|
||||
0x9502f90000000000,0x0,
|
||||
0xba43b74000000000,0x0,
|
||||
0xe8d4a51000000000,0x0,
|
||||
0x9184e72a00000000,0x0,
|
||||
0xb5e620f480000000,0x0,
|
||||
0xe35fa931a0000000,0x0,
|
||||
0x8e1bc9bf04000000,0x0,
|
||||
0xb1a2bc2ec5000000,0x0,
|
||||
0xde0b6b3a76400000,0x0,
|
||||
0x8ac7230489e80000,0x0,
|
||||
0xad78ebc5ac620000,0x0,
|
||||
0xd8d726b7177a8000,0x0,
|
||||
0x878678326eac9000,0x0,
|
||||
0xa968163f0a57b400,0x0,
|
||||
0xd3c21bcecceda100,0x0,
|
||||
0x84595161401484a0,0x0,
|
||||
0xa56fa5b99019a5c8,0x0,
|
||||
0xcecb8f27f4200f3a,0x0,
|
||||
0x813f3978f8940984,0x4000000000000000,
|
||||
0xa18f07d736b90be5,0x5000000000000000,
|
||||
0xc9f2c9cd04674ede,0xa400000000000000,
|
||||
0xfc6f7c4045812296,0x4d00000000000000,
|
||||
0x9dc5ada82b70b59d,0xf020000000000000,
|
||||
0xc5371912364ce305,0x6c28000000000000,
|
||||
0xf684df56c3e01bc6,0xc732000000000000,
|
||||
0x9a130b963a6c115c,0x3c7f400000000000,
|
||||
0xc097ce7bc90715b3,0x4b9f100000000000,
|
||||
0xf0bdc21abb48db20,0x1e86d40000000000,
|
||||
0x96769950b50d88f4,0x1314448000000000,
|
||||
0xbc143fa4e250eb31,0x17d955a000000000,
|
||||
0xeb194f8e1ae525fd,0x5dcfab0800000000,
|
||||
0x92efd1b8d0cf37be,0x5aa1cae500000000,
|
||||
0xb7abc627050305ad,0xf14a3d9e40000000,
|
||||
0xe596b7b0c643c719,0x6d9ccd05d0000000,
|
||||
0x8f7e32ce7bea5c6f,0xe4820023a2000000,
|
||||
0xb35dbf821ae4f38b,0xdda2802c8a800000,
|
||||
0xe0352f62a19e306e,0xd50b2037ad200000,
|
||||
0x8c213d9da502de45,0x4526f422cc340000,
|
||||
0xaf298d050e4395d6,0x9670b12b7f410000,
|
||||
0xdaf3f04651d47b4c,0x3c0cdd765f114000,
|
||||
0x88d8762bf324cd0f,0xa5880a69fb6ac800,
|
||||
0xab0e93b6efee0053,0x8eea0d047a457a00,
|
||||
0xd5d238a4abe98068,0x72a4904598d6d880,
|
||||
0x85a36366eb71f041,0x47a6da2b7f864750,
|
||||
0xa70c3c40a64e6c51,0x999090b65f67d924,
|
||||
0xd0cf4b50cfe20765,0xfff4b4e3f741cf6d,
|
||||
0x82818f1281ed449f,0xbff8f10e7a8921a4,
|
||||
0xa321f2d7226895c7,0xaff72d52192b6a0d,
|
||||
0xcbea6f8ceb02bb39,0x9bf4f8a69f764490,
|
||||
0xfee50b7025c36a08,0x2f236d04753d5b4,
|
||||
0x9f4f2726179a2245,0x1d762422c946590,
|
||||
0xc722f0ef9d80aad6,0x424d3ad2b7b97ef5,
|
||||
0xf8ebad2b84e0d58b,0xd2e0898765a7deb2,
|
||||
0x9b934c3b330c8577,0x63cc55f49f88eb2f,
|
||||
0xc2781f49ffcfa6d5,0x3cbf6b71c76b25fb,
|
||||
0xf316271c7fc3908a,0x8bef464e3945ef7a,
|
||||
0x97edd871cfda3a56,0x97758bf0e3cbb5ac,
|
||||
0xbde94e8e43d0c8ec,0x3d52eeed1cbea317,
|
||||
0xed63a231d4c4fb27,0x4ca7aaa863ee4bdd,
|
||||
0x945e455f24fb1cf8,0x8fe8caa93e74ef6a,
|
||||
0xb975d6b6ee39e436,0xb3e2fd538e122b44,
|
||||
0xe7d34c64a9c85d44,0x60dbbca87196b616,
|
||||
0x90e40fbeea1d3a4a,0xbc8955e946fe31cd,
|
||||
0xb51d13aea4a488dd,0x6babab6398bdbe41,
|
||||
0xe264589a4dcdab14,0xc696963c7eed2dd1,
|
||||
0x8d7eb76070a08aec,0xfc1e1de5cf543ca2,
|
||||
0xb0de65388cc8ada8,0x3b25a55f43294bcb,
|
||||
0xdd15fe86affad912,0x49ef0eb713f39ebe,
|
||||
0x8a2dbf142dfcc7ab,0x6e3569326c784337,
|
||||
0xacb92ed9397bf996,0x49c2c37f07965404,
|
||||
0xd7e77a8f87daf7fb,0xdc33745ec97be906,
|
||||
0x86f0ac99b4e8dafd,0x69a028bb3ded71a3,
|
||||
0xa8acd7c0222311bc,0xc40832ea0d68ce0c,
|
||||
0xd2d80db02aabd62b,0xf50a3fa490c30190,
|
||||
0x83c7088e1aab65db,0x792667c6da79e0fa,
|
||||
0xa4b8cab1a1563f52,0x577001b891185938,
|
||||
0xcde6fd5e09abcf26,0xed4c0226b55e6f86,
|
||||
0x80b05e5ac60b6178,0x544f8158315b05b4,
|
||||
0xa0dc75f1778e39d6,0x696361ae3db1c721,
|
||||
0xc913936dd571c84c,0x3bc3a19cd1e38e9,
|
||||
0xfb5878494ace3a5f,0x4ab48a04065c723,
|
||||
0x9d174b2dcec0e47b,0x62eb0d64283f9c76,
|
||||
0xc45d1df942711d9a,0x3ba5d0bd324f8394,
|
||||
0xf5746577930d6500,0xca8f44ec7ee36479,
|
||||
0x9968bf6abbe85f20,0x7e998b13cf4e1ecb,
|
||||
0xbfc2ef456ae276e8,0x9e3fedd8c321a67e,
|
||||
0xefb3ab16c59b14a2,0xc5cfe94ef3ea101e,
|
||||
0x95d04aee3b80ece5,0xbba1f1d158724a12,
|
||||
0xbb445da9ca61281f,0x2a8a6e45ae8edc97,
|
||||
0xea1575143cf97226,0xf52d09d71a3293bd,
|
||||
0x924d692ca61be758,0x593c2626705f9c56,
|
||||
0xb6e0c377cfa2e12e,0x6f8b2fb00c77836c,
|
||||
0xe498f455c38b997a,0xb6dfb9c0f956447,
|
||||
0x8edf98b59a373fec,0x4724bd4189bd5eac,
|
||||
0xb2977ee300c50fe7,0x58edec91ec2cb657,
|
||||
0xdf3d5e9bc0f653e1,0x2f2967b66737e3ed,
|
||||
0x8b865b215899f46c,0xbd79e0d20082ee74,
|
||||
0xae67f1e9aec07187,0xecd8590680a3aa11,
|
||||
0xda01ee641a708de9,0xe80e6f4820cc9495,
|
||||
0x884134fe908658b2,0x3109058d147fdcdd,
|
||||
0xaa51823e34a7eede,0xbd4b46f0599fd415,
|
||||
0xd4e5e2cdc1d1ea96,0x6c9e18ac7007c91a,
|
||||
0x850fadc09923329e,0x3e2cf6bc604ddb0,
|
||||
0xa6539930bf6bff45,0x84db8346b786151c,
|
||||
0xcfe87f7cef46ff16,0xe612641865679a63,
|
||||
0x81f14fae158c5f6e,0x4fcb7e8f3f60c07e,
|
||||
0xa26da3999aef7749,0xe3be5e330f38f09d,
|
||||
0xcb090c8001ab551c,0x5cadf5bfd3072cc5,
|
||||
0xfdcb4fa002162a63,0x73d9732fc7c8f7f6,
|
||||
0x9e9f11c4014dda7e,0x2867e7fddcdd9afa,
|
||||
0xc646d63501a1511d,0xb281e1fd541501b8,
|
||||
0xf7d88bc24209a565,0x1f225a7ca91a4226,
|
||||
0x9ae757596946075f,0x3375788de9b06958,
|
||||
0xc1a12d2fc3978937,0x52d6b1641c83ae,
|
||||
0xf209787bb47d6b84,0xc0678c5dbd23a49a,
|
||||
0x9745eb4d50ce6332,0xf840b7ba963646e0,
|
||||
0xbd176620a501fbff,0xb650e5a93bc3d898,
|
||||
0xec5d3fa8ce427aff,0xa3e51f138ab4cebe,
|
||||
0x93ba47c980e98cdf,0xc66f336c36b10137,
|
||||
0xb8a8d9bbe123f017,0xb80b0047445d4184,
|
||||
0xe6d3102ad96cec1d,0xa60dc059157491e5,
|
||||
0x9043ea1ac7e41392,0x87c89837ad68db2f,
|
||||
0xb454e4a179dd1877,0x29babe4598c311fb,
|
||||
0xe16a1dc9d8545e94,0xf4296dd6fef3d67a,
|
||||
0x8ce2529e2734bb1d,0x1899e4a65f58660c,
|
||||
0xb01ae745b101e9e4,0x5ec05dcff72e7f8f,
|
||||
0xdc21a1171d42645d,0x76707543f4fa1f73,
|
||||
0x899504ae72497eba,0x6a06494a791c53a8,
|
||||
0xabfa45da0edbde69,0x487db9d17636892,
|
||||
0xd6f8d7509292d603,0x45a9d2845d3c42b6,
|
||||
0x865b86925b9bc5c2,0xb8a2392ba45a9b2,
|
||||
0xa7f26836f282b732,0x8e6cac7768d7141e,
|
||||
0xd1ef0244af2364ff,0x3207d795430cd926,
|
||||
0x8335616aed761f1f,0x7f44e6bd49e807b8,
|
||||
0xa402b9c5a8d3a6e7,0x5f16206c9c6209a6,
|
||||
0xcd036837130890a1,0x36dba887c37a8c0f,
|
||||
0x802221226be55a64,0xc2494954da2c9789,
|
||||
0xa02aa96b06deb0fd,0xf2db9baa10b7bd6c,
|
||||
0xc83553c5c8965d3d,0x6f92829494e5acc7,
|
||||
0xfa42a8b73abbf48c,0xcb772339ba1f17f9,
|
||||
0x9c69a97284b578d7,0xff2a760414536efb,
|
||||
0xc38413cf25e2d70d,0xfef5138519684aba,
|
||||
0xf46518c2ef5b8cd1,0x7eb258665fc25d69,
|
||||
0x98bf2f79d5993802,0xef2f773ffbd97a61,
|
||||
0xbeeefb584aff8603,0xaafb550ffacfd8fa,
|
||||
0xeeaaba2e5dbf6784,0x95ba2a53f983cf38,
|
||||
0x952ab45cfa97a0b2,0xdd945a747bf26183,
|
||||
0xba756174393d88df,0x94f971119aeef9e4,
|
||||
0xe912b9d1478ceb17,0x7a37cd5601aab85d,
|
||||
0x91abb422ccb812ee,0xac62e055c10ab33a,
|
||||
0xb616a12b7fe617aa,0x577b986b314d6009,
|
||||
0xe39c49765fdf9d94,0xed5a7e85fda0b80b,
|
||||
0x8e41ade9fbebc27d,0x14588f13be847307,
|
||||
0xb1d219647ae6b31c,0x596eb2d8ae258fc8,
|
||||
0xde469fbd99a05fe3,0x6fca5f8ed9aef3bb,
|
||||
0x8aec23d680043bee,0x25de7bb9480d5854,
|
||||
0xada72ccc20054ae9,0xaf561aa79a10ae6a,
|
||||
0xd910f7ff28069da4,0x1b2ba1518094da04,
|
||||
0x87aa9aff79042286,0x90fb44d2f05d0842,
|
||||
0xa99541bf57452b28,0x353a1607ac744a53,
|
||||
0xd3fa922f2d1675f2,0x42889b8997915ce8,
|
||||
0x847c9b5d7c2e09b7,0x69956135febada11,
|
||||
0xa59bc234db398c25,0x43fab9837e699095,
|
||||
0xcf02b2c21207ef2e,0x94f967e45e03f4bb,
|
||||
0x8161afb94b44f57d,0x1d1be0eebac278f5,
|
||||
0xa1ba1ba79e1632dc,0x6462d92a69731732,
|
||||
0xca28a291859bbf93,0x7d7b8f7503cfdcfe,
|
||||
0xfcb2cb35e702af78,0x5cda735244c3d43e,
|
||||
0x9defbf01b061adab,0x3a0888136afa64a7,
|
||||
0xc56baec21c7a1916,0x88aaa1845b8fdd0,
|
||||
0xf6c69a72a3989f5b,0x8aad549e57273d45,
|
||||
0x9a3c2087a63f6399,0x36ac54e2f678864b,
|
||||
0xc0cb28a98fcf3c7f,0x84576a1bb416a7dd,
|
||||
0xf0fdf2d3f3c30b9f,0x656d44a2a11c51d5,
|
||||
0x969eb7c47859e743,0x9f644ae5a4b1b325,
|
||||
0xbc4665b596706114,0x873d5d9f0dde1fee,
|
||||
0xeb57ff22fc0c7959,0xa90cb506d155a7ea,
|
||||
0x9316ff75dd87cbd8,0x9a7f12442d588f2,
|
||||
0xb7dcbf5354e9bece,0xc11ed6d538aeb2f,
|
||||
0xe5d3ef282a242e81,0x8f1668c8a86da5fa,
|
||||
0x8fa475791a569d10,0xf96e017d694487bc,
|
||||
0xb38d92d760ec4455,0x37c981dcc395a9ac,
|
||||
0xe070f78d3927556a,0x85bbe253f47b1417,
|
||||
0x8c469ab843b89562,0x93956d7478ccec8e,
|
||||
0xaf58416654a6babb,0x387ac8d1970027b2,
|
||||
0xdb2e51bfe9d0696a,0x6997b05fcc0319e,
|
||||
0x88fcf317f22241e2,0x441fece3bdf81f03,
|
||||
0xab3c2fddeeaad25a,0xd527e81cad7626c3,
|
||||
0xd60b3bd56a5586f1,0x8a71e223d8d3b074,
|
||||
0x85c7056562757456,0xf6872d5667844e49,
|
||||
0xa738c6bebb12d16c,0xb428f8ac016561db,
|
||||
0xd106f86e69d785c7,0xe13336d701beba52,
|
||||
0x82a45b450226b39c,0xecc0024661173473,
|
||||
0xa34d721642b06084,0x27f002d7f95d0190,
|
||||
0xcc20ce9bd35c78a5,0x31ec038df7b441f4,
|
||||
0xff290242c83396ce,0x7e67047175a15271,
|
||||
0x9f79a169bd203e41,0xf0062c6e984d386,
|
||||
0xc75809c42c684dd1,0x52c07b78a3e60868,
|
||||
0xf92e0c3537826145,0xa7709a56ccdf8a82,
|
||||
0x9bbcc7a142b17ccb,0x88a66076400bb691,
|
||||
0xc2abf989935ddbfe,0x6acff893d00ea435,
|
||||
0xf356f7ebf83552fe,0x583f6b8c4124d43,
|
||||
0x98165af37b2153de,0xc3727a337a8b704a,
|
||||
0xbe1bf1b059e9a8d6,0x744f18c0592e4c5c,
|
||||
0xeda2ee1c7064130c,0x1162def06f79df73,
|
||||
0x9485d4d1c63e8be7,0x8addcb5645ac2ba8,
|
||||
0xb9a74a0637ce2ee1,0x6d953e2bd7173692,
|
||||
0xe8111c87c5c1ba99,0xc8fa8db6ccdd0437,
|
||||
0x910ab1d4db9914a0,0x1d9c9892400a22a2,
|
||||
0xb54d5e4a127f59c8,0x2503beb6d00cab4b,
|
||||
0xe2a0b5dc971f303a,0x2e44ae64840fd61d,
|
||||
0x8da471a9de737e24,0x5ceaecfed289e5d2,
|
||||
0xb10d8e1456105dad,0x7425a83e872c5f47,
|
||||
0xdd50f1996b947518,0xd12f124e28f77719,
|
||||
0x8a5296ffe33cc92f,0x82bd6b70d99aaa6f,
|
||||
0xace73cbfdc0bfb7b,0x636cc64d1001550b,
|
||||
0xd8210befd30efa5a,0x3c47f7e05401aa4e,
|
||||
0x8714a775e3e95c78,0x65acfaec34810a71,
|
||||
0xa8d9d1535ce3b396,0x7f1839a741a14d0d,
|
||||
0xd31045a8341ca07c,0x1ede48111209a050,
|
||||
0x83ea2b892091e44d,0x934aed0aab460432,
|
||||
0xa4e4b66b68b65d60,0xf81da84d5617853f,
|
||||
0xce1de40642e3f4b9,0x36251260ab9d668e,
|
||||
0x80d2ae83e9ce78f3,0xc1d72b7c6b426019,
|
||||
0xa1075a24e4421730,0xb24cf65b8612f81f,
|
||||
0xc94930ae1d529cfc,0xdee033f26797b627,
|
||||
0xfb9b7cd9a4a7443c,0x169840ef017da3b1,
|
||||
0x9d412e0806e88aa5,0x8e1f289560ee864e,
|
||||
0xc491798a08a2ad4e,0xf1a6f2bab92a27e2,
|
||||
0xf5b5d7ec8acb58a2,0xae10af696774b1db,
|
||||
0x9991a6f3d6bf1765,0xacca6da1e0a8ef29,
|
||||
0xbff610b0cc6edd3f,0x17fd090a58d32af3,
|
||||
0xeff394dcff8a948e,0xddfc4b4cef07f5b0,
|
||||
0x95f83d0a1fb69cd9,0x4abdaf101564f98e,
|
||||
0xbb764c4ca7a4440f,0x9d6d1ad41abe37f1,
|
||||
0xea53df5fd18d5513,0x84c86189216dc5ed,
|
||||
0x92746b9be2f8552c,0x32fd3cf5b4e49bb4,
|
||||
0xb7118682dbb66a77,0x3fbc8c33221dc2a1,
|
||||
0xe4d5e82392a40515,0xfabaf3feaa5334a,
|
||||
0x8f05b1163ba6832d,0x29cb4d87f2a7400e,
|
||||
0xb2c71d5bca9023f8,0x743e20e9ef511012,
|
||||
0xdf78e4b2bd342cf6,0x914da9246b255416,
|
||||
0x8bab8eefb6409c1a,0x1ad089b6c2f7548e,
|
||||
0xae9672aba3d0c320,0xa184ac2473b529b1,
|
||||
0xda3c0f568cc4f3e8,0xc9e5d72d90a2741e,
|
||||
0x8865899617fb1871,0x7e2fa67c7a658892,
|
||||
0xaa7eebfb9df9de8d,0xddbb901b98feeab7,
|
||||
0xd51ea6fa85785631,0x552a74227f3ea565,
|
||||
0x8533285c936b35de,0xd53a88958f87275f,
|
||||
0xa67ff273b8460356,0x8a892abaf368f137,
|
||||
0xd01fef10a657842c,0x2d2b7569b0432d85,
|
||||
0x8213f56a67f6b29b,0x9c3b29620e29fc73,
|
||||
0xa298f2c501f45f42,0x8349f3ba91b47b8f,
|
||||
0xcb3f2f7642717713,0x241c70a936219a73,
|
||||
0xfe0efb53d30dd4d7,0xed238cd383aa0110,
|
||||
0x9ec95d1463e8a506,0xf4363804324a40aa,
|
||||
0xc67bb4597ce2ce48,0xb143c6053edcd0d5,
|
||||
0xf81aa16fdc1b81da,0xdd94b7868e94050a,
|
||||
0x9b10a4e5e9913128,0xca7cf2b4191c8326,
|
||||
0xc1d4ce1f63f57d72,0xfd1c2f611f63a3f0,
|
||||
0xf24a01a73cf2dccf,0xbc633b39673c8cec,
|
||||
0x976e41088617ca01,0xd5be0503e085d813,
|
||||
0xbd49d14aa79dbc82,0x4b2d8644d8a74e18,
|
||||
0xec9c459d51852ba2,0xddf8e7d60ed1219e,
|
||||
0x93e1ab8252f33b45,0xcabb90e5c942b503,
|
||||
0xb8da1662e7b00a17,0x3d6a751f3b936243,
|
||||
0xe7109bfba19c0c9d,0xcc512670a783ad4,
|
||||
0x906a617d450187e2,0x27fb2b80668b24c5,
|
||||
0xb484f9dc9641e9da,0xb1f9f660802dedf6,
|
||||
0xe1a63853bbd26451,0x5e7873f8a0396973,
|
||||
0x8d07e33455637eb2,0xdb0b487b6423e1e8,
|
||||
0xb049dc016abc5e5f,0x91ce1a9a3d2cda62,
|
||||
0xdc5c5301c56b75f7,0x7641a140cc7810fb,
|
||||
0x89b9b3e11b6329ba,0xa9e904c87fcb0a9d,
|
||||
0xac2820d9623bf429,0x546345fa9fbdcd44,
|
||||
0xd732290fbacaf133,0xa97c177947ad4095,
|
||||
0x867f59a9d4bed6c0,0x49ed8eabcccc485d,
|
||||
0xa81f301449ee8c70,0x5c68f256bfff5a74,
|
||||
0xd226fc195c6a2f8c,0x73832eec6fff3111,
|
||||
0x83585d8fd9c25db7,0xc831fd53c5ff7eab,
|
||||
0xa42e74f3d032f525,0xba3e7ca8b77f5e55,
|
||||
0xcd3a1230c43fb26f,0x28ce1bd2e55f35eb,
|
||||
0x80444b5e7aa7cf85,0x7980d163cf5b81b3,
|
||||
0xa0555e361951c366,0xd7e105bcc332621f,
|
||||
0xc86ab5c39fa63440,0x8dd9472bf3fefaa7,
|
||||
0xfa856334878fc150,0xb14f98f6f0feb951,
|
||||
0x9c935e00d4b9d8d2,0x6ed1bf9a569f33d3,
|
||||
0xc3b8358109e84f07,0xa862f80ec4700c8,
|
||||
0xf4a642e14c6262c8,0xcd27bb612758c0fa,
|
||||
0x98e7e9cccfbd7dbd,0x8038d51cb897789c,
|
||||
0xbf21e44003acdd2c,0xe0470a63e6bd56c3,
|
||||
0xeeea5d5004981478,0x1858ccfce06cac74,
|
||||
0x95527a5202df0ccb,0xf37801e0c43ebc8,
|
||||
0xbaa718e68396cffd,0xd30560258f54e6ba,
|
||||
0xe950df20247c83fd,0x47c6b82ef32a2069,
|
||||
0x91d28b7416cdd27e,0x4cdc331d57fa5441,
|
||||
0xb6472e511c81471d,0xe0133fe4adf8e952,
|
||||
0xe3d8f9e563a198e5,0x58180fddd97723a6,
|
||||
0x8e679c2f5e44ff8f,0x570f09eaa7ea7648,};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
263
include/fast_float/float_common.h
Normal file
263
include/fast_float/float_common.h
Normal file
@ -0,0 +1,263 @@
|
||||
#ifndef FASTFLOAT_FLOAT_COMMON_H
|
||||
#define FASTFLOAT_FLOAT_COMMON_H
|
||||
|
||||
#include <cfloat>
|
||||
#include <cstdint>
|
||||
#ifndef _WIN32
|
||||
// strcasecmp, strncasecmp
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define FASTFLOAT_VISUAL_STUDIO 1
|
||||
#endif
|
||||
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
#define fastfloat_really_inline __forceinline
|
||||
#else
|
||||
#define fastfloat_really_inline inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define fastfloat_strcasecmp _stricmp
|
||||
#define fastfloat_strncasecmp _strnicmp
|
||||
#else
|
||||
#define fastfloat_strcasecmp strcasecmp
|
||||
#define fastfloat_strncasecmp strncasecmp
|
||||
#endif
|
||||
namespace fast_float {
|
||||
#ifndef FLT_EVAL_METHOD
|
||||
#error "FLT_EVAL_METHOD should be defined, please include cfloat."
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool is_space(uint8_t c) {
|
||||
static const bool table[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
return table[c];
|
||||
}
|
||||
|
||||
namespace {
|
||||
constexpr uint32_t max_digits = 768;
|
||||
|
||||
constexpr int32_t decimal_point_range = 2047;
|
||||
} // namespace
|
||||
|
||||
|
||||
struct value128 {
|
||||
uint64_t low;
|
||||
uint64_t high;
|
||||
value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {}
|
||||
value128() : low(0), high(0) {}
|
||||
};
|
||||
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
fastfloat_really_inline
|
||||
int leading_zeroes(uint64_t input_num) {
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
unsigned long leading_zero = 0;
|
||||
// Search the mask data from most significant bit (MSB)
|
||||
// to least significant bit (LSB) for a set bit (1).
|
||||
if (_BitScanReverse64(&leading_zero, input_num))
|
||||
return (int)(63 - leading_zero);
|
||||
else
|
||||
return 64;
|
||||
#else
|
||||
return __builtin_clzll(input_num);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
#include <intrin.h>
|
||||
|
||||
#if !defined(_M_X64) && !defined(_M_ARM64)// _umul128 for x86, arm
|
||||
// this is a slow emulation routine for 32-bit Windows
|
||||
//
|
||||
fastfloat_really_inline uint64_t __emulu(uint32_t x, uint32_t y) {
|
||||
return x * (uint64_t)y;
|
||||
}
|
||||
fastfloat_really_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) {
|
||||
uint64_t ad = __emulu((uint32_t)(ab >> 32), (uint32_t)cd);
|
||||
uint64_t bd = __emulu((uint32_t)ab, (uint32_t)cd);
|
||||
uint64_t adbc = ad + __emulu((uint32_t)ab, (uint32_t)(cd >> 32));
|
||||
uint64_t adbc_carry = !!(adbc < ad);
|
||||
uint64_t lo = bd + (adbc << 32);
|
||||
*hi = __emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) +
|
||||
(adbc_carry << 32) + !!(lo < bd);
|
||||
return lo;
|
||||
}
|
||||
#endif
|
||||
|
||||
fastfloat_really_inline value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
||||
value128 answer;
|
||||
#ifdef _M_ARM64
|
||||
// ARM64 has native support for 64-bit multiplications, no need to emultate
|
||||
answer.high = __umulh(value1, value2);
|
||||
answer.low = value1 * value2;
|
||||
#else
|
||||
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
|
||||
#endif // _M_ARM64
|
||||
return answer;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// compute value1 * value2
|
||||
fastfloat_really_inline
|
||||
value128 full_multiplication(uint64_t value1, uint64_t value2) {
|
||||
value128 answer;
|
||||
__uint128_t r = ((__uint128_t)value1) * value2;
|
||||
answer.low = uint64_t(r);
|
||||
answer.high = uint64_t(r >> 64);
|
||||
return answer;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct adjusted_mantissa {
|
||||
uint64_t mantissa;
|
||||
int power2;
|
||||
adjusted_mantissa() : mantissa(0), power2(0) {}
|
||||
};
|
||||
|
||||
struct decimal {
|
||||
uint32_t num_digits;
|
||||
int32_t decimal_point;
|
||||
bool negative;
|
||||
bool truncated;
|
||||
uint8_t digits[max_digits];
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct binary_format {
|
||||
static constexpr int mantissa_explicit_bits();
|
||||
static constexpr int minimum_exponent();
|
||||
static constexpr int infinite_power();
|
||||
static constexpr int sign_index();
|
||||
static constexpr int min_exponent_fast_path();
|
||||
static constexpr int max_exponent_fast_path();
|
||||
static constexpr int max_exponent_round_to_even();
|
||||
static constexpr int min_exponent_round_to_even();
|
||||
static constexpr uint64_t max_mantissa_fast_path();
|
||||
static constexpr T exact_power_of_ten(int64_t power);
|
||||
constexpr static double powers_of_ten_double[] = {
|
||||
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
|
||||
1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
|
||||
constexpr static float powers_of_ten_float[] = {
|
||||
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10};
|
||||
};
|
||||
|
||||
template <>
|
||||
constexpr int binary_format<double>::mantissa_explicit_bits() {
|
||||
return 52;
|
||||
}
|
||||
template <>
|
||||
constexpr int binary_format<float>::mantissa_explicit_bits() {
|
||||
return 23;
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr int binary_format<double>::max_exponent_round_to_even() {
|
||||
return 23;
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr int binary_format<float>::max_exponent_round_to_even() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
constexpr int binary_format<double>::min_exponent_round_to_even() {
|
||||
return -4;
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr int binary_format<float>::min_exponent_round_to_even() {
|
||||
return -17;
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr int binary_format<double>::minimum_exponent() {
|
||||
return -1023;
|
||||
}
|
||||
template <>
|
||||
constexpr int binary_format<float>::minimum_exponent() {
|
||||
return -127;
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr int binary_format<double>::infinite_power() {
|
||||
return 0x7FF;
|
||||
}
|
||||
template <>
|
||||
constexpr int binary_format<float>::infinite_power() {
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr int binary_format<double>::sign_index() {
|
||||
return 63;
|
||||
}
|
||||
template <>
|
||||
constexpr int binary_format<float>::sign_index() {
|
||||
return 31;
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr int binary_format<double>::min_exponent_fast_path() {
|
||||
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
|
||||
return 0;
|
||||
#else
|
||||
return -22;
|
||||
#endif
|
||||
}
|
||||
template <>
|
||||
constexpr int binary_format<float>::min_exponent_fast_path() {
|
||||
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
|
||||
return 0;
|
||||
#else
|
||||
return -10;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
constexpr int binary_format<double>::max_exponent_fast_path() {
|
||||
return 22;
|
||||
}
|
||||
template <>
|
||||
constexpr int binary_format<float>::max_exponent_fast_path() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
|
||||
return uint64_t(2) << mantissa_explicit_bits();
|
||||
}
|
||||
template <>
|
||||
constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
|
||||
return uint64_t(2) << mantissa_explicit_bits();
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr double binary_format<double>::exact_power_of_ten(int64_t power) {
|
||||
return powers_of_ten_double[power];
|
||||
}
|
||||
template <>
|
||||
constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
|
||||
|
||||
return powers_of_ten_float[power];
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace fast_float
|
||||
|
||||
#endif
|
||||
116
include/fast_float/parse_number.h
Normal file
116
include/fast_float/parse_number.h
Normal file
@ -0,0 +1,116 @@
|
||||
#ifndef FASTFLOAT_PARSE_NUMBER_H
|
||||
#define FASTFLOAT_PARSE_NUMBER_H
|
||||
#include "ascii_number.h"
|
||||
#include "decimal_to_binary.h"
|
||||
#include "thompson_tao.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <system_error>
|
||||
|
||||
namespace fast_float {
|
||||
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Special case +inf, -inf, nan, infinity, -infinity.
|
||||
* The case comparisons could be made much faster given that we know that the
|
||||
* strings a null-free and fixed.
|
||||
**/
|
||||
template <typename T>
|
||||
from_chars_result parse_infnan(const char *first, const char *last, T &value) noexcept {
|
||||
from_chars_result answer;
|
||||
answer.ec = std::errc(); // be optimistic
|
||||
if (last - first >= 3) {
|
||||
if (fastfloat_strncasecmp(first, "nan", 3) == 0) {
|
||||
answer.ptr = first + 3;
|
||||
value = std::numeric_limits<T>::quiet_NaN();
|
||||
return answer;
|
||||
}
|
||||
if (fastfloat_strncasecmp(first, "inf", 3) == 0) {
|
||||
|
||||
if ((last - first >= 8) && (fastfloat_strncasecmp(first, "infinity", 8) == 0)) {
|
||||
answer.ptr = first + 8;
|
||||
} else {
|
||||
answer.ptr = first + 3;
|
||||
}
|
||||
value = std::numeric_limits<T>::infinity();
|
||||
return answer;
|
||||
}
|
||||
if (last - first >= 4) {
|
||||
if ((fastfloat_strncasecmp(first, "+nan", 4) == 0) || (fastfloat_strncasecmp(first, "-nan", 4) == 0)) {
|
||||
answer.ptr = first + 4;
|
||||
value = std::numeric_limits<T>::quiet_NaN();
|
||||
if (first[0] == '-') {
|
||||
value = -value;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
if ((fastfloat_strncasecmp(first, "+inf", 4) == 0) || (fastfloat_strncasecmp(first, "-inf", 4) == 0)) {
|
||||
if ((last - first >= 8) && (fastfloat_strncasecmp(first + 1, "infinity", 8) == 0)) {
|
||||
answer.ptr = first + 9;
|
||||
} else {
|
||||
answer.ptr = first + 4;
|
||||
}
|
||||
value = std::numeric_limits<T>::infinity();
|
||||
if (first[0] == '-') {
|
||||
value = -value;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
}
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
return answer;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
from_chars_result from_chars(const char *first, const char *last,
|
||||
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
||||
static_assert (std::is_same<T, double>::value || std::is_same<T, float>::value, "only float and double are supported");
|
||||
|
||||
|
||||
from_chars_result answer;
|
||||
while ((first != last) && fast_float::is_space(*first)) {
|
||||
first++;
|
||||
}
|
||||
if (first == last) {
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
}
|
||||
parsed_number_string pns = parse_number_string(first, last, fmt);
|
||||
if (!pns.valid) {
|
||||
return parse_infnan(first, last, value);
|
||||
}
|
||||
answer.ec = std::errc(); // be optimistic
|
||||
answer.ptr = pns.lastmatch;
|
||||
|
||||
if (binary_format<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && pns.mantissa <=binary_format<T>::max_mantissa_fast_path()) {
|
||||
value = T(pns.mantissa);
|
||||
if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); }
|
||||
else { value = value * binary_format<T>::exact_power_of_ten(pns.exponent); }
|
||||
if (pns.negative) { value = -value; }
|
||||
return answer;
|
||||
}
|
||||
adjusted_mantissa am = pns.too_many_digits ? parse_long_mantissa<binary_format<T>>(first,last) : compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
|
||||
if(am.power2 < 0) {
|
||||
am = parse_long_mantissa<binary_format<T>>(first,last);
|
||||
}
|
||||
uint64_t word = am.mantissa;
|
||||
word |= uint64_t(am.power2) << binary_format<T>::mantissa_explicit_bits();
|
||||
word = pns.negative
|
||||
? word | (uint64_t(1) << binary_format<T>::sign_index()) : word;
|
||||
memcpy(&value, &word, sizeof(T));
|
||||
return answer;
|
||||
}
|
||||
|
||||
} // namespace fast_float
|
||||
|
||||
#endif
|
||||
374
include/fast_float/thompson_tao.h
Normal file
374
include/fast_float/thompson_tao.h
Normal file
@ -0,0 +1,374 @@
|
||||
#ifndef FASTFLOAT_GENERIC_DECIMAL_TO_BINARY_H
|
||||
#define FASTFLOAT_GENERIC_DECIMAL_TO_BINARY_H
|
||||
|
||||
/**
|
||||
* This code is meant to handle the case where we have more than 19 digits.
|
||||
*
|
||||
* Based on work by Nigel Tao (at https://github.com/google/wuffs/)
|
||||
* who credits Ken Thompson for the design (via a reference to the Go source
|
||||
* code). See
|
||||
* https://github.com/google/wuffs/blob/aa46859ea40c72516deffa1b146121952d6dfd3b/internal/cgen/base/floatconv-submodule-data.c
|
||||
* https://github.com/google/wuffs/blob/46cd8105f47ca07ae2ba8e6a7818ef9c0df6c152/internal/cgen/base/floatconv-submodule-code.c
|
||||
* It is probably not very fast but it is a fallback that should almost never
|
||||
* be used in reallife.
|
||||
**/
|
||||
#include "ascii_number.h"
|
||||
#include "decimal_to_binary.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace fast_float {
|
||||
|
||||
namespace {
|
||||
|
||||
// remove all final zeroes
|
||||
inline void trim(decimal &h) {
|
||||
while ((h.num_digits > 0) && (h.digits[h.num_digits - 1] == 0)) {
|
||||
h.num_digits--;
|
||||
}
|
||||
}
|
||||
|
||||
/** If you ever want to see what is going on, the following function might prove handy:
|
||||
* **/
|
||||
void print(const decimal d, int32_t exp2 = 0) {
|
||||
printf("0.");
|
||||
for(size_t i = 0; i < d.num_digits; i++) {
|
||||
printf("%d", int(d.digits[i]));
|
||||
}
|
||||
printf(" * 10 **%d ", d.decimal_point);
|
||||
printf(" * 2 **%d ", exp2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
uint32_t number_of_digits_decimal_left_shift(decimal &h, uint32_t shift) {
|
||||
shift &= 63;
|
||||
const static uint16_t number_of_digits_decimal_left_shift_table[65] = {
|
||||
0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817,
|
||||
0x181D, 0x2024, 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067,
|
||||
0x3073, 0x3080, 0x388E, 0x389C, 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF,
|
||||
0x4902, 0x4915, 0x4929, 0x513E, 0x5153, 0x5169, 0x5180, 0x5998, 0x59B0,
|
||||
0x59C9, 0x61E3, 0x61FD, 0x6218, 0x6A34, 0x6A50, 0x6A6D, 0x6A8B, 0x72AA,
|
||||
0x72C9, 0x72E9, 0x7B0A, 0x7B2B, 0x7B4D, 0x8370, 0x8393, 0x83B7, 0x83DC,
|
||||
0x8C02, 0x8C28, 0x8C4F, 0x9477, 0x949F, 0x94C8, 0x9CF2, 0x051C, 0x051C,
|
||||
0x051C, 0x051C,
|
||||
};
|
||||
uint32_t x_a = number_of_digits_decimal_left_shift_table[shift];
|
||||
uint32_t x_b = number_of_digits_decimal_left_shift_table[shift + 1];
|
||||
uint32_t num_new_digits = x_a >> 11;
|
||||
uint32_t pow5_a = 0x7FF & x_a;
|
||||
uint32_t pow5_b = 0x7FF & x_b;
|
||||
const static uint8_t
|
||||
number_of_digits_decimal_left_shift_table_powers_of_5[0x051C] = {
|
||||
5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3,
|
||||
9, 0, 6, 2, 5, 1, 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8,
|
||||
1, 2, 5, 2, 4, 4, 1, 4, 0, 6, 2, 5, 1, 2, 2, 0, 7, 0, 3, 1, 2, 5, 6, 1,
|
||||
0, 3, 5, 1, 5, 6, 2, 5, 3, 0, 5, 1, 7, 5, 7, 8, 1, 2, 5, 1, 5, 2, 5, 8,
|
||||
7, 8, 9, 0, 6, 2, 5, 7, 6, 2, 9, 3, 9, 4, 5, 3, 1, 2, 5, 3, 8, 1, 4, 6,
|
||||
9, 7, 2, 6, 5, 6, 2, 5, 1, 9, 0, 7, 3, 4, 8, 6, 3, 2, 8, 1, 2, 5, 9, 5,
|
||||
3, 6, 7, 4, 3, 1, 6, 4, 0, 6, 2, 5, 4, 7, 6, 8, 3, 7, 1, 5, 8, 2, 0, 3,
|
||||
1, 2, 5, 2, 3, 8, 4, 1, 8, 5, 7, 9, 1, 0, 1, 5, 6, 2, 5, 1, 1, 9, 2, 0,
|
||||
9, 2, 8, 9, 5, 5, 0, 7, 8, 1, 2, 5, 5, 9, 6, 0, 4, 6, 4, 4, 7, 7, 5, 3,
|
||||
9, 0, 6, 2, 5, 2, 9, 8, 0, 2, 3, 2, 2, 3, 8, 7, 6, 9, 5, 3, 1, 2, 5, 1,
|
||||
4, 9, 0, 1, 1, 6, 1, 1, 9, 3, 8, 4, 7, 6, 5, 6, 2, 5, 7, 4, 5, 0, 5, 8,
|
||||
0, 5, 9, 6, 9, 2, 3, 8, 2, 8, 1, 2, 5, 3, 7, 2, 5, 2, 9, 0, 2, 9, 8, 4,
|
||||
6, 1, 9, 1, 4, 0, 6, 2, 5, 1, 8, 6, 2, 6, 4, 5, 1, 4, 9, 2, 3, 0, 9, 5,
|
||||
7, 0, 3, 1, 2, 5, 9, 3, 1, 3, 2, 2, 5, 7, 4, 6, 1, 5, 4, 7, 8, 5, 1, 5,
|
||||
6, 2, 5, 4, 6, 5, 6, 6, 1, 2, 8, 7, 3, 0, 7, 7, 3, 9, 2, 5, 7, 8, 1, 2,
|
||||
5, 2, 3, 2, 8, 3, 0, 6, 4, 3, 6, 5, 3, 8, 6, 9, 6, 2, 8, 9, 0, 6, 2, 5,
|
||||
1, 1, 6, 4, 1, 5, 3, 2, 1, 8, 2, 6, 9, 3, 4, 8, 1, 4, 4, 5, 3, 1, 2, 5,
|
||||
5, 8, 2, 0, 7, 6, 6, 0, 9, 1, 3, 4, 6, 7, 4, 0, 7, 2, 2, 6, 5, 6, 2, 5,
|
||||
2, 9, 1, 0, 3, 8, 3, 0, 4, 5, 6, 7, 3, 3, 7, 0, 3, 6, 1, 3, 2, 8, 1, 2,
|
||||
5, 1, 4, 5, 5, 1, 9, 1, 5, 2, 2, 8, 3, 6, 6, 8, 5, 1, 8, 0, 6, 6, 4, 0,
|
||||
6, 2, 5, 7, 2, 7, 5, 9, 5, 7, 6, 1, 4, 1, 8, 3, 4, 2, 5, 9, 0, 3, 3, 2,
|
||||
0, 3, 1, 2, 5, 3, 6, 3, 7, 9, 7, 8, 8, 0, 7, 0, 9, 1, 7, 1, 2, 9, 5, 1,
|
||||
6, 6, 0, 1, 5, 6, 2, 5, 1, 8, 1, 8, 9, 8, 9, 4, 0, 3, 5, 4, 5, 8, 5, 6,
|
||||
4, 7, 5, 8, 3, 0, 0, 7, 8, 1, 2, 5, 9, 0, 9, 4, 9, 4, 7, 0, 1, 7, 7, 2,
|
||||
9, 2, 8, 2, 3, 7, 9, 1, 5, 0, 3, 9, 0, 6, 2, 5, 4, 5, 4, 7, 4, 7, 3, 5,
|
||||
0, 8, 8, 6, 4, 6, 4, 1, 1, 8, 9, 5, 7, 5, 1, 9, 5, 3, 1, 2, 5, 2, 2, 7,
|
||||
3, 7, 3, 6, 7, 5, 4, 4, 3, 2, 3, 2, 0, 5, 9, 4, 7, 8, 7, 5, 9, 7, 6, 5,
|
||||
6, 2, 5, 1, 1, 3, 6, 8, 6, 8, 3, 7, 7, 2, 1, 6, 1, 6, 0, 2, 9, 7, 3, 9,
|
||||
3, 7, 9, 8, 8, 2, 8, 1, 2, 5, 5, 6, 8, 4, 3, 4, 1, 8, 8, 6, 0, 8, 0, 8,
|
||||
0, 1, 4, 8, 6, 9, 6, 8, 9, 9, 4, 1, 4, 0, 6, 2, 5, 2, 8, 4, 2, 1, 7, 0,
|
||||
9, 4, 3, 0, 4, 0, 4, 0, 0, 7, 4, 3, 4, 8, 4, 4, 9, 7, 0, 7, 0, 3, 1, 2,
|
||||
5, 1, 4, 2, 1, 0, 8, 5, 4, 7, 1, 5, 2, 0, 2, 0, 0, 3, 7, 1, 7, 4, 2, 2,
|
||||
4, 8, 5, 3, 5, 1, 5, 6, 2, 5, 7, 1, 0, 5, 4, 2, 7, 3, 5, 7, 6, 0, 1, 0,
|
||||
0, 1, 8, 5, 8, 7, 1, 1, 2, 4, 2, 6, 7, 5, 7, 8, 1, 2, 5, 3, 5, 5, 2, 7,
|
||||
1, 3, 6, 7, 8, 8, 0, 0, 5, 0, 0, 9, 2, 9, 3, 5, 5, 6, 2, 1, 3, 3, 7, 8,
|
||||
9, 0, 6, 2, 5, 1, 7, 7, 6, 3, 5, 6, 8, 3, 9, 4, 0, 0, 2, 5, 0, 4, 6, 4,
|
||||
6, 7, 7, 8, 1, 0, 6, 6, 8, 9, 4, 5, 3, 1, 2, 5, 8, 8, 8, 1, 7, 8, 4, 1,
|
||||
9, 7, 0, 0, 1, 2, 5, 2, 3, 2, 3, 3, 8, 9, 0, 5, 3, 3, 4, 4, 7, 2, 6, 5,
|
||||
6, 2, 5, 4, 4, 4, 0, 8, 9, 2, 0, 9, 8, 5, 0, 0, 6, 2, 6, 1, 6, 1, 6, 9,
|
||||
4, 5, 2, 6, 6, 7, 2, 3, 6, 3, 2, 8, 1, 2, 5, 2, 2, 2, 0, 4, 4, 6, 0, 4,
|
||||
9, 2, 5, 0, 3, 1, 3, 0, 8, 0, 8, 4, 7, 2, 6, 3, 3, 3, 6, 1, 8, 1, 6, 4,
|
||||
0, 6, 2, 5, 1, 1, 1, 0, 2, 2, 3, 0, 2, 4, 6, 2, 5, 1, 5, 6, 5, 4, 0, 4,
|
||||
2, 3, 6, 3, 1, 6, 6, 8, 0, 9, 0, 8, 2, 0, 3, 1, 2, 5, 5, 5, 5, 1, 1, 1,
|
||||
5, 1, 2, 3, 1, 2, 5, 7, 8, 2, 7, 0, 2, 1, 1, 8, 1, 5, 8, 3, 4, 0, 4, 5,
|
||||
4, 1, 0, 1, 5, 6, 2, 5, 2, 7, 7, 5, 5, 5, 7, 5, 6, 1, 5, 6, 2, 8, 9, 1,
|
||||
3, 5, 1, 0, 5, 9, 0, 7, 9, 1, 7, 0, 2, 2, 7, 0, 5, 0, 7, 8, 1, 2, 5, 1,
|
||||
3, 8, 7, 7, 7, 8, 7, 8, 0, 7, 8, 1, 4, 4, 5, 6, 7, 5, 5, 2, 9, 5, 3, 9,
|
||||
5, 8, 5, 1, 1, 3, 5, 2, 5, 3, 9, 0, 6, 2, 5, 6, 9, 3, 8, 8, 9, 3, 9, 0,
|
||||
3, 9, 0, 7, 2, 2, 8, 3, 7, 7, 6, 4, 7, 6, 9, 7, 9, 2, 5, 5, 6, 7, 6, 2,
|
||||
6, 9, 5, 3, 1, 2, 5, 3, 4, 6, 9, 4, 4, 6, 9, 5, 1, 9, 5, 3, 6, 1, 4, 1,
|
||||
8, 8, 8, 2, 3, 8, 4, 8, 9, 6, 2, 7, 8, 3, 8, 1, 3, 4, 7, 6, 5, 6, 2, 5,
|
||||
1, 7, 3, 4, 7, 2, 3, 4, 7, 5, 9, 7, 6, 8, 0, 7, 0, 9, 4, 4, 1, 1, 9, 2,
|
||||
4, 4, 8, 1, 3, 9, 1, 9, 0, 6, 7, 3, 8, 2, 8, 1, 2, 5, 8, 6, 7, 3, 6, 1,
|
||||
7, 3, 7, 9, 8, 8, 4, 0, 3, 5, 4, 7, 2, 0, 5, 9, 6, 2, 2, 4, 0, 6, 9, 5,
|
||||
9, 5, 3, 3, 6, 9, 1, 4, 0, 6, 2, 5,
|
||||
};
|
||||
const uint8_t *pow5 =
|
||||
&number_of_digits_decimal_left_shift_table_powers_of_5[pow5_a];
|
||||
uint32_t i = 0;
|
||||
uint32_t n = pow5_b - pow5_a;
|
||||
for (; i < n; i++) {
|
||||
if (i >= h.num_digits) {
|
||||
return num_new_digits - 1;
|
||||
} else if (h.digits[i] == pow5[i]) {
|
||||
continue;
|
||||
} else if (h.digits[i] < pow5[i]) {
|
||||
return num_new_digits - 1;
|
||||
} else {
|
||||
return num_new_digits;
|
||||
}
|
||||
}
|
||||
return num_new_digits;
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
uint64_t round(decimal &h) {
|
||||
if ((h.num_digits == 0) || (h.decimal_point < 0)) {
|
||||
return 0;
|
||||
} else if (h.decimal_point > 18) {
|
||||
return UINT64_MAX;
|
||||
}
|
||||
// at this point, we know that h.decimal_point >= 0
|
||||
uint32_t dp = uint32_t(h.decimal_point);
|
||||
uint64_t n = 0;
|
||||
for (uint32_t i = 0; i < dp; i++) {
|
||||
n = (10 * n) + ((i < h.num_digits) ? h.digits[i] : 0);
|
||||
}
|
||||
bool round_up = false;
|
||||
if (dp < h.num_digits) {
|
||||
round_up = h.digits[dp] >= 5; // normally, we round up
|
||||
// but we may need to round to even!
|
||||
if ((h.digits[dp] == 5) && (dp + 1 == h.num_digits)) {
|
||||
round_up = h.truncated || ((dp > 0) && (1 & h.digits[dp - 1]));
|
||||
}
|
||||
}
|
||||
if (round_up) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// computes h * 2^-shift
|
||||
void decimal_left_shift(decimal &h, uint32_t shift) {
|
||||
if (h.num_digits == 0) {
|
||||
return;
|
||||
}
|
||||
uint32_t num_new_digits = number_of_digits_decimal_left_shift(h, shift);
|
||||
int32_t read_index = int32_t(h.num_digits - 1);
|
||||
uint32_t write_index = h.num_digits - 1 + num_new_digits;
|
||||
uint64_t n = 0;
|
||||
|
||||
while (read_index >= 0) {
|
||||
n += uint64_t(h.digits[read_index]) << shift;
|
||||
uint64_t quotient = n / 10;
|
||||
uint64_t remainder = n - (10 * quotient);
|
||||
if (write_index < max_digits) {
|
||||
h.digits[write_index] = uint8_t(remainder);
|
||||
} else if (remainder > 0) {
|
||||
h.truncated = true;
|
||||
}
|
||||
n = quotient;
|
||||
write_index--;
|
||||
read_index--;
|
||||
}
|
||||
while (n > 0) {
|
||||
uint64_t quotient = n / 10;
|
||||
uint64_t remainder = n - (10 * quotient);
|
||||
if (write_index < max_digits) {
|
||||
h.digits[write_index] = uint8_t(remainder);
|
||||
} else if (remainder > 0) {
|
||||
h.truncated = true;
|
||||
}
|
||||
n = quotient;
|
||||
write_index--;
|
||||
}
|
||||
h.num_digits += num_new_digits;
|
||||
if (h.num_digits > max_digits) {
|
||||
h.num_digits = max_digits;
|
||||
}
|
||||
h.decimal_point += int32_t(num_new_digits);
|
||||
trim(h);
|
||||
}
|
||||
|
||||
// computes h * 2^shift
|
||||
void decimal_right_shift(decimal &h, uint32_t shift) {
|
||||
uint32_t read_index = 0;
|
||||
uint32_t write_index = 0;
|
||||
|
||||
uint64_t n = 0;
|
||||
|
||||
while ((n >> shift) == 0) {
|
||||
if (read_index < h.num_digits) {
|
||||
n = (10 * n) + h.digits[read_index++];
|
||||
} else if (n == 0) {
|
||||
return;
|
||||
} else {
|
||||
while ((n >> shift) == 0) {
|
||||
n = 10 * n;
|
||||
read_index++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
h.decimal_point -= int32_t(read_index - 1);
|
||||
if (h.decimal_point < -decimal_point_range) { // it is zero
|
||||
h.num_digits = 0;
|
||||
h.decimal_point = 0;
|
||||
h.negative = false;
|
||||
h.truncated = false;
|
||||
return;
|
||||
}
|
||||
uint64_t mask = (uint64_t(1) << shift) - 1;
|
||||
while (read_index < h.num_digits) {
|
||||
uint8_t new_digit = uint8_t(n >> shift);
|
||||
n = (10 * (n & mask)) + h.digits[read_index++];
|
||||
h.digits[write_index++] = new_digit;
|
||||
}
|
||||
while (n > 0) {
|
||||
uint8_t new_digit = uint8_t(n >> shift);
|
||||
n = 10 * (n & mask);
|
||||
if (write_index < max_digits) {
|
||||
h.digits[write_index++] = new_digit;
|
||||
} else if (new_digit > 0) {
|
||||
h.truncated = true;
|
||||
}
|
||||
}
|
||||
h.num_digits = write_index;
|
||||
trim(h);
|
||||
}
|
||||
|
||||
|
||||
template <typename binary>
|
||||
adjusted_mantissa compute_float(decimal &d) {
|
||||
adjusted_mantissa answer;
|
||||
if (d.num_digits == 0) {
|
||||
// should be zero
|
||||
answer.power2 = 0;
|
||||
answer.mantissa = 0;
|
||||
return answer;
|
||||
}
|
||||
// At this point, going further, we can assume that d.num_digits > 0.
|
||||
//
|
||||
// We want to guard against excessive decimal point values because
|
||||
// they can result in long running times. Indeed, we do
|
||||
// shifts by at most 60 bits. We have that log(10**400)/log(2**60) ~= 22
|
||||
// which is fine, but log(10**299995)/log(2**60) ~= 16609 which is not
|
||||
// fine (runs for a long time).
|
||||
//
|
||||
if(d.decimal_point < -324) {
|
||||
// We have something smaller than 1e-324 which is always zero
|
||||
// in binary64 and binary32.
|
||||
// It should be zero.
|
||||
answer.power2 = 0;
|
||||
answer.mantissa = 0;
|
||||
return answer;
|
||||
} else if(d.decimal_point >= 310) {
|
||||
// We have something at least as large as 0.1e310 which is
|
||||
// always infinite.
|
||||
answer.power2 = binary::infinite_power();
|
||||
answer.mantissa = 0;
|
||||
return answer;
|
||||
}
|
||||
static const uint32_t max_shift = 60;
|
||||
static const uint32_t num_powers = 19;
|
||||
static const uint8_t powers[19] = {
|
||||
0, 3, 6, 9, 13, 16, 19, 23, 26, 29, //
|
||||
33, 36, 39, 43, 46, 49, 53, 56, 59, //
|
||||
};
|
||||
int32_t exp2 = 0;
|
||||
while (d.decimal_point > 0) {
|
||||
uint32_t n = uint32_t(d.decimal_point);
|
||||
uint32_t shift = (n < num_powers) ? powers[n] : max_shift;
|
||||
decimal_right_shift(d, shift);
|
||||
if (d.decimal_point < -decimal_point_range) {
|
||||
// should be zero
|
||||
answer.power2 = 0;
|
||||
answer.mantissa = 0;
|
||||
return answer;
|
||||
}
|
||||
exp2 += int32_t(shift);
|
||||
}
|
||||
// We shift left toward [1/2 ... 1].
|
||||
while (d.decimal_point <= 0) {
|
||||
uint32_t shift;
|
||||
if (d.decimal_point == 0) {
|
||||
if (d.digits[0] >= 5) {
|
||||
break;
|
||||
}
|
||||
shift = (d.digits[0] < 2) ? 2 : 1;
|
||||
} else {
|
||||
uint32_t n = uint32_t(-d.decimal_point);
|
||||
shift = (n < num_powers) ? powers[n] : max_shift;
|
||||
}
|
||||
decimal_left_shift(d, shift);
|
||||
if (d.decimal_point > decimal_point_range) {
|
||||
// we want to get infinity:
|
||||
answer.power2 = 0xFF;
|
||||
answer.mantissa = 0;
|
||||
return answer;
|
||||
}
|
||||
exp2 -= int32_t(shift);
|
||||
}
|
||||
// We are now in the range [1/2 ... 1] but the binary format uses [1 ... 2].
|
||||
exp2--;
|
||||
constexpr int32_t minimum_exponent = binary::minimum_exponent();
|
||||
while ((minimum_exponent + 1) > exp2) {
|
||||
uint32_t n = uint32_t((minimum_exponent + 1) - exp2);
|
||||
if (n > max_shift) {
|
||||
n = max_shift;
|
||||
}
|
||||
decimal_right_shift(d, n);
|
||||
exp2 += int32_t(n);
|
||||
}
|
||||
if ((exp2 - minimum_exponent) >= binary::infinite_power()) {
|
||||
answer.power2 = binary::infinite_power();
|
||||
answer.mantissa = 0;
|
||||
return answer;
|
||||
}
|
||||
|
||||
const int mantissa_size_in_bits = binary::mantissa_explicit_bits() + 1;
|
||||
decimal_left_shift(d, mantissa_size_in_bits);
|
||||
|
||||
uint64_t mantissa = round(d);
|
||||
// It is possible that we have an overflow, in which case we need
|
||||
// to shift back.
|
||||
if(mantissa >= (uint64_t(1) << mantissa_size_in_bits)) {
|
||||
decimal_right_shift(d, 1);
|
||||
exp2 += 1;
|
||||
mantissa = round(d);
|
||||
if ((exp2 - minimum_exponent) >= binary::infinite_power()) {
|
||||
answer.power2 = binary::infinite_power();
|
||||
answer.mantissa = 0;
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
answer.power2 = exp2 - binary::minimum_exponent();
|
||||
if(mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) { answer.power2--; }
|
||||
answer.mantissa = mantissa & ((uint64_t(1) << binary::mantissa_explicit_bits()) - 1);
|
||||
return answer;
|
||||
}
|
||||
|
||||
template <typename binary>
|
||||
adjusted_mantissa parse_long_mantissa(const char *first, const char* last) {
|
||||
decimal d = parse_decimal(first, last);
|
||||
return compute_float<binary>(d);
|
||||
}
|
||||
|
||||
} // namespace fast_float
|
||||
#endif
|
||||
36
script/analysis.py
Normal file
36
script/analysis.py
Normal file
@ -0,0 +1,36 @@
|
||||
from math import floor
|
||||
|
||||
def log2(x):
|
||||
"""returns ceil(log2(x)))"""
|
||||
y = 0
|
||||
while((1<<y) < x):
|
||||
y = y + 1
|
||||
return y
|
||||
|
||||
|
||||
for q in range(1,17+1):
|
||||
d = 5**q
|
||||
b = 127 + log2(d)
|
||||
t = 2** b
|
||||
c = t//d + 1
|
||||
assert c < 2**128
|
||||
assert c >= 2**127
|
||||
K = 2**127
|
||||
if(not(c * K * d<=( K + 1) * t)):
|
||||
print(q)
|
||||
top = floor(t/(c * d - t))
|
||||
sys.exit(-1)
|
||||
|
||||
for q in range(18, 344+1):
|
||||
d = 5**q
|
||||
b = 64 + 2*log2(d)
|
||||
t = 2**b
|
||||
c = t//d + 1
|
||||
assert c > 2**(64 +log2(d))
|
||||
K = 2**64
|
||||
if(not(c * K * d<=( K + 1) * t)):
|
||||
print(q)
|
||||
top = floor(t/(c * d - t))
|
||||
sys.exit(-1)
|
||||
|
||||
print("all good")
|
||||
30
script/table_generation.py
Normal file
30
script/table_generation.py
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
def format(number):
|
||||
# move the most significant bit in position
|
||||
while(number < (1<<127)):
|
||||
number *= 2
|
||||
# then *truncate*
|
||||
while(number >= (1<<128)):
|
||||
number //= 2
|
||||
upper = number // (1<<64)
|
||||
lower = number % (1<<64)
|
||||
print(""+hex(upper)+","+hex(lower)+",")
|
||||
|
||||
for q in range(-342,0):
|
||||
power5 = 5 ** -q
|
||||
z = 0
|
||||
while( (1<<z) < power5) :
|
||||
z += 1
|
||||
if( q >= -17 ):
|
||||
b = z + 127
|
||||
c = 2 ** b // power5 + 1
|
||||
assert c < (1<<128)
|
||||
format(c)
|
||||
else:
|
||||
b = 2 * z + 64
|
||||
c = 2 ** b // power5 + 1
|
||||
format(c)
|
||||
|
||||
for q in range(0,308+1):
|
||||
power5 = 5 ** q
|
||||
format(power5)
|
||||
17
tests/CMakeLists.txt
Normal file
17
tests/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
function(fast_float_add_cpp_test TEST_NAME)
|
||||
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
|
||||
add_test(${TEST_NAME} ${TEST_NAME})
|
||||
target_link_libraries(${TEST_NAME} PUBLIC fast_float)
|
||||
endfunction(fast_float_add_cpp_test)
|
||||
fast_float_add_cpp_test(exhaustive32_midpoint)
|
||||
fast_float_add_cpp_test(random_string)
|
||||
fast_float_add_cpp_test(string_test)
|
||||
fast_float_add_cpp_test(exhaustive32)
|
||||
fast_float_add_cpp_test(exhaustive32_64)
|
||||
fast_float_add_cpp_test(long_exhaustive32)
|
||||
fast_float_add_cpp_test(long_exhaustive32_64)
|
||||
fast_float_add_cpp_test(long_random64)
|
||||
fast_float_add_cpp_test(random64)
|
||||
fast_float_add_cpp_test(basictest)
|
||||
fast_float_add_cpp_test(example_test)
|
||||
232
tests/basictest.cpp
Normal file
232
tests/basictest.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <iomanip>
|
||||
|
||||
inline void Assert(bool Assertion) {
|
||||
if (!Assertion)
|
||||
throw std::runtime_error("bug");
|
||||
}
|
||||
|
||||
template <typename T> std::string to_string(T d) {
|
||||
std::string s(64, '\0');
|
||||
auto written = std::snprintf(&s[0], s.size(), "%.*e",
|
||||
std::numeric_limits<T>::max_digits10 - 1, d);
|
||||
s.resize(written);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename T> std::string to_long_string(T d) {
|
||||
std::string s(4096, '\0');
|
||||
auto written = std::snprintf(&s[0], s.size(), "%.*e",
|
||||
std::numeric_limits<T>::max_digits10 * 10, d);
|
||||
s.resize(written);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool basic_test_32bit(std::string vals) {
|
||||
std::cout << " parsing " << vals << std::endl;
|
||||
float result_value;
|
||||
auto result = fast_float::from_chars(vals.data(), vals.data() + vals.size(),
|
||||
result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << " I could not parse " << vals << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << std::hexfloat << result_value << std::endl;
|
||||
std::cout << std::dec;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool basic_test_32bit(std::string vals, float val) {
|
||||
std::cout << " parsing " << vals << std::endl;
|
||||
float result_value;
|
||||
auto result = fast_float::from_chars(vals.data(), vals.data() + vals.size(),
|
||||
result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << " I could not parse " << vals << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (std::isnan(val)) {
|
||||
if (!std::isnan(result_value)) {
|
||||
std::cerr << "not nan" << result_value << std::endl;
|
||||
return false;
|
||||
}
|
||||
} else if (result_value != val) {
|
||||
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
|
||||
<< std::endl;
|
||||
std::cerr << std::dec;
|
||||
uint32_t word;
|
||||
memcpy(&word, &result_value, sizeof(word));
|
||||
std::cout << "got mantissa = " << (word & ((1<<23)-1)) << std::endl;
|
||||
memcpy(&word, &val, sizeof(word));
|
||||
std::cout << "wanted mantissa = " << (word & ((1<<23)-1)) << std::endl;
|
||||
std::cerr << "string: " << vals << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << std::hexfloat << result_value << " == " << val << std::endl;
|
||||
std::cout << std::dec;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool basic_test_32bit(float val) {
|
||||
std::string long_vals = to_long_string(val);
|
||||
std::string vals = to_string(val);
|
||||
return basic_test_32bit(long_vals, val) && basic_test_32bit(vals, val);
|
||||
}
|
||||
|
||||
bool basic_test_64bit(std::string vals, double val) {
|
||||
std::cout << " parsing " << vals << std::endl;
|
||||
double result_value;
|
||||
auto result = fast_float::from_chars(vals.data(), vals.data() + vals.size(),
|
||||
result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << " I could not parse " << vals << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (std::isnan(val)) {
|
||||
if (!std::isnan(result_value)) {
|
||||
std::cerr << "not nan" << result_value << std::endl;
|
||||
return false;
|
||||
}
|
||||
} else if (result_value != val) {
|
||||
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
|
||||
<< std::endl;
|
||||
std::cerr << std::dec;
|
||||
std::cerr << "string: " << vals << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << std::hexfloat << result_value << " == " << val << std::endl;
|
||||
std::cout << std::dec;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool basic_test_64bit(double val) {
|
||||
std::string long_vals = to_long_string(val);
|
||||
std::string vals = to_string(val);
|
||||
return basic_test_64bit(long_vals, val) && basic_test_64bit(vals, val);
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
|
||||
std::cout << "======= 64 bits " << std::endl;
|
||||
Assert(basic_test_64bit("2.2250738585072013e-308",2.2250738585072013e-308));
|
||||
Assert(basic_test_64bit("-92666518056446206563E3", -92666518056446206563E3));
|
||||
Assert(basic_test_64bit("-92666518056446206563E3", -92666518056446206563E3));
|
||||
Assert(basic_test_64bit("-42823146028335318693e-128",-42823146028335318693e-128));
|
||||
Assert(basic_test_64bit("90054602635948575728E72",90054602635948575728E72));
|
||||
Assert(basic_test_64bit("1.00000000000000188558920870223463870174566020691753515394643550663070558368373221972569761144603605635692374830246134201063722058e-309", 1.00000000000000188558920870223463870174566020691753515394643550663070558368373221972569761144603605635692374830246134201063722058e-309));
|
||||
Assert(basic_test_64bit("0e9999999999999999999999999999", 0));
|
||||
Assert(basic_test_32bit("1234456789012345678901234567890e9999999999999999999999999999", std::numeric_limits<double>::infinity()));
|
||||
Assert(basic_test_64bit("-2139879401095466344511101915470454744.9813888656856943E+272", -std::numeric_limits<double>::infinity()));
|
||||
Assert(basic_test_64bit("-2402844368454405395.2", -2402844368454405395.2));
|
||||
Assert(basic_test_64bit("2402844368454405395.2", 2402844368454405395.2));
|
||||
Assert(basic_test_64bit("7.0420557077594588669468784357561207962098443483187940792729600000e+59", 7.0420557077594588669468784357561207962098443483187940792729600000e+59));
|
||||
Assert(basic_test_64bit("7.0420557077594588669468784357561207962098443483187940792729600000e+59", 7.0420557077594588669468784357561207962098443483187940792729600000e+59));
|
||||
Assert(basic_test_64bit("-1.7339253062092163730578609458683877051596800000000000000000000000e+42", -1.7339253062092163730578609458683877051596800000000000000000000000e+42));
|
||||
Assert(basic_test_64bit("-2.0972622234386619214559824785284023792871122537545728000000000000e+52", -2.0972622234386619214559824785284023792871122537545728000000000000e+52));
|
||||
Assert(basic_test_64bit("-1.0001803374372191849407179462120053338028379051879898808320000000e+57", -1.0001803374372191849407179462120053338028379051879898808320000000e+57));
|
||||
Assert(basic_test_64bit("-1.8607245283054342363818436991534856973992070520151142825984000000e+58", -1.8607245283054342363818436991534856973992070520151142825984000000e+58));
|
||||
Assert(basic_test_64bit("-1.9189205311132686907264385602245237137907390376574976000000000000e+52", -1.9189205311132686907264385602245237137907390376574976000000000000e+52));
|
||||
Assert(basic_test_64bit("-2.8184483231688951563253238886553506793085187889855201280000000000e+54", -2.8184483231688951563253238886553506793085187889855201280000000000e+54));
|
||||
Assert(basic_test_64bit("-1.7664960224650106892054063261344555646357024359107788800000000000e+53", -1.7664960224650106892054063261344555646357024359107788800000000000e+53));
|
||||
Assert(basic_test_64bit("-2.1470977154320536489471030463761883783915110400000000000000000000e+45", -2.1470977154320536489471030463761883783915110400000000000000000000e+45));
|
||||
Assert(basic_test_64bit("-4.4900312744003159009338275160799498340862630046359789166919680000e+61", -4.4900312744003159009338275160799498340862630046359789166919680000e+61));
|
||||
Assert(basic_test_64bit("+1", 1));
|
||||
Assert(basic_test_64bit("1.8e308", std::numeric_limits<double>::infinity()));
|
||||
Assert(basic_test_64bit("1.797693134862315700000000000000001e308", 1.7976931348623157e308));
|
||||
Assert(basic_test_64bit("1.832312213213213232132132143451234453123412321321312e308", std::numeric_limits<double>::infinity()));
|
||||
Assert(basic_test_64bit("2e30000000000000000", std::numeric_limits<double>::infinity()));
|
||||
Assert(basic_test_64bit("2e3000", std::numeric_limits<double>::infinity()));
|
||||
Assert(basic_test_64bit("1.9e308", std::numeric_limits<double>::infinity()));
|
||||
Assert(basic_test_64bit(3e-324));
|
||||
Assert(basic_test_64bit(1.00000006e+09f));
|
||||
Assert(basic_test_64bit(4.9406564584124653e-324));
|
||||
Assert(basic_test_64bit(4.9406564584124654e-324));
|
||||
Assert(basic_test_64bit(2.2250738585072009e-308));
|
||||
Assert(basic_test_64bit(2.2250738585072014e-308));
|
||||
Assert(basic_test_64bit(1.7976931348623157e308));
|
||||
Assert(basic_test_64bit(1.7976931348623158e308));
|
||||
Assert(basic_test_64bit("4503599627370496.5", 4503599627370496.5));
|
||||
Assert(basic_test_64bit("4503599627475352.5", 4503599627475352.5));
|
||||
Assert(basic_test_64bit("4503599627475353.5", 4503599627475353.5));
|
||||
Assert(basic_test_64bit("2251799813685248.25", 2251799813685248.25));
|
||||
Assert(basic_test_64bit("1125899906842624.125", 1125899906842624.125));
|
||||
Assert(basic_test_64bit("1125899906842901.875", 1125899906842901.875));
|
||||
Assert(basic_test_64bit("2251799813685803.75", 2251799813685803.75));
|
||||
Assert(basic_test_64bit("4503599627370497.5", 4503599627370497.5));
|
||||
Assert(basic_test_64bit("45035996.273704995", 45035996.273704995));
|
||||
Assert(basic_test_64bit("45035996.273704985", 45035996.273704985));
|
||||
Assert(basic_test_64bit("0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044501477170144022721148195934182639518696390927032912960468522194496444440421538910330590478162701758282983178260792422137401728773891892910553144148156412434867599762821265346585071045737627442980259622449029037796981144446145705102663115100318287949527959668236039986479250965780342141637013812613333119898765515451440315261253813266652951306000184917766328660755595837392240989947807556594098101021612198814605258742579179000071675999344145086087205681577915435923018910334964869420614052182892431445797605163650903606514140377217442262561590244668525767372446430075513332450079650686719491377688478005309963967709758965844137894433796621993967316936280457084866613206797017728916080020698679408551343728867675409720757232455434770912461317493580281734466552734375", 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044501477170144022721148195934182639518696390927032912960468522194496444440421538910330590478162701758282983178260792422137401728773891892910553144148156412434867599762821265346585071045737627442980259622449029037796981144446145705102663115100318287949527959668236039986479250965780342141637013812613333119898765515451440315261253813266652951306000184917766328660755595837392240989947807556594098101021612198814605258742579179000071675999344145086087205681577915435923018910334964869420614052182892431445797605163650903606514140377217442262561590244668525767372446430075513332450079650686719491377688478005309963967709758965844137894433796621993967316936280457084866613206797017728916080020698679408551343728867675409720757232455434770912461317493580281734466552734375));
|
||||
Assert(basic_test_64bit("0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375", 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375));
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "======= 32 bits " << std::endl;
|
||||
Assert(basic_test_32bit("1.1754943508e-38",1.1754943508e-38f));
|
||||
Assert(basic_test_32bit("30219.0830078125",30219.0830078125f));
|
||||
Assert(basic_test_32bit("16252921.5",16252921.5f));
|
||||
Assert(basic_test_32bit("5322519.25",5322519.25f));
|
||||
Assert(basic_test_32bit("3900245.875",3900245.875f));
|
||||
Assert(basic_test_32bit("1510988.3125",1510988.3125f));
|
||||
Assert(basic_test_32bit("782262.28125",782262.28125f));
|
||||
Assert(basic_test_32bit("328381.484375",328381.484375f));
|
||||
Assert(basic_test_32bit("156782.0703125",156782.0703125f));
|
||||
Assert(basic_test_32bit("85003.24609375",85003.24609375f));
|
||||
Assert(basic_test_32bit("43827.048828125",43827.048828125f));
|
||||
Assert(basic_test_32bit("17419.6494140625",17419.6494140625f));
|
||||
Assert(basic_test_32bit("15498.36376953125",15498.36376953125f));
|
||||
Assert(basic_test_32bit("6318.580322265625",6318.580322265625f));
|
||||
Assert(basic_test_32bit("2525.2840576171875",2525.2840576171875f));
|
||||
Assert(basic_test_32bit("1370.9265747070312",1370.9265747070312f));
|
||||
Assert(basic_test_32bit("936.3702087402344",936.3702087402344f));
|
||||
Assert(basic_test_32bit("411.88682556152344",411.88682556152344f));
|
||||
Assert(basic_test_32bit("206.50310516357422",206.50310516357422f));
|
||||
Assert(basic_test_32bit("124.16878890991211",124.16878890991211f));
|
||||
Assert(basic_test_32bit("50.811574935913086",50.811574935913086f));
|
||||
Assert(basic_test_32bit("17.486443519592285",17.486443519592285f));
|
||||
Assert(basic_test_32bit("13.91745138168335",13.91745138168335f));
|
||||
Assert(basic_test_32bit("7.5464513301849365",7.5464513301849365f));
|
||||
Assert(basic_test_32bit("2.687217116355896",2.687217116355896f));
|
||||
Assert(basic_test_32bit("1.1877630352973938",1.1877630352973938f));
|
||||
Assert(basic_test_32bit("0.7622503340244293",0.7622503340244293f));
|
||||
Assert(basic_test_32bit("0.30531780421733856",0.30531780421733856f));
|
||||
Assert(basic_test_32bit("0.21791061013936996",0.21791061013936996f));
|
||||
Assert(basic_test_32bit("0.09289376810193062",0.09289376810193062f));
|
||||
Assert(basic_test_32bit("0.03706067614257336",0.03706067614257336f));
|
||||
Assert(basic_test_32bit("0.028068351559340954",0.028068351559340954f));
|
||||
Assert(basic_test_32bit("0.012114629615098238",0.012114629615098238f));
|
||||
Assert(basic_test_32bit("0.004221370676532388",0.004221370676532388f));
|
||||
Assert(basic_test_32bit("0.002153817447833717",0.002153817447833717f));
|
||||
Assert(basic_test_32bit("0.0015924838953651488",0.0015924838953651488f));
|
||||
Assert(basic_test_32bit("0.0008602388261351734",0.0008602388261351734f));
|
||||
Assert(basic_test_32bit("0.00036393293703440577",0.00036393293703440577f));
|
||||
Assert(basic_test_32bit("0.00013746770127909258",0.00013746770127909258));
|
||||
Assert(basic_test_32bit("16407.9462890625", 16407.9462890625f));
|
||||
Assert(basic_test_32bit("1.1754947011469036e-38", 1.1754947011469036e-38f));
|
||||
Assert(basic_test_32bit("7.0064923216240854e-46", 7.0064923216240854e-46f));
|
||||
Assert(basic_test_32bit("8388614.5", 8388614.5f));
|
||||
Assert(basic_test_32bit("0e9999999999999999999999999999", 0));
|
||||
Assert(basic_test_32bit("1234456789012345678901234567890e9999999999999999999999999999", std::numeric_limits<float>::infinity()));
|
||||
Assert(basic_test_32bit("4.7019774032891500318749461488889827112746622270883500860350068251e-38",4.7019774032891500318749461488889827112746622270883500860350068251e-38f));
|
||||
Assert(basic_test_32bit("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679", 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679));
|
||||
Assert(basic_test_32bit("2.3509887016445750159374730744444913556373311135441750430175034126e-38", 2.3509887016445750159374730744444913556373311135441750430175034126e-38f));
|
||||
Assert(basic_test_32bit("+1", 1));
|
||||
Assert(basic_test_32bit("2e3000", std::numeric_limits<float>::infinity()));
|
||||
Assert(basic_test_32bit("3.5028234666e38", std::numeric_limits<float>::infinity()));
|
||||
Assert(basic_test_32bit("7.0060e-46", 0));
|
||||
Assert(basic_test_32bit(1.00000006e+09f));
|
||||
Assert(basic_test_32bit(1.4012984643e-45f));
|
||||
Assert(basic_test_32bit(1.1754942107e-38f));
|
||||
Assert(basic_test_32bit(1.1754943508e-45f));
|
||||
Assert(basic_test_32bit(3.4028234664e38f));
|
||||
Assert(basic_test_32bit(3.4028234665e38f));
|
||||
Assert(basic_test_32bit(3.4028234666e38f));
|
||||
Assert(basic_test_32bit("0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625", 0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625));
|
||||
Assert(basic_test_32bit("0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125", 0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125));
|
||||
Assert(basic_test_32bit("0.00000000000000000000000000000000000002350988561514728583455765982071533026645717985517980855365926236850006129930346077117064851336181163787841796875", 0.00000000000000000000000000000000000002350988561514728583455765982071533026645717985517980855365926236850006129930346077117064851336181163787841796875));
|
||||
Assert(basic_test_32bit("0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875", 0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875));
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "All ok" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
6203
tests/dtoa.c
Normal file
6203
tests/dtoa.c
Normal file
File diff suppressed because it is too large
Load Diff
11
tests/example_test.cpp
Normal file
11
tests/example_test.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
const std::string input = "3.1416 xyz ";
|
||||
double result;
|
||||
auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result);
|
||||
if(answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||
std::cout << "parsed the number " << result << std::endl;
|
||||
}
|
||||
55
tests/exhaustive32.cpp
Normal file
55
tests/exhaustive32.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
template <typename T> char *to_string(T d, char *buffer) {
|
||||
auto written = std::snprintf(buffer, 64, "%.*e",
|
||||
std::numeric_limits<T>::max_digits10 - 1, d);
|
||||
return buffer + written;
|
||||
}
|
||||
|
||||
void allvalues() {
|
||||
char buffer[64];
|
||||
for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) {
|
||||
float v;
|
||||
if ((w % 1048576) == 0) {
|
||||
std::cout << ".";
|
||||
std::cout.flush();
|
||||
}
|
||||
uint32_t word = w;
|
||||
memcpy(&v, &word, sizeof(v));
|
||||
|
||||
{
|
||||
const char *string_end = to_string(v, buffer);
|
||||
float result_value;
|
||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||
abort();
|
||||
}
|
||||
if (std::isnan(v)) {
|
||||
if (!std::isnan(result_value)) {
|
||||
std::cerr << "not nan" << buffer << std::endl;
|
||||
abort();
|
||||
}
|
||||
} else if (result_value != v) {
|
||||
std::cerr << "no match ? " << buffer << std::endl;
|
||||
std::cout << "started with " << std::hexfloat << v << std::endl;
|
||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||
std::cout << std::dec;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
allvalues();
|
||||
std::cout << std::endl;
|
||||
std::cout << "all ok" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
56
tests/exhaustive32_64.cpp
Normal file
56
tests/exhaustive32_64.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
template <typename T> char *to_string(T d, char *buffer) {
|
||||
auto written = std::snprintf(buffer, 64, "%.*e",
|
||||
std::numeric_limits<T>::max_digits10 - 1, d);
|
||||
return buffer + written;
|
||||
}
|
||||
|
||||
void all_32bit_values() {
|
||||
char buffer[64];
|
||||
for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) {
|
||||
float v32;
|
||||
if ((w % 1048576) == 0) {
|
||||
std::cout << ".";
|
||||
std::cout.flush();
|
||||
}
|
||||
uint32_t word = uint32_t(w);
|
||||
memcpy(&v32, &word, sizeof(v32));
|
||||
double v = v32;
|
||||
|
||||
{
|
||||
const char *string_end = to_string(v, buffer);
|
||||
double result_value;
|
||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||
abort();
|
||||
}
|
||||
if (std::isnan(v)) {
|
||||
if (!std::isnan(result_value)) {
|
||||
std::cerr << "not nan" << buffer << std::endl;
|
||||
abort();
|
||||
}
|
||||
} else if (result_value != v) {
|
||||
std::cerr << "no match ? " << buffer << std::endl;
|
||||
std::cout << "started with " << std::hexfloat << v << std::endl;
|
||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||
std::cout << std::dec;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
all_32bit_values();
|
||||
std::cout << std::endl;
|
||||
std::cout << "all ok" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
80
tests/exhaustive32_midpoint.cpp
Normal file
80
tests/exhaustive32_midpoint.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
template <typename T> char *to_string(T d, char *buffer) {
|
||||
auto written = std::snprintf(buffer, 64, "%.*e",
|
||||
std::numeric_limits<T>::max_digits10 - 1, d);
|
||||
return buffer + written;
|
||||
}
|
||||
|
||||
void strtod_from_string(const char * st, float& d) {
|
||||
char *pr = (char *)st;
|
||||
#ifdef _WIN32
|
||||
static _locale_t c_locale = _create_locale(LC_ALL, "C");
|
||||
d = _strtof_l(st, &pr, c_locale);
|
||||
#else
|
||||
static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
|
||||
d = strtof_l(st, &pr, c_locale);
|
||||
#endif
|
||||
if (pr == st) {
|
||||
throw std::runtime_error("bug in strtod_from_string");
|
||||
}
|
||||
}
|
||||
|
||||
void allvalues() {
|
||||
char buffer[64];
|
||||
for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) {
|
||||
float v;
|
||||
if ((w % 1048576) == 0) {
|
||||
std::cout << ".";
|
||||
std::cout.flush();
|
||||
}
|
||||
uint32_t word = w;
|
||||
memcpy(&v, &word, sizeof(v));
|
||||
if(std::isfinite(v)) {
|
||||
float nextf = std::nextafterf(v, INFINITY);
|
||||
if(!std::isfinite(nextf)) { continue; }
|
||||
double v1{v};
|
||||
assert(float(v1) == v);
|
||||
double v2{nextf};
|
||||
assert(float(v2) == nextf);
|
||||
double midv{v1 + (v2 - v1) / 2};
|
||||
float expected_midv(midv);
|
||||
|
||||
const char *string_end = to_string(midv, buffer);
|
||||
float str_answer;
|
||||
strtod_from_string(buffer, str_answer);
|
||||
|
||||
float result_value;
|
||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||
abort();
|
||||
}
|
||||
if (std::isnan(v)) {
|
||||
if (!std::isnan(result_value)) {
|
||||
std::cerr << "not nan" << buffer << std::endl;
|
||||
abort();
|
||||
}
|
||||
} else if (result_value != str_answer) {
|
||||
std::cerr << "no match ? " << buffer << std::endl;
|
||||
std::cout << "started with " << std::hexfloat << midv << std::endl;
|
||||
std::cout << "round down to " << std::hexfloat << str_answer << std::endl;
|
||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||
std::cout << std::dec;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
allvalues();
|
||||
std::cout << std::endl;
|
||||
std::cout << "all ok" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
55
tests/long_exhaustive32.cpp
Normal file
55
tests/long_exhaustive32.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
template <typename T> char *to_string(T d, char *buffer) {
|
||||
auto written = std::snprintf(buffer, 128, "%.*e",
|
||||
64, d);
|
||||
return buffer + written;
|
||||
}
|
||||
|
||||
void allvalues() {
|
||||
char buffer[128];
|
||||
for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) {
|
||||
float v;
|
||||
if ((w % 1048576) == 0) {
|
||||
std::cout << ".";
|
||||
std::cout.flush();
|
||||
}
|
||||
uint32_t word = uint32_t(w);
|
||||
memcpy(&v, &word, sizeof(v));
|
||||
|
||||
{
|
||||
const char *string_end = to_string(v, buffer);
|
||||
float result_value;
|
||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||
abort();
|
||||
}
|
||||
if (std::isnan(v)) {
|
||||
if (!std::isnan(result_value)) {
|
||||
std::cerr << "not nan" << buffer << std::endl;
|
||||
abort();
|
||||
}
|
||||
} else if (result_value != v) {
|
||||
std::cerr << "no match ? " << buffer << " got " << result_value << " expected " << v << std::endl;
|
||||
std::cout << "started with " << std::hexfloat << v << std::endl;
|
||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||
std::cout << std::dec;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
allvalues();
|
||||
std::cout << std::endl;
|
||||
std::cout << "all ok" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
55
tests/long_exhaustive32_64.cpp
Normal file
55
tests/long_exhaustive32_64.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
template <typename T> char *to_string(T d, char *buffer) {
|
||||
auto written = std::snprintf(buffer, 128, "%.*e",
|
||||
64, d);
|
||||
return buffer + written;
|
||||
}
|
||||
|
||||
void all_32bit_values() {
|
||||
char buffer[128];
|
||||
for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) {
|
||||
float v32;
|
||||
if ((w % 1048576) == 0) {
|
||||
std::cout << ".";
|
||||
std::cout.flush();
|
||||
}
|
||||
uint32_t word = uint32_t(w);
|
||||
memcpy(&v32, &word, sizeof(v32));
|
||||
double v = v32;
|
||||
|
||||
{
|
||||
const char *string_end = to_string(v, buffer);
|
||||
double result_value;
|
||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||
abort();
|
||||
}
|
||||
if (std::isnan(v)) {
|
||||
if (!std::isnan(result_value)) {
|
||||
std::cerr << "not nan" << buffer << std::endl;
|
||||
abort();
|
||||
}
|
||||
} else if (result_value != v) {
|
||||
std::cerr << "no match ? " << buffer << std::endl;
|
||||
std::cout << "started with " << std::hexfloat << v << std::endl;
|
||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||
std::cout << std::dec;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
all_32bit_values();
|
||||
std::cout << std::endl;
|
||||
std::cout << "all ok" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
93
tests/long_random64.cpp
Normal file
93
tests/long_random64.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
template <typename T> char *to_string(T d, char *buffer) {
|
||||
auto written = std::snprintf(buffer, 128, "%.*e",
|
||||
64, d);
|
||||
return buffer + written;
|
||||
}
|
||||
|
||||
static __uint128_t g_lehmer64_state;
|
||||
|
||||
/**
|
||||
* D. H. Lehmer, Mathematical methods in large-scale computing units.
|
||||
* Proceedings of a Second Symposium on Large Scale Digital Calculating
|
||||
* Machinery;
|
||||
* Annals of the Computation Laboratory, Harvard Univ. 26 (1951), pp. 141-146.
|
||||
*
|
||||
* P L'Ecuyer, Tables of linear congruential generators of different sizes and
|
||||
* good lattice structure. Mathematics of Computation of the American
|
||||
* Mathematical
|
||||
* Society 68.225 (1999): 249-260.
|
||||
*/
|
||||
|
||||
static inline void lehmer64_seed(uint64_t seed) { g_lehmer64_state = seed; }
|
||||
|
||||
static inline uint64_t lehmer64() {
|
||||
g_lehmer64_state *= UINT64_C(0xda942042e4dd58b5);
|
||||
return uint64_t(g_lehmer64_state >> 64);
|
||||
}
|
||||
|
||||
size_t errors;
|
||||
|
||||
void random_values(size_t N) {
|
||||
char buffer[128];
|
||||
lehmer64_seed(N);
|
||||
for (size_t t = 0; t < N; t++) {
|
||||
if ((t % 1048576) == 0) {
|
||||
std::cout << ".";
|
||||
std::cout.flush();
|
||||
}
|
||||
uint64_t word = lehmer64();
|
||||
double v;
|
||||
memcpy(&v, &word, sizeof(v));
|
||||
{
|
||||
const char *string_end = to_string(v, buffer);
|
||||
double result_value;
|
||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||
errors++;
|
||||
if (errors > 10) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
if (std::isnan(v)) {
|
||||
if (!std::isnan(result_value)) {
|
||||
std::cerr << "not nan" << buffer << std::endl;
|
||||
errors++;
|
||||
if (errors > 10) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
} else if (result_value != v) {
|
||||
std::cerr << "no match ? '" << buffer << "'" << std::endl;
|
||||
std::cout << "started with " << std::hexfloat << v << std::endl;
|
||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||
std::cout << std::dec;
|
||||
errors++;
|
||||
if (errors > 10) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
errors = 0;
|
||||
size_t N = size_t(1) << 32;
|
||||
random_values(N);
|
||||
if (errors == 0) {
|
||||
std::cout << std::endl;
|
||||
std::cout << "all ok" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "errors were encountered" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
53
tests/long_test.cpp
Normal file
53
tests/long_test.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
inline void Assert(bool Assertion) {
|
||||
if (!Assertion)
|
||||
throw std::runtime_error("bug");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool test() {
|
||||
std::string input = "0.156250000000000000000000000000000000000000 3.14159265358979323846264338327950288419716939937510 2.71828182845904523536028747135266249775724709369995";
|
||||
std::vector<T> answers = {T(0.15625), T(3.141592653589793), T(2.718281828459045)};
|
||||
const char * begin = input.data();
|
||||
const char * end = input.data() + input.size();
|
||||
for(size_t i = 0; i < answers.size(); i++) {
|
||||
T result_value;
|
||||
auto result = fast_float::from_chars(begin, end,
|
||||
result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
printf("parsing %.*s\n", int(end - begin), begin);
|
||||
std::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
}
|
||||
if(result_value != answers[i]) {
|
||||
printf("parsing %.*s\n", int(end - begin), begin);
|
||||
std::cerr << " Mismatch " << std::endl;
|
||||
std::cerr << " Expected " << answers[i] << std::endl;
|
||||
std::cerr << " Got " << result_value << std::endl;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
begin = result.ptr;
|
||||
}
|
||||
if(begin != end) {
|
||||
std::cerr << " bad ending " << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
std::cout << "32 bits checks" << std::endl;
|
||||
Assert(test<float>());
|
||||
|
||||
std::cout << "64 bits checks" << std::endl;
|
||||
Assert(test<double>());
|
||||
|
||||
std::cout << "All ok" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
94
tests/random64.cpp
Normal file
94
tests/random64.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
template <typename T> char *to_string(T d, char *buffer) {
|
||||
auto written = std::snprintf(buffer, 64, "%.*e",
|
||||
std::numeric_limits<T>::max_digits10 - 1, d);
|
||||
return buffer + written;
|
||||
}
|
||||
|
||||
static __uint128_t g_lehmer64_state;
|
||||
|
||||
/**
|
||||
* D. H. Lehmer, Mathematical methods in large-scale computing units.
|
||||
* Proceedings of a Second Symposium on Large Scale Digital Calculating
|
||||
* Machinery;
|
||||
* Annals of the Computation Laboratory, Harvard Univ. 26 (1951), pp. 141-146.
|
||||
*
|
||||
* P L'Ecuyer, Tables of linear congruential generators of different sizes and
|
||||
* good lattice structure. Mathematics of Computation of the American
|
||||
* Mathematical
|
||||
* Society 68.225 (1999): 249-260.
|
||||
*/
|
||||
|
||||
static inline void lehmer64_seed(uint64_t seed) { g_lehmer64_state = seed; }
|
||||
|
||||
static inline uint64_t lehmer64() {
|
||||
g_lehmer64_state *= UINT64_C(0xda942042e4dd58b5);
|
||||
return uint64_t(g_lehmer64_state >> 64);
|
||||
}
|
||||
|
||||
size_t errors;
|
||||
|
||||
void random_values(size_t N) {
|
||||
char buffer[64];
|
||||
lehmer64_seed(N);
|
||||
for (size_t t = 0; t < N; t++) {
|
||||
if ((t % 1048576) == 0) {
|
||||
std::cout << ".";
|
||||
std::cout.flush();
|
||||
}
|
||||
uint64_t word = lehmer64();
|
||||
double v;
|
||||
memcpy(&v, &word, sizeof(v));
|
||||
// if (!std::isnormal(v))
|
||||
{
|
||||
const char *string_end = to_string(v, buffer);
|
||||
double result_value;
|
||||
auto result = fast_float::from_chars(buffer, string_end, result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << "parsing error ? " << buffer << std::endl;
|
||||
errors++;
|
||||
if (errors > 10) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
if (std::isnan(v)) {
|
||||
if (!std::isnan(result_value)) {
|
||||
std::cerr << "not nan" << buffer << std::endl;
|
||||
errors++;
|
||||
if (errors > 10) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
} else if (result_value != v) {
|
||||
std::cerr << "no match ? " << buffer << std::endl;
|
||||
std::cout << "started with " << std::hexfloat << v << std::endl;
|
||||
std::cout << "got back " << std::hexfloat << result_value << std::endl;
|
||||
std::cout << std::dec;
|
||||
errors++;
|
||||
if (errors > 10) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
errors = 0;
|
||||
size_t N = size_t(1) << 32;
|
||||
random_values(N);
|
||||
if (errors == 0) {
|
||||
std::cout << std::endl;
|
||||
std::cout << "all ok" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "errors were encountered" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
188
tests/random_string.cpp
Normal file
188
tests/random_string.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
|
||||
class RandomEngine {
|
||||
public:
|
||||
RandomEngine() = delete;
|
||||
RandomEngine(int new_seed) { wyhash64_x_ = new_seed; };
|
||||
uint64_t next() {
|
||||
// Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h
|
||||
// Inspired from
|
||||
// https://github.com/lemire/testingRNG/blob/master/source/wyhash.h
|
||||
wyhash64_x_ += UINT64_C(0x60bee2bee120fc15);
|
||||
__uint128_t tmp;
|
||||
tmp = (__uint128_t)wyhash64_x_ * UINT64_C(0xa3b195354a39b70d);
|
||||
uint64_t m1 = (tmp >> 64) ^ tmp;
|
||||
tmp = (__uint128_t)m1 * UINT64_C(0x1b03738712fad5c9);
|
||||
uint64_t m2 = (tmp >> 64) ^ tmp;
|
||||
return m2;
|
||||
}
|
||||
bool next_bool() { return (next() & 1) == 1; }
|
||||
int next_int() { return static_cast<int>(next()); }
|
||||
char next_char() { return static_cast<char>(next()); }
|
||||
double next_double() { return static_cast<double>(next()); }
|
||||
|
||||
int next_ranged_int(int min, int max) { // min and max are include
|
||||
// Adapted from
|
||||
// https://lemire.me/blog/2019/06/06/nearly-divisionless-random-integer-generation-on-various-systems/
|
||||
/* if (min == max) {
|
||||
return min;
|
||||
}*/
|
||||
int s = max - min + 1;
|
||||
uint64_t x = next();
|
||||
__uint128_t m = (__uint128_t)x * (__uint128_t)s;
|
||||
uint64_t l = (uint64_t)m;
|
||||
if (l < s) {
|
||||
uint64_t t = -s % s;
|
||||
while (l < t) {
|
||||
x = next();
|
||||
m = (__uint128_t)x * (__uint128_t)s;
|
||||
l = (uint64_t)m;
|
||||
}
|
||||
}
|
||||
return (m >> 64) + min;
|
||||
}
|
||||
int next_digit() { return next_ranged_int(0, 9); }
|
||||
|
||||
private:
|
||||
uint64_t wyhash64_x_;
|
||||
};
|
||||
|
||||
size_t build_random_string(RandomEngine &rand, char *buffer) {
|
||||
size_t pos{0};
|
||||
if (rand.next_bool()) {
|
||||
buffer[pos++] = '-';
|
||||
}
|
||||
int number_of_digits = rand.next_ranged_int(1, 100);
|
||||
int location_of_decimal_separator = rand.next_ranged_int(1, number_of_digits);
|
||||
for (size_t i = 0; i < number_of_digits; i++) {
|
||||
if (i == location_of_decimal_separator) {
|
||||
buffer[pos++] = '.';
|
||||
}
|
||||
buffer[pos++] = char(rand.next_digit() + '0');
|
||||
}
|
||||
if (rand.next_bool()) {
|
||||
if (rand.next_bool()) {
|
||||
buffer[pos++] = 'e';
|
||||
} else {
|
||||
buffer[pos++] = 'E';
|
||||
}
|
||||
if (rand.next_bool()) {
|
||||
buffer[pos++] = '-';
|
||||
} else {
|
||||
if (rand.next_bool()) {
|
||||
buffer[pos++] = '+';
|
||||
}
|
||||
}
|
||||
number_of_digits = rand.next_ranged_int(1, 3);
|
||||
for (size_t i = 0; i < number_of_digits; i++) {
|
||||
buffer[pos++] = char(rand.next_digit() + '0');
|
||||
}
|
||||
}
|
||||
buffer[pos] = '\0'; // null termination
|
||||
return pos;
|
||||
}
|
||||
|
||||
std::pair<double, bool> strtod_from_string(char *st) {
|
||||
double d;
|
||||
char *pr;
|
||||
#ifdef _WIN32
|
||||
static _locale_t c_locale = _create_locale(LC_ALL, "C");
|
||||
d = _strtod_l(st, &pr, c_locale);
|
||||
#else
|
||||
static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
|
||||
d = strtod_l(st, &pr, c_locale);
|
||||
#endif
|
||||
if (st == pr) {
|
||||
std::cerr << "strtod_l could not parse '" << st << std::endl;
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
return std::make_pair(d, true);
|
||||
}
|
||||
|
||||
std::pair<float, bool> strtof_from_string(char *st) {
|
||||
float d;
|
||||
char *pr;
|
||||
#ifdef _WIN32
|
||||
static _locale_t c_locale = _create_locale(LC_ALL, "C");
|
||||
d = _strtof_l(st, &pr, c_locale);
|
||||
#else
|
||||
static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
|
||||
d = strtof_l(st, &pr, c_locale);
|
||||
#endif
|
||||
if (st == pr) {
|
||||
std::cerr << "strtof_l could not parse '" << st << std::endl;
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
return std::make_pair(d, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* We generate random strings and we try to parse them with both strtod/strtof,
|
||||
* and we verify that we get the same answer with with fast_float::from_chars.
|
||||
*/
|
||||
bool tester(int seed, size_t volume) {
|
||||
char buffer[1024]; // large buffer (can't overflow)
|
||||
RandomEngine rand(seed);
|
||||
for (size_t i = 0; i < volume; i++) {
|
||||
if((i%100000) == 0) { std::cout << "."; std::cout.flush(); }
|
||||
size_t length = build_random_string(rand, buffer);
|
||||
std::pair<double, bool> expected_double = strtod_from_string(buffer);
|
||||
if (expected_double.second) {
|
||||
double result_value;
|
||||
auto result =
|
||||
fast_float::from_chars(buffer, buffer + length, result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
printf("parsing %.*s\n", int(length), buffer);
|
||||
std::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (result.ptr != buffer + length) {
|
||||
printf("parsing %.*s\n", int(length), buffer);
|
||||
std::cerr << " Did not get to the end " << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (result_value != expected_double.first) {
|
||||
printf("parsing %.*s\n", int(length), buffer);
|
||||
std::cerr << std::hexfloat << result_value << std::endl;
|
||||
std::cerr << std::hexfloat << expected_double.first << std::endl;
|
||||
std::cerr << " Mismatch " << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
std::pair<float, bool> expected_float = strtof_from_string(buffer);
|
||||
if (expected_float.second) {
|
||||
float result_value;
|
||||
auto result =
|
||||
fast_float::from_chars(buffer, buffer + length, result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
printf("parsing %.*s\n", int(length), buffer);
|
||||
std::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (result.ptr != buffer + length) {
|
||||
printf("parsing %.*s\n", int(length), buffer);
|
||||
std::cerr << " Did not get to the end " << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (result_value != expected_float.first) {
|
||||
printf("parsing %.*s\n", int(length), buffer);
|
||||
std::cerr << std::hexfloat << result_value << std::endl;
|
||||
std::cerr << std::hexfloat << expected_float.first << std::endl;
|
||||
std::cerr << " Mismatch " << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
if (tester(1234344, 100000000)) {
|
||||
std::cout << "All tests ok." << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
std::cout << "Failure." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
229
tests/string_test.cpp
Normal file
229
tests/string_test.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
inline void Assert(bool Assertion) {
|
||||
if (!Assertion)
|
||||
throw std::runtime_error("bug");
|
||||
}
|
||||
|
||||
template <typename T> std::string to_string(T d) {
|
||||
std::string s(64, '\0');
|
||||
auto written = std::snprintf(&s[0], s.size(), "%.*e",
|
||||
std::numeric_limits<T>::max_digits10 - 1, d);
|
||||
s.resize(written);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool test() {
|
||||
std::string input = "0.1 1e1000 100000 3.14159265359 -1e-500 001 1e01 1e0000001 -inf";
|
||||
std::vector<T> answers = {T(0.1), std::numeric_limits<T>::infinity(), 100000, T(3.14159265359), -0.0, 1, 10, 10, -std::numeric_limits<T>::infinity()};
|
||||
const char * begin = input.data();
|
||||
const char * end = input.data() + input.size();
|
||||
for(size_t i = 0; i < answers.size(); i++) {
|
||||
T result_value;
|
||||
auto result = fast_float::from_chars(begin, end,
|
||||
result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
printf("parsing %.*s\n", int(end - begin), begin);
|
||||
std::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
}
|
||||
if(result_value != answers[i]) {
|
||||
printf("parsing %.*s\n", int(end - begin), begin);
|
||||
std::cerr << " Mismatch " << std::endl;
|
||||
return false;
|
||||
|
||||
}
|
||||
begin = result.ptr;
|
||||
}
|
||||
if(begin != end) {
|
||||
std::cerr << " bad ending " << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void strtod_from_string(const std::string &st, T& d);
|
||||
|
||||
template <>
|
||||
void strtod_from_string(const std::string &st, double& d) {
|
||||
char *pr = (char *)st.data();
|
||||
#ifdef _WIN32
|
||||
static _locale_t c_locale = _create_locale(LC_ALL, "C");
|
||||
d = _strtod_l(st.data(), &pr, c_locale);
|
||||
#else
|
||||
static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
|
||||
d = strtod_l(st.data(), &pr, c_locale);
|
||||
#endif
|
||||
if (pr == st.data()) {
|
||||
throw std::runtime_error("bug in strtod_from_string");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void strtod_from_string(const std::string &st, float& d) {
|
||||
char *pr = (char *)st.data();
|
||||
#ifdef _WIN32
|
||||
static _locale_t c_locale = _create_locale(LC_ALL, "C");
|
||||
d = _strtof_l(st.data(), &pr, c_locale);
|
||||
#else
|
||||
static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
|
||||
d = strtof_l(st.data(), &pr, c_locale);
|
||||
#endif
|
||||
if (pr == st.data()) {
|
||||
throw std::runtime_error("bug in strtod_from_string");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool partow_test() {
|
||||
// credit: https://github.com/ArashPartow/strtk/blob/master/strtk_tokenizer_cmp.cpp#L568
|
||||
// MIT license
|
||||
const std::string strint_list[] = { "9007199254740993", "9007199254740994", "9007199254740995" ,
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
"917049", "4931205", "6768064", "6884243", "5647132", "7371203", "-8629878", "4941840", "4543268", "1075600",
|
||||
"+290", "823", "+111", "715", "-866", "+367", "666", "-706", "850", "-161",
|
||||
"9922547", "6960207", "1883152", "2300759", "-279294", "4187292", "3699841", "+8386395", "-1441129", "-887892",
|
||||
"-635422", "9742573", "2326186", "-5903851", "5648486", "3057647", "2980079", "2957468", "7929158", "1925615",
|
||||
"879", "+130", "292", "+705", "817", "446", "576", "750", "523", "-527",
|
||||
"4365041", "5624958", "8990205", "2652177", "3993588", "-298316", "+2901599", "3887387", "-5202979", "1196268",
|
||||
"5968501", "7619928", "3565643", "1885272", "-749485", "2961381", "2982579", "2387454", "4250081", "5958205",
|
||||
"00000", "00001", "00002", "+00003", "00004", "00005", "00006", "00007", "00008", "+00009",
|
||||
"4907034", "2592882", "3269234", "549815", "6256292", "9721039", "-595225", "+5587491", "4596297", "-3885009",
|
||||
"673", "-899", "174", "354", "870", "147", "898", "-510", "369", "+859",
|
||||
"6518423", "5149762", "8834164", "-8085586", "3233120", "8166948", "4172345", "6735549", "-934295", "9481935",
|
||||
"-430406", "6932717", "4087292", "4047263", "3236400", "-3863050", "4312079", "6956261", "5689446", "3871332",
|
||||
"+535", "691", "+326", "-409", "704", "-568", "+301", "951", "121", "384",
|
||||
"4969414", "9378599", "7971781", "5380630", "5001363", "1715827", "6044615", "9118925", "9956168", "-8865496",
|
||||
"5962464", "7408980", "6646513", "-634564", "4188330", "9805948", "5625691", "+7641113", "-4212929", "7802447",
|
||||
"+0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", "+8", "+9",
|
||||
"2174248", "7449361", "9896659", "-25961", "1706598", "2412368", "-4617035", "6314554", "2225957", "7521434",
|
||||
"-9530566", "3914164", "2394759", "7157744", "9919392", "6406949", "-744004", "9899789", "8380325", "-1416284",
|
||||
"3402833", "2150043", "5191009", "8979538", "9565778", "3750211", "7304823", "2829359", "6544236", "-615740",
|
||||
"363", "-627", "129", "+656", "135", "113", "381", "+646", "198", "38",
|
||||
"8060564", "-176752", "1184717", "-666343", "-1273292", "-485827", "6241066", "6579411", "8093119", "7481306",
|
||||
"-4924485", "7467889", "9813178", "7927100", "+3614859", "7293354", "9232973", "4323115", "1133911", "+9511638",
|
||||
"4443188", "2289448", "5639726", "9073898", "8540394", "5389992", "1397726", "-589230", "1017086", "1852330",
|
||||
"-840", "267", "201", "533", "-675", "494", "315", "706", "-920", "784",
|
||||
"9097353", "6002251", "-308780", "-3830169", "4340467", "2235284", "3314444", "1085967", "4152107", "+5431117",
|
||||
"-0000", "-0001", "-0002", "-0003", "-0004", "-0005", "-0006", "-0007", "-0008", "-0009",
|
||||
"-444999", "2136400", "6925907", "6990614", "3588271", "8422028", "-4034772", "5804039", "-6740545", "9381873",
|
||||
"-924923", "1652367", "2302616", "6776663", "2567821", "-248935", "2587688", "7076742", "-6461467", "1562896",
|
||||
"-768116", "2338768", "9887307", "9992184", "2045182", "2797589", "9784597", "9696554", "5113329", "1067216",
|
||||
"-76247763", "58169007", "29408062", "85342511", "42092201", "-95817703", "-1912517", "-26275135", "54656606", "-58188878",
|
||||
"+473", "74", "374", "-64", "266", "+715", "937", "-249", "249", "780",
|
||||
"3907360", "-23063423", "59062754", "83711047", "-95221044", "34894840", "-38562139", "-82018330", "14226223", "-10799717",
|
||||
"8529722", "88961903", "25608618", "-39988247", "33228241", "+38598533", "21161480", "-33723784", "8873948", "96505557",
|
||||
"-47385048", "-79413272", "-85904404", "87791158", "49194195", "13051222", "57773302", "31904423", "3142966", "27846156",
|
||||
"7420011", "-72376922", "-68873971", "23765361", "4040725", "-22359806", "85777219", "10099223", "-90364256", "-40158172",
|
||||
"-7948696", "-64344821", "34404238", "84037448", "-85084788", "-42078409", "-56550310", "96898389", "-595829", "-73166703",
|
||||
"-0", "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9",
|
||||
"2147483647", "31", "2147483610", "33", "2147483573", "37", "2147483536",
|
||||
"-82838342", "64441808", "43641062", "-64419642", "-44421934", "75232413", "-75773725", "-89139509", "12812089", "-97633526",
|
||||
"36090916", "-57706234", "17804655", "4189936", "-4100124", "38803710", "-39735126", "-62397437", "75801648", "51302332",
|
||||
"73433906", "13015224", "-12624818", "91360377", "11576319", "-54467535", "8892431", "36319780", "38832042", "50172572",
|
||||
"-317", "109", "-888", "302", "-463", "716", "+916", "665", "826", "513",
|
||||
"42423473", "41078812", "40445652", "-76722281", "95092224", "12075234", "-4045888", "-74396490", "-57304222", "-21726885",
|
||||
"92038121", "-31899682", "21589254", "-30260046", "56000244", "69686659", "+93327838", "96882881", "-91419389", "77529147",
|
||||
"+43288506", "1192435", "-74095920", "76756590", "-31184683", "-35716724", "9451980", "-63168350", "62864002", "26283194",
|
||||
"37188395", "29151634", "99343471", "-69450330", "-55680090", "-64957599", "47577948", "47107924", "2490477", "+48633003",
|
||||
"-82740809", "-24122215", "67301713", "-63649610", "75499016", "82746620", "17052193", "4602244", "-32721165", "20837836",
|
||||
"674", "+467", "+706", "889", "172", "+282", "-795", "188", "+87", "153",
|
||||
"64501793", "53146328", "5152287", "-9674493", "68105580", "57245637", "39740229", "-74071854", "86777268", "86484437",
|
||||
"-86962508", "12644427", "-62944073", "59539680", "43340539", "30661534", "20143968", "-68183731", "-48250926", "42669063",
|
||||
"+000", "+001", "+002", "+003", "+004", "+005", "+006", "+007", "+008", "+009",
|
||||
"2147483499", "71", "2147483462", "73", "2147483425", "77", "2147483388",
|
||||
"87736852", "-4444906", "-48094147", "54774735", "54571890", "-22473078", "95053418", "393654", "-33229960", "32276798",
|
||||
"-48361110", "44295939", "-79813406", "11630865", "38544571", "70972830", "-9821748", "-60965384", "-13096675", "-24569041",
|
||||
"708", "-467", "-794", "610", "+929", "766", "152", "482", "397", "-191",
|
||||
"97233152", "51028396", "-13796948", "95437272", "71352512", "-83233730", "-68517318", "61832742", "-42667174", "-18002395",
|
||||
"-92239407", "12701336", "-63830875", "41514172", "-5726049", "18668677", "69555144", "-13737009", "-22626233", "-55078143",
|
||||
"00", "11", "22", "33", "44", "-00", "-11", "-22", "-33", "-44",
|
||||
"000", "111", "222", "333", "444", "-000", "-111", "-222", "-333", "-444",
|
||||
"0000", "1111", "2222", "3333", "4444", "-0000", "-1111", "-2222", "-3333", "-4444",
|
||||
"00000", "11111", "22222", "33333", "44444", "-00000", "-11111", "-22222", "-33333", "-44444",
|
||||
"000000", "111111", "222222", "333333", "444444", "-000000", "-111111", "-222222", "-333333", "-444444",
|
||||
"0000000", "1111111", "2222222", "3333333", "4444444", "-0000000", "-1111111", "-2222222", "-3333333", "-4444444",
|
||||
"00000000", "11111111", "22222222", "33333333", "44444444", "-00000000", "-11111111", "-22222222", "-33333333", "-44444444",
|
||||
"000000000", "111111111", "222222222", "333333333", "444444444","-000000000","-111111111","-222222222","-333333333","-444444444",
|
||||
"2147483351", "51", "2147483314", "53", "-2147483648", "57", "-2147483611",
|
||||
"55", "66", "77", "88", "99", "-55", "-66", "-77", "-88", "-99",
|
||||
"555", "666", "777", "888", "999", "-555", "-666", "-777", "-888", "-999",
|
||||
"5555", "6666", "7777", "8888", "9999", "-5555", "-6666", "-7777", "-8888", "-9999",
|
||||
"55555", "66666", "77777", "88888", "99999", "-55555", "-66666", "-77777", "-88888", "-99999",
|
||||
"555555", "666666", "777777", "888888", "999999", "-555555", "-666666", "-777777", "-888888", "-999999",
|
||||
"5555555", "6666666", "7777777", "8888888", "9999999", "-5555555", "-6666666", "-7777777", "-8888888", "-9999999",
|
||||
"55555555", "66666666", "77777777", "88888888", "99999999", "-55555555", "-66666666", "-77777777", "-88888888", "-99999999",
|
||||
"555555555", "666666666", "777777777", "888888888", "999999999","-555555555","-666666666","-777777777","-888888888","-999999999",
|
||||
"-2147483574", "91", "-2147483537", "93", "-2147483500", "97", "-2147483463",
|
||||
"0000000011", "0000000022", "0000000033", "0000000044", "-000000011", "-000000022", "-000000033", "-000000044", "-000000088",
|
||||
"0000000111", "0000000222", "0000000333", "0000000444", "-000000111", "-000000222", "-000000333", "-000000444", "-000000888",
|
||||
"0000001111", "0000002222", "0000003333", "0000004444", "-000001111", "-000002222", "-000003333", "-000004444", "-000008888",
|
||||
"0000011111", "0000022222", "0000033333", "0000044444", "-000011111", "-000022222", "-000033333", "-000044444", "-000088888",
|
||||
"0000111111", "0000222222", "0000333333", "0000444444", "-000111111", "-000222222", "-000333333", "-000444444", "-000888888",
|
||||
"0001111111", "0002222222", "0003333333", "0004444444", "-001111111", "-002222222", "-003333333", "-004444444", "-008888888",
|
||||
"0011111111", "0022222222", "0033333333", "0044444444", "-011111111", "-022222222", "-033333333", "-044444444", "-088888888",
|
||||
"0111111111", "0222222222", "0333333333", "0444444444", "-111111111", "-222222222", "-333333333", "-444444444", "-888888888",
|
||||
"0000000055", "0000000066", "0000000077", "0000000088", "0000000099", "-000000055", "-000000066", "-000000077", "-000000099",
|
||||
"0000000555", "0000000666", "0000000777", "0000000888", "0000000999", "-000000555", "-000000666", "-000000777", "-000000999",
|
||||
"0000005555", "0000006666", "0000007777", "0000008888", "0000009999", "-000005555", "-000006666", "-000007777", "-000009999",
|
||||
"0000055555", "0000066666", "0000077777", "0000088888", "0000099999", "-000055555", "-000066666", "-000077777", "-000099999",
|
||||
"0000555555", "0000666666", "0000777777", "0000888888", "0000999999", "-000555555", "-000666666", "-000777777", "-000999999",
|
||||
"0005555555", "0006666666", "0007777777", "0008888888", "0009999999", "-005555555", "-006666666", "-007777777", "-009999999",
|
||||
"0055555555", "0066666666", "0077777777", "0088888888", "0099999999", "-055555555", "-066666666", "-077777777", "-099999999",
|
||||
"0555555555", "0666666666", "0777777777", "0888888888", "0999999999", "-555555555", "-666666666", "-777777777", "-999999999",
|
||||
"-2147483426", "101", "-2147483389", "103", "-2147483352", "105", "-2147483315",
|
||||
"0000001234567890", "+0000001234567890", "-0000001234567890",
|
||||
"000001234567890", "+000001234567890", "-000001234567890",
|
||||
"00001234567890", "+00001234567890", "-00001234567890",
|
||||
"0001234567890", "+0001234567890", "-0001234567890",
|
||||
"001234567890", "+001234567890", "-001234567890",
|
||||
"01234567890", "+01234567890", "-01234567890",
|
||||
"1234567890", "+1234567890", "-1234567890",
|
||||
};
|
||||
for(const std::string& st : strint_list) {
|
||||
T expected_value;
|
||||
strtod_from_string(st, expected_value);
|
||||
T result_value;
|
||||
auto result = fast_float::from_chars(st.data(), st.data() + st.size(),
|
||||
result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
printf("parsing %.*s\n", int(st.size()), st.data());
|
||||
std::cerr << " I could not parse " << std::endl;
|
||||
return false;
|
||||
}
|
||||
if(result.ptr != st.data() + st.size()) {
|
||||
printf("parsing %.*s\n", int(st.size()), st.data());
|
||||
std::cerr << " Did not get to the end " << std::endl;
|
||||
return false;
|
||||
}
|
||||
if(result_value != expected_value) {
|
||||
printf("parsing %.*s\n", int(st.size()), st.data());
|
||||
std::cerr << "expected value : " << to_string(expected_value) << std::endl;
|
||||
std::cerr << "result value : " << to_string(result_value) << std::endl;
|
||||
std::cerr << " Mismatch " << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
std::cout << "32 bits checks" << std::endl;
|
||||
Assert(partow_test<float>());
|
||||
Assert(test<float>());
|
||||
|
||||
std::cout << "64 bits checks" << std::endl;
|
||||
Assert(partow_test<double>());
|
||||
Assert(test<double>());
|
||||
|
||||
std::cout << "All ok" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
122
tests/test.cpp
Normal file
122
tests/test.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
inline void Assert(bool Assertion) {
|
||||
if (!Assertion)
|
||||
throw std::runtime_error("bug");
|
||||
}
|
||||
|
||||
template <typename T> std::string to_string(T d) {
|
||||
std::string s(64, '\0');
|
||||
auto written = std::snprintf(&s[0], s.size(), "%.*e",
|
||||
std::numeric_limits<T>::max_digits10 - 1, d);
|
||||
s.resize(written);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool demo32(std::string vals) {
|
||||
float result_value;
|
||||
auto result = fast_float::from_chars(vals.data(), vals.data() + vals.size(),
|
||||
result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << " I could not parse " << vals << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << result_value << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool demo32(std::string vals, float val) {
|
||||
float result_value;
|
||||
auto result = fast_float::from_chars(vals.data(), vals.data() + vals.size(),
|
||||
result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << " I could not parse " << vals << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (std::isnan(val)) {
|
||||
if (!std::isnan(result_value)) {
|
||||
std::cerr << "not nan" << result_value << std::endl;
|
||||
return false;
|
||||
}
|
||||
} else if (result_value != val) {
|
||||
std::cerr << "I got " << std::setprecision(15) << result_value << " but I was expecting " << val
|
||||
<< std::endl;
|
||||
uint32_t word;
|
||||
memcpy(&word, &result_value, sizeof(word));
|
||||
std::cout << "got mantissa = " << (word & ((1<<23)-1)) << std::endl;
|
||||
memcpy(&word, &val, sizeof(word));
|
||||
std::cout << "wanted mantissa = " << (word & ((1<<23)-1)) << std::endl;
|
||||
std::cerr << "string: " << vals << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << result_value << " == " << val << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool demo32(float val) {
|
||||
std::string vals = to_string(val);
|
||||
return demo32(vals, val);
|
||||
}
|
||||
|
||||
bool demo64(std::string vals, double val) {
|
||||
double result_value;
|
||||
auto result = fast_float::from_chars(vals.data(), vals.data() + vals.size(),
|
||||
result_value);
|
||||
if (result.ec != std::errc()) {
|
||||
std::cerr << " I could not parse " << vals << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (std::isnan(val)) {
|
||||
if (!std::isnan(result_value)) {
|
||||
std::cerr << "not nan" << result_value << std::endl;
|
||||
return false;
|
||||
}
|
||||
} else if (result_value != val) {
|
||||
std::cerr << "I got " << std::setprecision(15) << result_value << " but I was expecting " << val
|
||||
<< std::endl;
|
||||
std::cerr << "string: " << vals << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << result_value << " == " << val << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool demo64(double val) {
|
||||
std::string vals = to_string(val);
|
||||
return demo64(vals, val);
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "32 bits " << std::endl;
|
||||
Assert(demo64("+1", 1));
|
||||
Assert(demo64("2e3000", std::numeric_limits<float>::infinity()));
|
||||
Assert(demo32("3.5028234666e38", std::numeric_limits<float>::infinity()));
|
||||
Assert(demo32("7.0060e-46", 0));
|
||||
Assert(demo32(1.00000006e+09f));
|
||||
Assert(demo32(1.4012984643e-45f));
|
||||
Assert(demo32(1.1754942107e-38f));
|
||||
Assert(demo32(1.1754943508e-45f));
|
||||
Assert(demo32(3.4028234664e38f));
|
||||
Assert(demo32(3.4028234665e38f));
|
||||
Assert(demo32(3.4028234666e38f));
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "64 bits " << std::endl;
|
||||
Assert(demo64("+1", 1));
|
||||
Assert(demo64("2e3000", std::numeric_limits<double>::infinity()));
|
||||
Assert(demo64("1.9e308", std::numeric_limits<double>::infinity()));
|
||||
Assert(demo64(3e-324));
|
||||
Assert(demo32(1.00000006e+09f));
|
||||
Assert(demo64(4.9406564584124653e-324));
|
||||
Assert(demo64(4.9406564584124654e-324));
|
||||
Assert(demo64(2.2250738585072009e-308));
|
||||
Assert(demo64(2.2250738585072014e-308));
|
||||
Assert(demo64(1.7976931348623157e308));
|
||||
Assert(demo64(1.7976931348623158e308));
|
||||
std::cout << std::endl;
|
||||
std::cout << "All ok" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user