Fix scientific formatting when exponent is 0

This commit is contained in:
Matt Borland
2023-05-02 15:37:57 +02:00
parent 3a6821d6cd
commit 30edfaeb32
3 changed files with 31 additions and 22 deletions

View File

@@ -26,6 +26,7 @@
#include <boost/charconv/detail/dragonbox_common.hpp>
#include <boost/charconv/detail/bit_layouts.hpp>
#include <boost/charconv/detail/emulated128.hpp>
#include <boost/charconv/chars_format.hpp>
#include <boost/core/bit.hpp>
#include <type_traits>
#include <limits>
@@ -2559,11 +2560,11 @@ BOOST_FORCEINLINE BOOST_CHARCONV_SAFEBUFFERS auto to_decimal(Float x, Policies..
namespace to_chars_detail {
template <class Float, class FloatTraits>
extern char* to_chars(typename FloatTraits::carrier_uint significand, int exponent, char* buffer) noexcept;
extern char* to_chars(typename FloatTraits::carrier_uint significand, int exponent, char* buffer, chars_format fmt) noexcept;
// Avoid needless ABI overhead incurred by tag dispatch.
template <class PolicyHolder, class Float, class FloatTraits>
char* to_chars_n_impl(dragonbox_float_bits<Float, FloatTraits> br, char* buffer) noexcept
char* to_chars_n_impl(dragonbox_float_bits<Float, FloatTraits> br, char* buffer, chars_format fmt) noexcept
{
const auto exponent_bits = br.extract_exponent_bits();
const auto s = br.remove_exponent_bits(exponent_bits);
@@ -2583,7 +2584,7 @@ namespace to_chars_detail {
typename PolicyHolder::binary_to_decimal_rounding_policy{},
typename PolicyHolder::cache_policy{});
return to_chars_detail::to_chars<Float, FloatTraits>(result.significand,
result.exponent, buffer);
result.exponent, buffer, fmt);
}
else
{
@@ -2664,7 +2665,7 @@ namespace to_chars_detail {
// Returns the next-to-end position
template <typename Float, typename FloatTraits = dragonbox_float_traits<Float>, typename... Policies>
char* to_chars_n(Float x, char* buffer, BOOST_ATTRIBUTE_UNUSED Policies... policies) noexcept
char* to_chars_n(Float x, char* buffer, chars_format fmt, BOOST_ATTRIBUTE_UNUSED Policies... policies) noexcept
{
using namespace policy_impl;
@@ -2686,14 +2687,14 @@ char* to_chars_n(Float x, char* buffer, BOOST_ATTRIBUTE_UNUSED Policies... polic
#endif
return to_chars_detail::to_chars_n_impl<policy_holder>(dragonbox_float_bits<Float, FloatTraits>(x), buffer);
return to_chars_detail::to_chars_n_impl<policy_holder>(dragonbox_float_bits<Float, FloatTraits>(x), buffer, fmt);
}
// Null-terminate and bypass the return value of fp_to_chars_n
template <typename Float, typename FloatTraits = dragonbox_float_traits<Float>, typename... Policies>
char* to_chars(Float x, char* buffer, Policies... policies) noexcept
char* to_chars(Float x, char* buffer, chars_format fmt, Policies... policies) noexcept
{
auto ptr = to_chars_n<Float, FloatTraits>(x, buffer, policies...);
auto ptr = to_chars_n<Float, FloatTraits>(x, buffer, fmt, policies...);
*ptr = '\0';
return ptr;
}

View File

@@ -481,7 +481,7 @@ to_chars_result to_chars_hex(char* first, char* last, Real value, int precision)
BOOST_FALLTHROUGH;
case FP_NAN:
// The dragonbox impl will return the correct type of NaN
ptr = boost::charconv::detail::to_chars(value, first);
ptr = boost::charconv::detail::to_chars(value, first, chars_format::general);
return { ptr, 0 };
case FP_ZERO:
if (std::signbit(value))
@@ -692,13 +692,13 @@ to_chars_result to_chars_float_impl(char* first, char* last, Real value, chars_f
}
else
{
auto* ptr = boost::charconv::detail::to_chars(value, first);
auto* ptr = boost::charconv::detail::to_chars(value, first, fmt);
return { ptr, 0 };
}
}
else if (fmt == boost::charconv::chars_format::scientific)
{
auto* ptr = boost::charconv::detail::to_chars(value, first);
auto* ptr = boost::charconv::detail::to_chars(value, first, fmt);
return { ptr, 0 };
}
}

View File

@@ -299,7 +299,7 @@ namespace boost { namespace charconv { namespace detail { namespace to_chars_det
}
template <>
char* to_chars<float, dragonbox_float_traits<float>>(std::uint32_t s32, int exponent, char* buffer) noexcept
char* to_chars<float, dragonbox_float_traits<float>>(std::uint32_t s32, int exponent, char* buffer, chars_format fmt) noexcept
{
// Print significand.
print_9_digits(s32, exponent, buffer);
@@ -311,28 +311,30 @@ namespace boost { namespace charconv { namespace detail { namespace to_chars_det
buffer += 2;
exponent = -exponent;
}
else if (exponent == 0)
{
if (fmt == chars_format::scientific)
{
std::memcpy(buffer, "e+00", 4);
buffer += 4;
}
return buffer;
}
else
{
std::memcpy(buffer, "e+", 2);
buffer += 2;
}
if (exponent >= 10)
{
print_2_digits(std::uint32_t(exponent), buffer);
buffer += 2;
}
else
{
print_1_digit(std::uint32_t(exponent), buffer);
buffer += 1;
}
print_2_digits(std::uint32_t(exponent), buffer);
buffer += 2;
return buffer;
}
template <>
char* to_chars<double, dragonbox_float_traits<double>>(const std::uint64_t significand, int exponent, char* buffer) noexcept {
char* to_chars<double, dragonbox_float_traits<double>>(const std::uint64_t significand, int exponent, char* buffer, chars_format fmt) noexcept {
// Print significand by decomposing it into a 9-digit block and a 8-digit block.
std::uint32_t first_block;
std::uint32_t second_block {};
@@ -522,6 +524,12 @@ namespace boost { namespace charconv { namespace detail { namespace to_chars_det
}
else if (exponent == 0)
{
if (fmt == chars_format::scientific)
{
std::memcpy(buffer, "e+00", 4);
buffer += 4;
}
return buffer;
}
else