Browse Source

Format: Improve the double formatting implementation

master
Riyyi 1 year ago
parent
commit
c8e4ae884e
  1. 50
      src/ruc/format/builder.cpp

50
src/ruc/format/builder.cpp

@ -5,6 +5,7 @@
*/ */
#include <algorithm> // min #include <algorithm> // min
#include <charconv> // std::to_chars
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t #include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
#include <iomanip> // setprecision #include <iomanip> // setprecision
@ -178,15 +179,46 @@ void Builder::putI64(int64_t value,
void Builder::putF64(double number, uint8_t precision) const void Builder::putF64(double number, uint8_t precision) const
{ {
precision = std::min(precision, static_cast<uint8_t>(std::numeric_limits<double>::digits10)); char buffer[512];
auto conversion = std::to_chars(buffer, buffer + sizeof(buffer), number);
std::stringstream stream; auto converted = std::string(buffer, conversion.ptr - buffer);
stream
<< std::fixed << std::setprecision(precision) size_t dot = converted.find('.');
<< number size_t length = dot + precision + 1;
<< std::defaultfloat << std::setprecision(6);
std::string string = stream.str(); // There is no number behind the decimal point
m_builder << string; if (dot == std::string::npos) {
if (precision > 0) {
converted += ".0";
}
m_builder << converted;
return;
}
// Only round if there are more numbers behind the decimal point than the precision,
// or the number that comes after the maximum precision is higher than 4
if (converted.length() > length && converted[length] > '4') {
for (size_t i = length - 1; i >= 0 && i < converted.length(); --i) {
if (converted[i] == '.') {
continue;
}
if (converted[i] < '9') { // Overflow stops here
converted[i]++;
break;
}
converted[i] = '0';
}
}
// Cut off the characters after the requested precision
if (converted.length() > length) {
size_t last_included_number = converted.find_last_not_of("0", length - 1);
// If precision is zero, also cut off the '.', otherwise include the '0' after the '.'
size_t last_character_is_dot_offset = (converted[last_included_number] == '.') ? (precision > 0 ? 1 : -1) : 0;
converted = converted.substr(0, last_included_number + last_character_is_dot_offset + 1);
}
m_builder << converted;
} }
void Builder::putString(std::string_view string, char fill, Align align, size_t width) const void Builder::putString(std::string_view string, char fill, Align align, size_t width) const

Loading…
Cancel
Save