Skip to content

Commit 0490d8b

Browse files
committed
fix missing case in shortest string generation
"1.23e+004" now becomes "1.23e4" instead of staying the same
1 parent a726cc3 commit 0490d8b

File tree

2 files changed

+53
-51
lines changed

2 files changed

+53
-51
lines changed

benchmarks/algorithms.h

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
#define YY_DOUBLE_SUPPORTED 0
4545
#endif
4646

47-
4847
template<arithmetic_float T>
4948
struct BenchArgs {
5049
using Type = T;
@@ -63,60 +62,61 @@ struct BenchArgs {
6362

6463
namespace BenchmarkShortest {
6564

66-
6765
/**
6866
* We have that std::to_chars does not produce the shortest
6967
* representation for numbers in scientific notation, so we
7068
* optimize the string representation to be shorter.
7169
*/
7270
inline std::string optimize_number_string(const std::string &input) {
7371
// Check if input contains 'E' or 'e' for scientific notation
74-
auto e_pos = input.find_first_of("Ee");
75-
if (e_pos != std::string::npos) {
72+
if (const auto e_pos = input.find_first_of("Ee");
73+
e_pos != std::string::npos) {
7674
// Handle scientific notation
77-
std::string mantissa = input.substr(0, e_pos);
75+
const std::string mantissa = input.substr(0, e_pos);
7876
std::string exponent = input.substr(e_pos + 1);
7977

8078
// Remove leading zeros in exponent, preserving sign
81-
bool negative = exponent[0] == '-';
82-
exponent.erase(0, negative ? 1 : 0);
79+
const bool negative = exponent[0] == '-';
80+
const bool positive = exponent[0] == '+';
81+
exponent.erase(0, (negative || positive) ? 1 : 0);
8382
exponent.erase(0, exponent.find_first_not_of('0'));
8483
if (exponent.empty())
8584
exponent = "0";
8685
if (negative && exponent != "0")
8786
exponent = "-" + exponent;
8887

8988
// Reconstruct the number
90-
return mantissa + "E" + exponent;
89+
return mantissa + "e" + exponent;
9190
}
9291

9392
// Handle non-scientific notation
9493
if (input == "0" || input == "-0")
9594
return input;
9695

9796
// Determine sign
98-
bool is_negative = input[0] == '-';
99-
std::string num = is_negative ? input.substr(1) : input;
97+
const bool is_negative = input[0] == '-';
10098

10199
// Find first and last significant digits
102-
std::string digits = num;
103-
size_t decimal_pos = digits.find('.');
104-
if (decimal_pos != std::string::npos) {
105-
digits.erase(decimal_pos, 1); // Remove decimal point
100+
std::string digits = is_negative ? input.substr(1) : input;
101+
if (const size_t decimal_pos = digits.find('.');
102+
decimal_pos != std::string::npos) {
103+
digits.erase(decimal_pos, 1); // Remove decimal point
106104
}
107-
size_t first_non_zero = digits.find_first_not_of('0');
108-
size_t last_non_zero = digits.find_last_not_of('0');
105+
const size_t first_non_zero = digits.find_first_not_of('0');
106+
const size_t last_non_zero = digits.find_last_not_of('0');
109107
digits = digits.substr(first_non_zero, last_non_zero - first_non_zero + 1);
108+
110109
// Count significant digits
111-
size_t num_digits = digits.length();
110+
const size_t num_digits = digits.length();
112111
if (num_digits == 0)
113112
return input;
113+
114114
// Calculate exponent
115-
size_t input_decimal_pos = input.find('.');
116-
size_t input_first_non_zero = input.find_first_not_of('0');
117-
size_t input_last_non_zero = input.find_last_not_of('0');
115+
const size_t input_decimal_pos = input.find('.');
116+
const size_t input_first_non_zero = input.find_first_not_of('0');
117+
const size_t input_last_non_zero = input.find_last_not_of('0');
118118

119-
int exponent = 0;
119+
int exponent;
120120
if (input_decimal_pos == std::string::npos) {
121121
// we have 123232900000
122122
exponent = (input_last_non_zero - input_first_non_zero);
@@ -126,19 +126,21 @@ inline std::string optimize_number_string(const std::string &input) {
126126
} else {
127127
// Number like 0.000123
128128
exponent =
129-
-static_cast<int>(input.find_first_not_of('0', input_decimal_pos + 1) -
130-
input_decimal_pos);
129+
-static_cast<int>(input.find_first_not_of('0', input_decimal_pos + 1)
130+
- input_decimal_pos);
131131
}
132132
// Calculate scientific notation length
133-
size_t mantissa_len =
134-
num_digits + (num_digits > 1 ? 1 : 0); // Digits + optional decimal
135-
size_t exponent_len = (exponent == 0) ? 1
136-
: (exponent < 0 ? 1 : 0) +
137-
(std::abs(exponent) < 10 ? 1
138-
: std::abs(exponent) < 100 ? 2
139-
: 3);
140-
size_t sci_len = mantissa_len + 1 + exponent_len +
141-
(is_negative ? 1 : 0); // Mantissa + E + exponent + sign
133+
const size_t mantissa_len =
134+
num_digits + (num_digits > 1 ? 1 : 0); // Digits + optional decimal
135+
const size_t exponent_len = (exponent == 0)
136+
? 1
137+
: (exponent < 0 ? 1 : 0)
138+
+ (std::abs(exponent) < 10 ? 1
139+
: std::abs(exponent) < 100 ? 2
140+
: 3);
141+
const size_t sci_len =
142+
mantissa_len + 1 + exponent_len
143+
+ (is_negative ? 1 : 0); // Mantissa + E + exponent + sign
142144

143145
// Compare lengths
144146
if (sci_len >= input.length())
@@ -552,7 +554,6 @@ int std_to_chars(T d, std::span<char>& buffer) {
552554
#endif
553555
}
554556

555-
556557
} // namespace BenchmarksShortest
557558

558559
template <typename T>

benchmarks/benchmark.cpp

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ void evaluateProperties(const std::vector<TestCase<T>> &lines,
3737
}
3838

3939
struct diy_float_t {
40-
diy_float_t(uint64_t significand, int exponent, bool is_negative)
41-
: significand(significand), exponent(exponent), is_negative(is_negative) {}
42-
uint64_t significand;
43-
int exponent;
44-
bool is_negative;
40+
diy_float_t(uint64_t significand, int exponent, bool is_negative)
41+
: significand(significand), exponent(exponent), is_negative(is_negative) {}
42+
uint64_t significand;
43+
int exponent;
44+
bool is_negative;
4545
};
4646

4747
template <arithmetic_float T>
@@ -144,23 +144,24 @@ std::vector<TestCase<T>> get_random_numbers(size_t howmany,
144144
// Checks if a floating-point number is exactly representable as the specified integer type
145145
template <std::integral int_type, std::floating_point float_type>
146146
bool is_exact_integer(float_type x) {
147-
if (!std::isfinite(x)) {
148-
return false;
149-
}
150-
int_type i = static_cast<int_type>(x);
151-
return static_cast<float_type>(i) == x;
147+
if (!std::isfinite(x)) {
148+
return false;
149+
}
150+
int_type i = static_cast<int_type>(x);
151+
return static_cast<float_type>(i) == x;
152152
}
153153

154154
// New template version of describe
155155
template <typename T>
156-
void describe(const std::variant<std::vector<TestCase<float>>, std::vector<TestCase<double>>> &numbers,
157-
std::vector<BenchArgs<T>> args,
158-
const std::vector<std::string> &algo_filter) {
159-
if constexpr (std::is_same_v<T, float>) {
160-
args.push_back(get_std_to_chars_shorter<float>());
161-
} else if constexpr (std::is_same_v<T, double>) {
162-
args.push_back(get_std_to_chars_shorter<double>());
163-
}
156+
void describe(const std::variant<std::vector<TestCase<float>>,
157+
std::vector<TestCase<double>>> &numbers,
158+
std::vector<BenchArgs<T>> args,
159+
const std::vector<std::string> &algo_filter) {
160+
if constexpr (std::is_same_v<T, float>) {
161+
args.push_back(get_std_to_chars_shorter<float>());
162+
} else if constexpr (std::is_same_v<T, double>) {
163+
args.push_back(get_std_to_chars_shorter<double>());
164+
}
164165

165166
std::visit([&args, &algo_filter](const auto &lines) {
166167
size_t integers64 = 0;

0 commit comments

Comments
 (0)