2
0
mirror of https://github.com/boostorg/spirit.git synced 2026-01-19 04:42:11 +00:00

Karma: fix broken real_generator output for long double

Eliminate Boost 1.90.0 regression introduced in e6fbdf615b.
This commit is contained in:
Sergiu Deitsch
2025-12-20 00:37:29 +01:00
parent 9bcd344fc1
commit b80d6489c5
3 changed files with 58 additions and 14 deletions

View File

@@ -257,20 +257,28 @@ namespace boost { namespace spirit { namespace karma
// generate(sink, right_align(precision, '0')[ulong], n); // generate(sink, right_align(precision, '0')[ulong], n);
// but it's spelled out to avoid inter-modular dependencies. // but it's spelled out to avoid inter-modular dependencies.
unsigned int digits=1; //should be number of digits n(truncating any fraction) // should be number of digits n(truncating any fraction)
if(!boost::spirit::traits::test_zero(n)) { typename remove_const<T>::type digits = 1;
static constexpr uint64_t limit = UINT64_MAX / 10;
const T num = floor(n); if (!boost::spirit::traits::test_zero(n)) {
for (uint64_t x = 10u, i = 1u;; x *= 10, i++) { BOOST_CONSTEXPR_OR_CONST uint64_t limit =
if (num < x) { std::numeric_limits<uint64_t>::max() / 10;
digits=i;break; // Cannot cast T to uint64_t since the former might be a mocked
} // type that does not support type casting
if (x > limit) { const T num = floor(n);
digits= i + 1;break;
} 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; bool r = true;
for (/**/; r && digits < precision_; digits = digits + 1) for (/**/; r && digits < precision_; digits = digits + 1)
r = char_inserter<>::call(sink, '0'); r = char_inserter<>::call(sink, '0');

View File

@@ -145,6 +145,7 @@ run regression_iterator.cpp ;
run regression_optional_double.cpp ; run regression_optional_double.cpp ;
run regression_real_0.cpp ; run regression_real_0.cpp ;
run regression_real_policy_sign.cpp ; run regression_real_policy_sign.cpp ;
run regression_real_policy_precision.cpp ;
run regression_real_scientific.cpp ; run regression_real_scientific.cpp ;
run regression_semantic_action_attribute.cpp ; run regression_semantic_action_attribute.cpp ;
run regression_unicode_char.cpp : : : <pch>off ; run regression_unicode_char.cpp : : : <pch>off ;

View 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();
}