Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 34 additions & 33 deletions benchmarks/algorithms.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
#define YY_DOUBLE_SUPPORTED 0
#endif


template<arithmetic_float T>
struct BenchArgs {
using Type = T;
Expand All @@ -63,60 +62,61 @@ struct BenchArgs {

namespace BenchmarkShortest {


/**
* We have that std::to_chars does not produce the shortest
* representation for numbers in scientific notation, so we
* optimize the string representation to be shorter.
*/
inline std::string optimize_number_string(const std::string &input) {
// Check if input contains 'E' or 'e' for scientific notation
auto e_pos = input.find_first_of("Ee");
if (e_pos != std::string::npos) {
if (const auto e_pos = input.find_first_of("Ee");
e_pos != std::string::npos) {
// Handle scientific notation
std::string mantissa = input.substr(0, e_pos);
const std::string mantissa = input.substr(0, e_pos);
std::string exponent = input.substr(e_pos + 1);

// Remove leading zeros in exponent, preserving sign
bool negative = exponent[0] == '-';
exponent.erase(0, negative ? 1 : 0);
const bool negative = exponent[0] == '-';
const bool positive = exponent[0] == '+';
exponent.erase(0, (negative || positive) ? 1 : 0);
exponent.erase(0, exponent.find_first_not_of('0'));
if (exponent.empty())
exponent = "0";
if (negative && exponent != "0")
exponent = "-" + exponent;

// Reconstruct the number
return mantissa + "E" + exponent;
return mantissa + "e" + exponent;
}

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

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

// Find first and last significant digits
std::string digits = num;
size_t decimal_pos = digits.find('.');
if (decimal_pos != std::string::npos) {
digits.erase(decimal_pos, 1); // Remove decimal point
std::string digits = is_negative ? input.substr(1) : input;
if (const size_t decimal_pos = digits.find('.');
decimal_pos != std::string::npos) {
digits.erase(decimal_pos, 1); // Remove decimal point
}
size_t first_non_zero = digits.find_first_not_of('0');
size_t last_non_zero = digits.find_last_not_of('0');
const size_t first_non_zero = digits.find_first_not_of('0');
const size_t last_non_zero = digits.find_last_not_of('0');
digits = digits.substr(first_non_zero, last_non_zero - first_non_zero + 1);

// Count significant digits
size_t num_digits = digits.length();
const size_t num_digits = digits.length();
if (num_digits == 0)
return input;

// Calculate exponent
size_t input_decimal_pos = input.find('.');
size_t input_first_non_zero = input.find_first_not_of('0');
size_t input_last_non_zero = input.find_last_not_of('0');
const size_t input_decimal_pos = input.find('.');
const size_t input_first_non_zero = input.find_first_not_of('0');
const size_t input_last_non_zero = input.find_last_not_of('0');

int exponent = 0;
int exponent;
if (input_decimal_pos == std::string::npos) {
// we have 123232900000
exponent = (input_last_non_zero - input_first_non_zero);
Expand All @@ -126,19 +126,21 @@ inline std::string optimize_number_string(const std::string &input) {
} else {
// Number like 0.000123
exponent =
-static_cast<int>(input.find_first_not_of('0', input_decimal_pos + 1) -
input_decimal_pos);
-static_cast<int>(input.find_first_not_of('0', input_decimal_pos + 1)
- input_decimal_pos);
}
// Calculate scientific notation length
size_t mantissa_len =
num_digits + (num_digits > 1 ? 1 : 0); // Digits + optional decimal
size_t exponent_len = (exponent == 0) ? 1
: (exponent < 0 ? 1 : 0) +
(std::abs(exponent) < 10 ? 1
: std::abs(exponent) < 100 ? 2
: 3);
size_t sci_len = mantissa_len + 1 + exponent_len +
(is_negative ? 1 : 0); // Mantissa + E + exponent + sign
const size_t mantissa_len =
num_digits + (num_digits > 1 ? 1 : 0); // Digits + optional decimal
const size_t exponent_len = (exponent == 0)
? 1
: (exponent < 0 ? 1 : 0)
+ (std::abs(exponent) < 10 ? 1
: std::abs(exponent) < 100 ? 2
: 3);
const size_t sci_len =
mantissa_len + 1 + exponent_len
+ (is_negative ? 1 : 0); // Mantissa + E + exponent + sign

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


} // namespace BenchmarksShortest

template <typename T>
Expand Down
37 changes: 19 additions & 18 deletions benchmarks/benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ void evaluateProperties(const std::vector<TestCase<T>> &lines,
}

struct diy_float_t {
diy_float_t(uint64_t significand, int exponent, bool is_negative)
: significand(significand), exponent(exponent), is_negative(is_negative) {}
uint64_t significand;
int exponent;
bool is_negative;
diy_float_t(uint64_t significand, int exponent, bool is_negative)
: significand(significand), exponent(exponent), is_negative(is_negative) {}
uint64_t significand;
int exponent;
bool is_negative;
};

template <arithmetic_float T>
Expand Down Expand Up @@ -144,23 +144,24 @@ std::vector<TestCase<T>> get_random_numbers(size_t howmany,
// Checks if a floating-point number is exactly representable as the specified integer type
template <std::integral int_type, std::floating_point float_type>
bool is_exact_integer(float_type x) {
if (!std::isfinite(x)) {
return false;
}
int_type i = static_cast<int_type>(x);
return static_cast<float_type>(i) == x;
if (!std::isfinite(x)) {
return false;
}
int_type i = static_cast<int_type>(x);
return static_cast<float_type>(i) == x;
}

// New template version of describe
template <typename T>
void describe(const std::variant<std::vector<TestCase<float>>, std::vector<TestCase<double>>> &numbers,
std::vector<BenchArgs<T>> args,
const std::vector<std::string> &algo_filter) {
if constexpr (std::is_same_v<T, float>) {
args.push_back(get_std_to_chars_shorter<float>());
} else if constexpr (std::is_same_v<T, double>) {
args.push_back(get_std_to_chars_shorter<double>());
}
void describe(const std::variant<std::vector<TestCase<float>>,
std::vector<TestCase<double>>> &numbers,
std::vector<BenchArgs<T>> args,
const std::vector<std::string> &algo_filter) {
if constexpr (std::is_same_v<T, float>) {
args.push_back(get_std_to_chars_shorter<float>());
} else if constexpr (std::is_same_v<T, double>) {
args.push_back(get_std_to_chars_shorter<double>());
}

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