Skip to content

Commit 7d0ab1e

Browse files
authored
Merge pull request #27 from fastfloat/exhaustive32
Exhaustive 32-bit check
2 parents 8628ca0 + a213fa3 commit 7d0ab1e

File tree

7 files changed

+251
-59
lines changed

7 files changed

+251
-59
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 3.15)
1+
cmake_minimum_required(VERSION 3.28)
22

33
project(SimpleFastFloatBenchmark VERSION 0.1.0 LANGUAGES CXX C)
44
set(CMAKE_CXX_STANDARD 20)

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Currently, the following approaches are compared:
2424
- [yy_double](https://github.com/ibireme/yyjson/issues/200#issuecomment-2726783097)
2525
- [SwiftDtoa](https://github.com/swiftlang/swift/blob/main/stdlib/public/runtime/SwiftDtoa.cpp)
2626

27-
If you have a recent version of CMake (3.15 or better) under linux, you can simply
27+
If you have a recent version of CMake under linux or macOS, you can simply
2828
go in the directory and type the following commands:
2929

3030
```
@@ -33,6 +33,8 @@ cmake --build build
3333
./build/benchmarks/benchmark
3434
```
3535

36+
We also support Visual Studio, please refer to the cmake documentation.
37+
3638
You may use docker to run these benchmarks easily on a variety of platforms: see https://github.com/lemire/docker_programming_station
3739

3840
## Windows
@@ -59,6 +61,15 @@ Serialize strings generated from floats in (0,1):
5961
./build/benchmarks/benchmark
6062
```
6163

64+
## Exhaustive 32-bit check
65+
66+
We also include an exhaustive check of all 32-bit floats, to verify
67+
that we can produce the shortest string representation.
68+
69+
```
70+
./build/benchmarks/exhaustivefloat32
71+
```
72+
6273
## Other existing benchmarks
6374

6475
- [dtoa Benchmark](https://github.com/miloyip/dtoa-benchmark)

benchmarks/CMakeLists.txt

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
add_executable(benchmark
22
benchmark.cpp
3-
ieeeToString.cpp
43
)
5-
4+
add_library(benchmark_deps INTERFACE)
5+
add_library(ieeeToString ieeeToString.cpp)
6+
target_include_directories(ieeeToString PRIVATE ${ryu_SOURCE_DIR})
7+
target_link_libraries(benchmark_deps INTERFACE ieeeToString)
68
include(CheckSourceCompiles)
79
check_source_compiles(CXX "
810
#include <charconv>
@@ -15,7 +17,7 @@ int main(void) {
1517
return 0;
1618
}
1719
" FROM_CHARS_OK)
18-
target_compile_definitions(benchmark PUBLIC FROM_CHARS_SUPPORTED=$<IF:$<BOOL:${FROM_CHARS_OK}>,1,0>)
20+
target_compile_definitions(benchmark_deps INTERFACE FROM_CHARS_SUPPORTED=$<IF:$<BOOL:${FROM_CHARS_OK}>,1,0>)
1921
check_source_compiles(CXX "
2022
#include <charconv>
2123
int main(void) {
@@ -27,7 +29,7 @@ int main(void) {
2729
return 0;
2830
}
2931
" TO_CHARS_OK)
30-
target_compile_definitions(benchmark PUBLIC TO_CHARS_SUPPORTED=$<IF:$<BOOL:${TO_CHARS_OK}>,1,0>)
32+
target_compile_definitions(benchmark_deps INTERFACE TO_CHARS_SUPPORTED=$<IF:$<BOOL:${TO_CHARS_OK}>,1,0>)
3133
if(TO_CHARS_OK)
3234
message(STATUS "std::to_chars with floats is supported")
3335
else(TO_CHARS_OK)
@@ -42,45 +44,55 @@ CPMAddPackage(
4244
NAME fast_float
4345
GITHUB_REPOSITORY "fastfloat/fast_float"
4446
GIT_TAG v8.0.2)
45-
target_link_libraries(benchmark PUBLIC fast_float)
47+
target_link_libraries(benchmark_deps INTERFACE fast_float)
4648
if (NOT WIN32)
47-
target_link_libraries(benchmark PUBLIC netlib)
48-
target_compile_definitions(benchmark PUBLIC NETLIB_SUPPORTED=1)
49+
target_link_libraries(benchmark_deps INTERFACE netlib)
50+
target_compile_definitions(benchmark_deps INTERFACE NETLIB_SUPPORTED=1)
4951
else()
50-
target_compile_definitions(benchmark PUBLIC NETLIB_SUPPORTED=0)
52+
target_compile_definitions(benchmark_deps INTERFACE NETLIB_SUPPORTED=0)
5153
endif()
5254

5355
if (NOT CYGWIN)
54-
target_link_libraries(benchmark PUBLIC absl::str_format)
55-
target_compile_definitions(benchmark PUBLIC ABSEIL_SUPPORTED=1)
56+
target_link_libraries(benchmark_deps INTERFACE absl::str_format)
57+
target_compile_definitions(benchmark_deps INTERFACE ABSEIL_SUPPORTED=1)
5658
else()
57-
target_compile_definitions(benchmark PUBLIC ABSEIL_SUPPORTED=0)
59+
target_compile_definitions(benchmark_deps INTERFACE ABSEIL_SUPPORTED=0)
5860
endif()
5961

6062
if(TARGET errol)
61-
target_link_libraries(benchmark PUBLIC errol)
62-
target_compile_definitions(benchmark PUBLIC ERROL_SUPPORTED=1)
63+
target_link_libraries(benchmark_deps INTERFACE errol)
64+
target_compile_definitions(benchmark_deps INTERFACE ERROL_SUPPORTED=1)
6365
else()
64-
target_compile_definitions(benchmark PUBLIC ERROL_SUPPORTED=0)
66+
target_compile_definitions(benchmark_deps INTERFACE ERROL_SUPPORTED=0)
6567
endif()
6668

67-
target_link_libraries(benchmark PUBLIC fmt)
68-
target_link_libraries(benchmark PUBLIC cxxopts)
69+
target_link_libraries(benchmark_deps INTERFACE fmt)
70+
target_link_libraries(benchmark_deps INTERFACE cxxopts)
6971

70-
target_link_libraries(benchmark PUBLIC yy_double)
71-
target_link_libraries(benchmark PUBLIC double-conversion)
72-
target_link_libraries(benchmark PUBLIC ryu::ryu)
73-
target_link_libraries(benchmark PUBLIC teju)
72+
target_link_libraries(benchmark_deps INTERFACE yy_double)
73+
target_link_libraries(benchmark_deps INTERFACE double-conversion)
74+
target_link_libraries(benchmark_deps INTERFACE ryu::ryu)
75+
target_link_libraries(benchmark_deps INTERFACE teju)
7476
if(teju_has_float128)
75-
target_link_libraries(benchmark PUBLIC teju_boost_multiprecision)
77+
target_link_libraries(benchmark_deps INTERFACE teju_boost_multiprecision)
7678
endif()
77-
target_link_libraries(benchmark PUBLIC dragonbox::dragonbox_to_chars)
78-
target_link_libraries(benchmark PUBLIC dragon_schubfach_lib)
79-
target_link_libraries(benchmark PUBLIC dragon4_lib)
79+
target_link_libraries(benchmark_deps INTERFACE dragonbox::dragonbox_to_chars)
80+
target_link_libraries(benchmark_deps INTERFACE dragon_schubfach_lib)
81+
target_link_libraries(benchmark_deps INTERFACE dragon4_lib)
8082
if(TARGET swift_lib)
81-
target_link_libraries(benchmark PUBLIC swift_lib)
82-
target_compile_definitions(benchmark PUBLIC SWIFT_LIB_SUPPORTED=1)
83+
target_link_libraries(benchmark_deps INTERFACE swift_lib)
84+
target_compile_definitions(benchmark_deps INTERFACE SWIFT_LIB_SUPPORTED=1)
8385
else(TARGET swift_lib)
84-
target_compile_definitions(benchmark PUBLIC SWIFT_LIB_SUPPORTED=0)
86+
target_compile_definitions(benchmark_deps INTERFACE SWIFT_LIB_SUPPORTED=0)
8587
endif(TARGET swift_lib)
86-
target_include_directories(benchmark PUBLIC ${grisu-exact_SOURCE_DIR})
88+
target_include_directories(benchmark_deps INTERFACE ${grisu-exact_SOURCE_DIR})
89+
90+
target_link_libraries(benchmark PUBLIC benchmark_deps)
91+
92+
if(TO_CHARS_OK AND FROM_CHARS_OK)
93+
add_executable(exhaustivefloat32
94+
exhaustivefloat32.cpp
95+
)
96+
target_link_libraries(exhaustivefloat32 PUBLIC benchmark_deps)
97+
endif(TO_CHARS_OK AND FROM_CHARS_OK)
98+

benchmarks/algorithms.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <fmt/format.h>
2121

22+
#include <array>
2223
#include <span>
2324

2425
#include "cpp/common/traits.hpp" // Teju Jagua
@@ -266,7 +267,7 @@ int abseil(T d, std::span<char>& buffer) {
266267
// absl::StrAppend(&s, d);
267268
// std::copy(s.begin(), s.end(), buffer.begin());
268269
// return size(s);
269-
return absl::SNPrintF(buffer.data(), buffer.size(), "%.17g", d);
270+
return absl::SNPrintF(buffer.data(), buffer.size(), "%g", d);
270271
}
271272

272273
template<arithmetic_float T>
@@ -285,6 +286,31 @@ int std_to_chars(T d, std::span<char>& buffer) {
285286
#endif
286287
}
287288

289+
290+
template <arithmetic_float T>
291+
std::array<BenchArgs<T>, Benchmarks::COUNT> initArgs(bool errol = false) {
292+
std::array<BenchArgs<T>, Benchmarks::COUNT> args;
293+
args[Benchmarks::DRAGON4] = { "dragon4" , Benchmarks::dragon4<T> , true , 10 };
294+
args[Benchmarks::ERROL3] = { "errol3" , Benchmarks::errol3<T> , errol };
295+
args[Benchmarks::TO_STRING] = { "std::to_string" , Benchmarks::to_string<T> , ERROL_SUPPORTED };
296+
args[Benchmarks::FMT_FORMAT] = { "fmt::format" , Benchmarks::fmt_format<T> , true };
297+
args[Benchmarks::NETLIB] = { "netlib" , Benchmarks::netlib<T> , NETLIB_SUPPORTED && std::is_same_v<T, double>, 10 };
298+
args[Benchmarks::SNPRINTF] = { "snprintf" , Benchmarks::snprintf<T> , true };
299+
args[Benchmarks::GRISU2] = { "grisu2" , Benchmarks::grisu2<T> , std::is_same_v<T, double> };
300+
args[Benchmarks::GRISU_EXACT] = { "grisu_exact" , Benchmarks::grisu_exact<T> , true };
301+
args[Benchmarks::SCHUBFACH] = { "schubfach" , Benchmarks::schubfach<T> , true };
302+
args[Benchmarks::DRAGONBOX] = { "dragonbox" , Benchmarks::dragonbox<T> , true };
303+
args[Benchmarks::RYU] = { "ryu" , Benchmarks::ryu<T> , true };
304+
args[Benchmarks::TEJU_JAGUA] = { "teju_jagua" , Benchmarks::teju_jagua<T> , true };
305+
args[Benchmarks::DOUBLE_CONVERSION] = { "double_conversion" , Benchmarks::double_conversion<T> , true };
306+
args[Benchmarks::ABSEIL] = { "abseil" , Benchmarks::abseil<T> , ABSEIL_SUPPORTED };
307+
args[Benchmarks::STD_TO_CHARS] = { "std::to_chars" , Benchmarks::std_to_chars<T> , TO_CHARS_SUPPORTED };
308+
args[Benchmarks::GRISU3] = { "grisu3" , Benchmarks::grisu3<T> , std::is_same_v<T, double> };
309+
args[Benchmarks::SWIFT_DTOA] = { "SwiftDtoa" , Benchmarks::swiftDtoa<T> , SWIFT_LIB_SUPPORTED };
310+
args[Benchmarks::YY_DOUBLE] = { "yy_double" , Benchmarks::yy_double<T> , YY_DOUBLE_SUPPORTED && std::is_same_v<T, double> };
311+
return args;
312+
};
313+
288314
} // namespace Benchmarks
289315

290316
#endif

benchmarks/benchmark.cpp

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ void evaluateProperties(const std::vector<T> &lines,
6060
assert(ptrAlgo == bufAlgo.data() + vAlgo);
6161
assert(ecAlgo == std::errc());
6262
if ((incorrect += (d != dAlgo)) == 1)
63-
fmt::println("\t{:20} mismatch: d = {:.17f}, bufRef = {}, bufAlgo = {}, dAlgo = {:.17f}",
63+
fmt::println("#\t{:20} mismatch: d = {:.17f}, bufRef = {}, bufAlgo = {}, dAlgo = {:.17f}",
6464
algo.name, d, bufRef.data(), bufAlgo.data(), dAlgo);
6565
}
6666
fmt::println("{:20} {:20}", algo.name, incorrect == 0 ? "yes" : "no");
@@ -178,36 +178,13 @@ int main(int argc, char **argv) {
178178
numbers = fileload<double>(filename);
179179
}
180180

181-
auto initArgs = [&](auto type) {
182-
using T = decltype(type);
183-
std::array<BenchArgs<T>, Benchmarks::COUNT> args;
184-
args[Benchmarks::DRAGON4] = { "dragon4" , Benchmarks::dragon4<T> , true , 10 };
185-
args[Benchmarks::ERROL3] = { "errol3" , Benchmarks::errol3<T> , result["errol"].as<bool>() };
186-
args[Benchmarks::TO_STRING] = { "std::to_string" , Benchmarks::to_string<T> , ERROL_SUPPORTED };
187-
args[Benchmarks::FMT_FORMAT] = { "fmt::format" , Benchmarks::fmt_format<T> , true };
188-
args[Benchmarks::NETLIB] = { "netlib" , Benchmarks::netlib<T> , NETLIB_SUPPORTED , 10 };
189-
args[Benchmarks::SNPRINTF] = { "snprintf" , Benchmarks::snprintf<T> , true };
190-
args[Benchmarks::GRISU2] = { "grisu2" , Benchmarks::grisu2<T> , true };
191-
args[Benchmarks::GRISU_EXACT] = { "grisu_exact" , Benchmarks::grisu_exact<T> , true };
192-
args[Benchmarks::SCHUBFACH] = { "schubfach" , Benchmarks::schubfach<T> , true };
193-
args[Benchmarks::DRAGONBOX] = { "dragonbox" , Benchmarks::dragonbox<T> , true };
194-
args[Benchmarks::RYU] = { "ryu" , Benchmarks::ryu<T> , true };
195-
args[Benchmarks::TEJU_JAGUA] = { "teju_jagua" , Benchmarks::teju_jagua<T> , true };
196-
args[Benchmarks::DOUBLE_CONVERSION] = { "double_conversion" , Benchmarks::double_conversion<T> , true };
197-
args[Benchmarks::ABSEIL] = { "abseil" , Benchmarks::abseil<T> , ABSEIL_SUPPORTED };
198-
args[Benchmarks::STD_TO_CHARS] = { "std::to_chars" , Benchmarks::std_to_chars<T> , TO_CHARS_SUPPORTED };
199-
args[Benchmarks::GRISU3] = { "grisu3" , Benchmarks::grisu3<T> , true };
200-
args[Benchmarks::SWIFT_DTOA] = { "SwiftDtoa" , Benchmarks::swiftDtoa<T> , SWIFT_LIB_SUPPORTED };
201-
args[Benchmarks::YY_DOUBLE] = { "yy_double" , Benchmarks::yy_double<T> , YY_DOUBLE_SUPPORTED };
202-
return args;
203-
};
204-
205181
std::variant<std::array<BenchArgs<float>, Benchmarks::COUNT>,
206182
std::array<BenchArgs<double>, Benchmarks::COUNT>> algorithms;
183+
const bool errol = result["errol"].as<bool>();
207184
if (single)
208-
algorithms = initArgs(float{});
185+
algorithms = Benchmarks::initArgs<float>(errol);
209186
else
210-
algorithms = initArgs(double{});
187+
algorithms = Benchmarks::initArgs<double>(errol);
211188

212189
const bool test = result["test"].as<bool>();
213190
std::visit([test](const auto &lines, const auto &args) {

0 commit comments

Comments
 (0)