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
36 changes: 22 additions & 14 deletions include/boost/spirit/home/karma/numeric/real_policies.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,20 +257,28 @@ namespace boost { namespace spirit { namespace karma
// generate(sink, right_align(precision, '0')[ulong], n);
// but it's spelled out to avoid inter-modular dependencies.

unsigned int digits=1; //should be number of digits n(truncating any fraction)
if(!boost::spirit::traits::test_zero(n)) {
static constexpr uint64_t limit = UINT64_MAX / 10;
const T num = floor(n);
for (uint64_t x = 10u, i = 1u;; x *= 10, i++) {
if (num < x) {
digits=i;break;
}
if (x > limit) {
digits= i + 1;break;
}
}
}

// should be number of digits n(truncating any fraction)
typename remove_const<T>::type digits = 1;

if (!boost::spirit::traits::test_zero(n)) {
BOOST_CONSTEXPR_OR_CONST uint64_t limit =
std::numeric_limits<uint64_t>::max() / 10;
// Cannot cast T to uint64_t since the former might be a mocked
// type that does not support type casting
const T num = floor(n);

if (num > limit) {
// uint64_t cannot represent the fractional part of an 80
// bit floating point type at full precision. Fallback to
// convential computation.
digits = ceil(log10(n + T(1.)));
} else {
for (uint64_t x = 10; num >= x; x *= 10) {
++digits;
}
}
}

bool r = true;
for (/**/; r && digits < precision_; digits = digits + 1)
r = char_inserter<>::call(sink, '0');
Expand Down
1 change: 1 addition & 0 deletions test/karma/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ run regression_iterator.cpp ;
run regression_optional_double.cpp ;
run regression_real_0.cpp ;
run regression_real_policy_sign.cpp ;
run regression_real_policy_precision.cpp ;
run regression_real_scientific.cpp ;
run regression_semantic_action_attribute.cpp ;
run regression_unicode_char.cpp : : : <pch>off ;
35 changes: 35 additions & 0 deletions test/karma/regression_real_policy_precision.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/spirit/home/karma/numeric/real_policies.hpp>
#include <limits>

#include "real.hpp"

template <class T>
struct max_precision_policy : boost::spirit::karma::real_policies<T> {
static BOOST_CONSTEXPR unsigned precision(T /*unused*/) BOOST_NOEXCEPT {
return std::numeric_limits<T>::max_digits10;
}
};

int main() {
using namespace boost::spirit;

boost::spirit::karma::real_generator<long double,
max_precision_policy<long double>>
real;

BOOST_TEST(test("1.004999999999999999996", real, 1.005l));
BOOST_TEST(test("1.049999999999999999956", real, 1.05l));
BOOST_TEST(test("1.549999999999999999968", real, 1.55l));

// Construct the fractional part as the limit of uint64_t plus one as
// 1844674407370955265 = (2^64-1)/10)+1
// to ensure the formatting does not break above this internal limit.
BOOST_TEST(test("1.001844674407370955251", real, 1.001844674407370955251l));
BOOST_TEST(test("1.01844674407370955262", real, 1.01844674407370955262l));
BOOST_TEST(test("1.184467440737095526528", real, 1.184467440737095526528l));

return boost::report_errors();
}