Skip to content

Commit eb1d813

Browse files
committed
Remove some redundencies and fix some typos
1 parent 96fefa1 commit eb1d813

File tree

7 files changed

+98
-128
lines changed

7 files changed

+98
-128
lines changed

benchmarks/algorithms.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "grisu3.h"
3131
#include "grisu_exact.h"
3232
#include "ieeeToString.h"
33+
#include "floatutils.h"
3334
#include "ryu/ryu.h"
3435
#include "schubfach_32.h"
3536
#include "schubfach_64.h"
@@ -67,10 +68,6 @@ enum Algorithm {
6768
COUNT // Keep last
6869
};
6970

70-
template<typename T>
71-
concept arithmetic_float
72-
= std::is_same_v<T, float> || std::is_same_v<T, double>;
73-
7471
template<arithmetic_float T>
7572
struct BenchArgs {
7673
using Type = T;

benchmarks/benchmark.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
*/
99

1010
#include "algorithms.h"
11-
#include <vector>
1211
#define IEEE_8087
1312
#include "benchutil.h"
1413
#include "cxxopts.hpp"
@@ -22,10 +21,10 @@
2221
#include <iostream>
2322
#include <string>
2423
#include <variant>
24+
#include <vector>
2525
#include <fast_float/fast_float.h>
2626
#include <fmt/core.h>
2727

28-
using Benchmarks::arithmetic_float;
2928
using Benchmarks::BenchArgs;
3029

3130
bool is_matched(const std::string &str, const std::span<std::string> filter) {
@@ -42,8 +41,8 @@ bool is_matched(const std::string &str, const std::span<std::string> filter) {
4241

4342
template <arithmetic_float T>
4443
void evaluateProperties(const std::vector<T> &lines,
45-
const std::array<BenchArgs<T>, Benchmarks::COUNT> &args, const std::span<std::string> filter = {}) {
46-
constexpr auto precision = std::numeric_limits<T>::digits10;
44+
const std::array<BenchArgs<T>, Benchmarks::COUNT> &args,
45+
const std::span<std::string> filter = {}) {
4746
fmt::println("{:20} {:20}", "Algorithm", "Valid round-trip");
4847

4948
for (const auto &algo : args) {

benchmarks/benchutil.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ event_aggregate bench(const function_type &&function, size_t min_repeat = 10,
1717
N = 1;
1818
}
1919
volatile double dontoptimize = 0.0;
20-
// We warmm up first. We warmup for at least 0.4s (by default). This makes
20+
// We warm up first. We warmup for at least 0.4s (by default). This makes
2121
// sure that the processor is in a consistent state.
2222
event_aggregate warm_aggregate{};
2323
for (size_t i = 0; i < N; i++) {
@@ -89,4 +89,5 @@ void pretty_print(const std::vector<T> &lines, const std::string &name,
8989
printf("\n");
9090
}
9191
}
92+
9293
#endif //// BENCHUTIL_H

benchmarks/exhaustivefloat32.cpp

Lines changed: 13 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -12,56 +12,9 @@
1212

1313
#include "algorithms.h"
1414
#include "cxxopts.hpp"
15-
16-
size_t count_significant_digits(std::string_view num_str) {
17-
size_t count = 0;
18-
size_t trailing_zeros = 0;
19-
bool leading_zero = true;
20-
21-
for (char c : num_str) {
22-
if (c == '.')
23-
continue;
24-
if (c == 'e' || c == 'E')
25-
break; // Stop counting at exponent
26-
if (std::isdigit(static_cast<unsigned char>(c))) {
27-
if (c == '0') {
28-
if (!leading_zero)
29-
trailing_zeros++;
30-
continue;
31-
}
32-
leading_zero = false;
33-
count += trailing_zeros + 1;
34-
trailing_zeros = 0;
35-
}
36-
}
37-
38-
return count;
39-
}
40-
41-
std::string float_to_hex(float f) {
42-
std::ostringstream oss;
43-
oss << std::hexfloat << f;
44-
return oss.str();
45-
}
46-
47-
std::optional<float> parse_float(std::string_view sv) {
48-
float result;
49-
const char* begin = sv.data();
50-
const char* end = sv.data() + sv.size();
51-
52-
auto [ptr, ec] = std::from_chars(begin, end, result);
53-
54-
// Check if parsing succeeded and consumed the entire string
55-
if (ec == std::errc{} && ptr == end) {
56-
return result;
57-
}
58-
59-
// Return nullopt if parsing failed or didn't consume all input
60-
return std::nullopt;
61-
}
15+
#include "floatutils.h"
6216

6317
void run_exhaustive32(bool errol, const std::vector<std::string>& algo_filter = {}) {
64-
constexpr auto precision = std::numeric_limits<float>::digits10;
6518
fmt::println("{:20} {:20}", "Algorithm", "Valid shortest serialization");
6619

6720
std::array<Benchmarks::BenchArgs<float>, Benchmarks::COUNT> args;
@@ -110,7 +63,7 @@ void run_exhaustive32(bool errol, const std::vector<std::string>& algo_filter =
11063
continue;
11164
// Reference output, we cannot use std::to_chars here, because it produces
11265
// the shortest representation, which is not necessarily the same as the
113-
// as the representation using the fewest significant digits.
66+
// representation using the fewest significant digits.
11467
// So we use dragonbox, which serves as the reference implementation.
11568
const size_t vRef = Benchmarks::dragonbox(d, bufRef);
11669
const size_t vAlgo = algo.func(d, bufAlgo);
@@ -120,12 +73,12 @@ void run_exhaustive32(bool errol, const std::vector<std::string>& algo_filter =
12073

12174
auto countRef = count_significant_digits(svRef);
12275
auto countAlgo = count_significant_digits(svAlgo);
123-
auto backRef = parse_float(svRef);
124-
auto backAlgo = parse_float(svAlgo);
76+
auto backRef = parse_float<float>(svRef);
77+
auto backAlgo = parse_float<float>(svAlgo);
12578
if(!backRef || !backAlgo) {
12679
incorrect = true;
127-
fmt::print(" parse error: d = {}, bufRef = {}, bufAlgo = {}", float_to_hex(d),
128-
svRef, svAlgo);
80+
fmt::print(" parse error: d = {}, bufRef = {}, bufAlgo = {}",
81+
float_to_hex<float>(d), svRef, svAlgo);
12982
fflush(stdout);
13083
break;
13184
}
@@ -134,20 +87,23 @@ void run_exhaustive32(bool errol, const std::vector<std::string>& algo_filter =
13487
}
13588
if(*backRef != d) {
13689
incorrect = true;
137-
fmt::print(" ref mismatch: d = {}, backRef = {}; svRef = {}, svAlgo = {}", float_to_hex(d), *backRef, svRef, svAlgo);
90+
fmt::print(" ref mismatch: d = {}, backRef = {}; svRef = {}, svAlgo = {}",
91+
float_to_hex<float>(d), *backRef, svRef, svAlgo);
13892
fflush(stdout);
13993
break;
14094
}
14195
if(*backAlgo != d) {
14296
incorrect = true;
143-
fmt::print(" algo mismatch: d = {}, backAlgo = {}; svRef = {}, svAlgo = {}, parsing the output with std::from_chars does not recover the original", float_to_hex(d), *backAlgo, svRef, svAlgo);
97+
fmt::print(" algo mismatch: d = {}, backAlgo = {}; svRef = {}, svAlgo = {}, "
98+
"parsing the output with std::from_chars does not recover the original",
99+
float_to_hex<float>(d), *backAlgo, svRef, svAlgo);
144100
fflush(stdout);
145101
break;
146102
}
147103
if (countRef != countAlgo) {
148104
incorrect = true;
149-
fmt::print(" mismatch: d = {}, bufRef = {}, bufAlgo = {}", float_to_hex(d),
150-
svRef, svAlgo);
105+
fmt::print(" mismatch: d = {}, bufRef = {}, bufAlgo = {}",
106+
float_to_hex<float>(d), svRef, svAlgo);
151107
fflush(stdout);
152108
break;
153109
}

benchmarks/floatutils.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#ifndef FLOATUTILS_H
2+
#define FLOATUTILS_H
3+
4+
#include <charconv>
5+
#include <string>
6+
#include <sstream>
7+
#include <optional>
8+
9+
template<typename T>
10+
concept arithmetic_float
11+
= std::is_same_v<T, float> || std::is_same_v<T, double>;
12+
13+
size_t count_significant_digits(std::string_view num_str) {
14+
size_t count = 0;
15+
size_t trailing_zeros = 0;
16+
bool leading_zero = true;
17+
18+
for (char c : num_str) {
19+
if (c == '.')
20+
continue;
21+
if (c == 'e' || c == 'E')
22+
break; // Stop counting at exponent
23+
if (std::isdigit(static_cast<unsigned char>(c))) {
24+
if (c == '0') {
25+
if (!leading_zero)
26+
trailing_zeros++;
27+
continue;
28+
}
29+
leading_zero = false;
30+
count += trailing_zeros + 1;
31+
trailing_zeros = 0;
32+
}
33+
}
34+
35+
return count;
36+
}
37+
38+
template <arithmetic_float T>
39+
std::string float_to_hex(const T f) {
40+
std::ostringstream oss;
41+
oss << std::hexfloat << f;
42+
return oss.str();
43+
}
44+
45+
template <arithmetic_float T>
46+
std::optional<T> parse_float(std::string_view sv) {
47+
T result;
48+
const char* begin = sv.data();
49+
const char* end = sv.data() + sv.size();
50+
51+
auto [ptr, ec] = std::from_chars(begin, end, result);
52+
53+
// Check if parsing succeeded and consumed the entire string
54+
if (ec == std::errc{} && ptr == end) {
55+
return result;
56+
}
57+
58+
// Return nullopt if parsing failed or didn't consume all input
59+
return std::nullopt;
60+
}
61+
62+
#endif

benchmarks/string_format.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ template <typename T> std::string accurate_to_string(T d) {
2222
answer.resize(written);
2323
return answer;
2424
}
25+
2526
template <typename T> std::string integer_to_string(T d) {
2627
std::stringstream ss;
2728
ss << d;

benchmarks/thoroughfloat64.cpp

Lines changed: 16 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -14,53 +14,7 @@
1414

1515
#include "algorithms.h"
1616
#include "cxxopts.hpp"
17-
18-
size_t count_significant_digits(std::string_view num_str) {
19-
size_t count = 0;
20-
size_t trailing_zeros = 0;
21-
bool leading_zero = true;
22-
23-
for (char c : num_str) {
24-
if (c == '.')
25-
continue;
26-
if (c == 'e' || c == 'E')
27-
break; // Stop counting at exponent
28-
if (std::isdigit(static_cast<unsigned char>(c))) {
29-
if (c == '0') {
30-
if (!leading_zero)
31-
trailing_zeros++;
32-
continue;
33-
}
34-
leading_zero = false;
35-
count += trailing_zeros + 1;
36-
trailing_zeros = 0;
37-
}
38-
}
39-
40-
return count;
41-
}
42-
43-
std::string double_to_hex(double d) {
44-
std::ostringstream oss;
45-
oss << std::hexfloat << d;
46-
return oss.str();
47-
}
48-
49-
std::optional<double> parse_double(std::string_view sv) {
50-
double result;
51-
const char* begin = sv.data();
52-
const char* end = sv.data() + sv.size();
53-
54-
auto [ptr, ec] = std::from_chars(begin, end, result);
55-
56-
// Check if parsing succeeded and consumed the entire string
57-
if (ec == std::errc{} && ptr == end) {
58-
return result;
59-
}
60-
61-
// Return nullopt if parsing failed or didn't consume all input
62-
return std::nullopt;
63-
}
17+
#include "floatutils.h"
6418

6519
struct test_case {
6620
double value;
@@ -71,27 +25,24 @@ struct test_case {
7125
std::vector<test_case> load_doubles_from_file(const std::string& filename) {
7226
std::vector<test_case> numbers;
7327
std::ifstream file(filename);
74-
std::string line;
7528

7629
if (!file.is_open()) {
7730
fmt::print("Error: Could not open file {}\n", filename);
7831
return numbers;
7932
}
8033

81-
while (std::getline(file, line)) {
82-
if (auto num = parse_double(line)) {
34+
for (std::string line; std::getline(file, line);) {
35+
if (auto num = parse_float<double>(line))
8336
numbers.emplace_back(*num,line);
84-
} else {
37+
else
8538
fmt::print("Warning: Could not parse '{}' as double, skipping\n", line);
86-
}
8739
}
8840

8941
file.close();
9042
return numbers;
9143
}
9244

9345
void run_file_test(const std::string& filename, bool errol, const std::vector<std::string>& algo_filter = {}) {
94-
constexpr auto precision = std::numeric_limits<double>::digits10;
9546
fmt::println("{:20} {:20}", "Algorithm", "Valid shortest serialization");
9647

9748
std::array<Benchmarks::BenchArgs<double>, Benchmarks::COUNT> args;
@@ -155,13 +106,13 @@ void run_file_test(const std::string& filename, bool errol, const std::vector<st
155106

156107
auto countRef = count_significant_digits(svRef);
157108
auto countAlgo = count_significant_digits(svAlgo);
158-
auto backRef = parse_double(svRef);
159-
auto backAlgo = parse_double(svAlgo);
109+
auto backRef = parse_float<double>(svRef);
110+
auto backAlgo = parse_float<double>(svAlgo);
160111

161112
if(!backRef || !backAlgo) {
162113
incorrect = true;
163-
fmt::print(" parse error: case: {}; d = {}, bufRef = {}, bufAlgo = {}", str_value, double_to_hex(d),
164-
svRef, svAlgo);
114+
fmt::print(" parse error: case: {}; d = {}, bufRef = {}, bufAlgo = {}",
115+
str_value, float_to_hex<double>(d), svRef, svAlgo);
165116
fflush(stdout);
166117
break;
167118
}
@@ -170,20 +121,23 @@ void run_file_test(const std::string& filename, bool errol, const std::vector<st
170121
}
171122
if(*backRef != d) {
172123
incorrect = true;
173-
fmt::print(" ref mismatch:case: {}; d = {}, backRef = {}; svRef = {}, svAlgo = {}", str_value, double_to_hex(d), *backRef, svRef, svAlgo);
124+
fmt::print(" ref mismatch:case: {}; d = {}, backRef = {}; svRef = {}, svAlgo = {}",
125+
str_value, float_to_hex<double>(d), *backRef, svRef, svAlgo);
174126
fflush(stdout);
175127
break;
176128
}
177129
if(*backAlgo != d) {
178130
incorrect = true;
179-
fmt::print(" algo mismatch: case: {}; d = {}, backAlgo = {}; svRef = {}, svAlgo = {}, parsing the output with std::from_chars does not recover the original", str_value, double_to_hex(d), *backAlgo, svRef, svAlgo);
131+
fmt::print(" algo mismatch: case: {}; d = {}, backAlgo = {}; svRef = {}, svAlgo = {}, "
132+
"parsing the output with std::from_chars does not recover the original",
133+
str_value, float_to_hex<double>(d), *backAlgo, svRef, svAlgo);
180134
fflush(stdout);
181135
break;
182136
}
183137
if (countRef != countAlgo) {
184138
incorrect = true;
185-
fmt::print(" mismatch: case: {}; d = {}, bufRef = {}, bufAlgo = {}", str_value, double_to_hex(d),
186-
svRef, svAlgo);
139+
fmt::print(" mismatch: case: {}; d = {}, bufRef = {}, bufAlgo = {}",
140+
str_value, float_to_hex<double>(d), svRef, svAlgo);
187141
fflush(stdout);
188142
break;
189143
}
@@ -222,4 +176,4 @@ int main(int argc, char **argv) {
222176
fmt::print("error parsing options: {}\n", e.what());
223177
return EXIT_FAILURE;
224178
}
225-
}
179+
}

0 commit comments

Comments
 (0)