Skip to content

Commit 208bcd0

Browse files
committed
generalize "process" function to support float
1 parent 4996733 commit 208bcd0

File tree

5 files changed

+158
-162
lines changed

5 files changed

+158
-162
lines changed

benchmarks/CMakeLists.txt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ include(CheckSourceCompiles)
77
check_source_compiles(CXX "
88
#include <charconv>
99
int main(void) {
10-
double value = 0;
10+
float valuef = 0;
11+
double valued = 0;
1112
const char* ptr;
12-
std::from_chars_result result = std::from_chars(ptr, ptr, value, std::chars_format::general);
13+
std::from_chars_result result1 = std::from_chars(ptr, ptr, valuef, std::chars_format::general);
14+
std::from_chars_result result2 = std::from_chars(ptr, ptr, valued, std::chars_format::general);
1315
return 0;
1416
}
15-
" from_chars_double)
17+
" from_chars_ok)
1618

17-
if (from_chars_double)
18-
target_compile_definitions(benchmark PUBLIC FROM_CHARS_DOUBLE_SUPPORTED=1)
19+
if (from_chars_ok)
20+
target_compile_definitions(benchmark PUBLIC FROM_CHARS_SUPPORTED=1)
1921
endif()
2022

2123
if (NOT WIN32)

benchmarks/benchmark.cpp

Lines changed: 68 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
#include "double-conversion/double-conversion.h"
2020
#include "grisu_exact.h"
2121
#include "dragon4.h"
22+
#include "schubfach_32.h"
2223
#include "schubfach_64.h"
24+
2325
#if __has_include("errol.h")
2426
#include "errol.h"
25-
#define ERROL_SUPPORTED 1
26-
#else
27-
#define ERROL_SUPPORTED 0
27+
#define ERROL_SUPPORTED
2828
#endif
2929

3030
#define IEEE_8087
@@ -39,66 +39,70 @@
3939
#include "random_generators.h"
4040
#include "ieeeToString.h"
4141

42-
#include <charconv>
42+
#include <fmt/format.h>
43+
4344
#include <climits>
4445
#include <cmath>
4546
#include <cstdio>
46-
#include <cstdlib>
47-
#include <cstring>
48-
#include <float.h>
49-
#include <fmt/format.h>
5047
#include <fstream>
5148
#include <iostream>
52-
#include <limits.h>
53-
#include <stdio.h>
5449
#include <string>
5550
#include <vector>
5651

57-
#if FROM_CHARS_DOUBLE_SUPPORTED
52+
#if FROM_CHARS_SUPPORTED
5853
#include <charconv>
5954
#endif
6055

6156
template <typename T>
6257
void process(const std::vector<T> &lines) {
63-
pretty_print(lines, "dragon4", [](const std::vector<T> &lines) -> T {
64-
T volume = 0;
58+
static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
59+
"The function currently only supports float or double");
60+
using MantissaType = std::conditional_t<std::is_same_v<T, float>,
61+
uint32_t, uint64_t>;
62+
using IEEE754Type = std::conditional_t<std::is_same_v<T, float>,
63+
IEEE754f, IEEE754d>;
64+
65+
// No dragon4 implementation optimized for float instead of double ?
66+
pretty_print(lines, "dragon4", [](const std::vector<T> &lines) -> int {
67+
int volume = 0;
6568
for (const auto d : lines) {
66-
uint64_t dmantissa;
69+
MantissaType dmantissa;
6770
int dexp;
68-
const IEEE754d fields = decode_ieee754(d);
71+
const IEEE754Type fields = decode_ieee754(d);
6972
dragon4::Dragon4(dmantissa, dexp, fields.mantissa, fields.exponent,
7073
true, true);
7174
char buffer[100];
7275
volume += to_chars(dmantissa, dexp, fields.sign, buffer);
7376
}
7477
return volume;
75-
});
78+
}, 10);
7679

77-
#if ERROL_SUPPORTED
78-
pretty_print(lines, "errol3", [](const std::vector<double> &lines) {
79-
double volume = 0;
80+
#ifdef ERROL_SUPPORTED
81+
// No errol3 implementation optimized for float instead of double ?
82+
pretty_print(lines, "errol3", [](const std::vector<T> &lines) -> int {
83+
int volume = 0;
8084
char buffer[100];
8185
for (const auto d : lines) {
82-
errol3_dtoa(d, buffer); // returns the exponent?
86+
errol3_dtoa(d, buffer); // returns the exponent
8387
volume += std::strlen(buffer);
8488
}
8589
return volume;
8690
});
8791
#else
8892
std::cout << "# errol not supported" << std::endl;
89-
#endif // ERROL_SUPPORTED
93+
#endif
9094

91-
pretty_print(lines, "std::to_string", [](const std::vector<T> &lines) -> T {
92-
T volume = 0;
95+
pretty_print(lines, "std::to_string", [](const std::vector<T> &lines) -> int {
96+
int volume = 0;
9397
for (const auto d : lines) {
9498
const std::string s = std::to_string(d);
9599
volume += s.size();
96100
}
97101
return volume;
98102
});
99103

100-
pretty_print(lines, "fmt::format", [](const std::vector<T> &lines) -> T {
101-
T volume = 0;
104+
pretty_print(lines, "fmt::format", [](const std::vector<T> &lines) -> int {
105+
int volume = 0;
102106
for (const auto d : lines) {
103107
const std::string s = fmt::format("{}", d);
104108
volume += s.size();
@@ -107,8 +111,9 @@ void process(const std::vector<T> &lines) {
107111
});
108112

109113
#if NETLIB_SUPPORTED
110-
pretty_print(lines, "netlib", [](const std::vector<T> &lines) -> T {
111-
T volume = 0;
114+
// There's no "ftoa", only "dtoa", so not optimized for float.
115+
pretty_print(lines, "netlib", [](const std::vector<T> &lines) -> int {
116+
int volume = 0;
112117
char *result;
113118
int decpt, sign;
114119
char *rve;
@@ -128,17 +133,19 @@ void process(const std::vector<T> &lines) {
128133
std::cout << "# netlib not supported" << std::endl;
129134
#endif
130135

131-
pretty_print(lines, "sprintf", [](const std::vector<T> &lines) -> T {
132-
T volume = 0;
136+
pretty_print(lines, "sprintf", [](const std::vector<T> &lines) -> int {
137+
int volume = 0;
133138
char buffer[100];
134139
for (const auto d : lines) {
135140
volume += snprintf(buffer, sizeof(buffer), "%g", d);
136141
}
137142
return volume;
138143
});
139144

140-
pretty_print(lines, "grisu2", [](const std::vector<T> &lines) -> T {
141-
T volume = 0;
145+
// grisu2::dtoa_impl::grisu2 can take a template type
146+
// However, grisu2::to_chars is hardcoded for double.
147+
pretty_print(lines, "grisu2", [](const std::vector<T> &lines) -> int {
148+
int volume = 0;
142149
char buffer[100];
143150
for (const auto d : lines) {
144151
const char *newp = grisu2::to_chars(buffer, nullptr, d);
@@ -147,8 +154,8 @@ void process(const std::vector<T> &lines) {
147154
return volume;
148155
});
149156

150-
pretty_print(lines, "grisu_exact", [](const std::vector<T> &lines) -> T {
151-
T volume = 0;
157+
pretty_print(lines, "grisu_exact", [](const std::vector<T> &lines) -> int {
158+
int volume = 0;
152159
char buffer[100];
153160
for (const auto d : lines) {
154161
auto v = jkj::grisu_exact(d);
@@ -157,54 +164,20 @@ void process(const std::vector<T> &lines) {
157164
return volume;
158165
});
159166

160-
#if FROM_CHARS_DOUBLE_SUPPORTED
161-
pretty_print(lines, "std::to_chars", [](const std::vector<double> &lines) {
162-
double volume = 0;
167+
pretty_print(lines, "schubfach", [](const std::vector<T> &lines) -> int {
168+
int volume = 0;
163169
char buffer[100];
164170
for (const auto d : lines) {
165-
const auto [p, ec] = std::to_chars(buffer, buffer + sizeof(buffer), d);
166-
if(ec != std::errc()) {
167-
std::cerr << "problem with " << d << std::endl;
168-
std::abort();
169-
}
170-
volume += p - buffer;
171-
}
172-
return volume;
173-
});
174-
#else
175-
std::cout << "# std::to_chars not supported" << std::endl;
176-
#endif
177-
178-
#if FROM_CHARS_DOUBLE_SUPPORTED
179-
pretty_print(lines, "std::to_chars", [](const std::vector<T> &lines) -> T {
180-
T volume = 0;
181-
char buffer[100];
182-
for (const auto d : lines) {
183-
const auto [p, ec] = std::to_chars(buffer, buffer + sizeof(buffer), d);
184-
if(ec != std::errc()) {
185-
std::cerr << "problem with " << d << std::endl;
186-
std::abort();
187-
}
188-
volume += p - buffer;
189-
}
190-
return volume;
191-
});
192-
#else
193-
std::cout << "# std::to_chars not supported" << std::endl;
194-
#endif
195-
196-
pretty_print(lines, "schubfach", [](const std::vector<T> &lines) -> T {
197-
T volume = 0;
198-
char buffer[100];
199-
for (const auto d : lines) {
200-
const char *end_ptr = schubfach::Dtoa(buffer, d);
171+
const char* end_ptr = std::is_same_v<T, float>
172+
? schubfach::Ftoa(buffer, d)
173+
: schubfach::Dtoa(buffer, d);
201174
volume += end_ptr - &buffer[0];
202175
}
203176
return volume;
204177
});
205178

206-
pretty_print(lines, "dragonbox", [](const std::vector<T> &lines) -> T {
207-
T volume = 0;
179+
pretty_print(lines, "dragonbox", [](const std::vector<T> &lines) -> int {
180+
int volume = 0;
208181
char buffer[100];
209182
for (const auto d : lines) {
210183
const char *end_ptr = jkj::dragonbox::to_chars(d, buffer);
@@ -213,38 +186,42 @@ void process(const std::vector<T> &lines) {
213186
return volume;
214187
});
215188

216-
pretty_print(lines, "ryu", [](const std::vector<T> &lines) -> T {
217-
T volume = 0;
189+
pretty_print(lines, "ryu", [](const std::vector<T> &lines) -> int {
190+
int volume = 0;
218191
char buffer[100];
219192
for (const auto d : lines) {
220-
volume += d2s_buffered_n(d, buffer);
193+
volume += std::is_same_v<T, float> ? f2s_buffered_n(d, buffer)
194+
: d2s_buffered_n(d, buffer);
221195
}
222196
return volume;
223197
});
224198

225-
pretty_print(lines, "teju_jagua", [](const std::vector<T> &lines) -> T {
226-
T volume = 0;
199+
pretty_print(lines, "teju_jagua", [](const std::vector<T> &lines) -> int {
200+
int volume = 0;
227201
char buffer[100];
228202
for (const auto d : lines) {
229-
const auto fields = teju::traits_t<double>::teju(d);
230-
const bool sign = (*reinterpret_cast<const uint64_t*>(&d) >> 63) & 1;
203+
const auto fields = teju::traits_t<T>::teju(d);
204+
const bool sign = std::signbit(d);
231205
volume += to_chars(fields.mantissa, fields.exponent, sign, buffer);
232206
}
233207
return volume;
234208
});
235209

236-
pretty_print(lines, "double_conversion", [](const std::vector<T> &lines) -> T {
237-
T volume = 0;
210+
pretty_print(lines, "double_conversion", [](const std::vector<T> &lines) -> int {
211+
int volume = 0;
212+
constexpr int kBufferSize = 100;
213+
char buffer[kBufferSize];
238214
const double_conversion::DoubleToStringConverter converter(
239215
double_conversion::DoubleToStringConverter::NO_FLAGS, "inf", "nan", 'e',
240216
-4, 6, 0, 0);
241-
const int kBufferSize = 100;
242-
char buffer[kBufferSize];
243217
double_conversion::StringBuilder builder(buffer, kBufferSize);
244218

245219
for (const auto d : lines) {
246220
builder.Reset();
247-
if (!converter.ToShortest(d, &builder)) {
221+
const bool valid = std::is_same_v<T, float>
222+
? converter.ToShortestSingle(d, &builder)
223+
: converter.ToShortest(d, &builder);
224+
if (!valid) {
248225
std::cerr << "problem with " << d << std::endl;
249226
std::abort();
250227
}
@@ -253,8 +230,8 @@ void process(const std::vector<T> &lines) {
253230
return volume;
254231
});
255232

256-
pretty_print(lines, "abseil", [](const std::vector<T> &lines) -> T {
257-
T volume = 0;
233+
pretty_print(lines, "abseil", [](const std::vector<T> &lines) -> int {
234+
int volume = 0;
258235
std::string buffer;
259236
for (const auto d : lines) {
260237
buffer.clear();
@@ -264,10 +241,9 @@ void process(const std::vector<T> &lines) {
264241
return volume;
265242
});
266243

267-
268-
#if FROM_CHARS_DOUBLE_SUPPORTED
269-
pretty_print(lines, "std::to_chars", [](const std::vector<double> &lines) {
270-
double volume = 0;
244+
#if FROM_CHARS_SUPPORTED
245+
pretty_print(lines, "std::to_chars", [](const std::vector<T> &lines) -> int {
246+
int volume = 0;
271247
char buffer[100];
272248
for (const auto d : lines) {
273249
const auto [p, ec] = std::to_chars(buffer, buffer + sizeof(buffer), d);
@@ -282,7 +258,6 @@ void process(const std::vector<T> &lines) {
282258
#else
283259
std::cout << "# std::to_chars not supported" << std::endl;
284260
#endif
285-
286261
}
287262

288263
void fileload(const char *filename) {

0 commit comments

Comments
 (0)