mirror of
https://github.com/boostorg/spirit.git
synced 2026-01-19 04:42:11 +00:00
Merge pull request #843 from sergiud/long-double-precision-format
Karma: fix broken `real_generator` output for `long double`
This commit is contained in:
@@ -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');
|
||||
|
||||
@@ -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
test/karma/regression_real_policy_precision.cpp
Normal file
35
test/karma/regression_real_policy_precision.cpp
Normal file
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user