Merge pull request #735 from boostorg/issue734

Fixes #734 in docs and code
This commit is contained in:
Christopher Kormanyos
2025-09-06 17:39:43 +02:00
committed by GitHub
6 changed files with 103 additions and 12 deletions

View File

@@ -45,7 +45,7 @@ and `ff` is a variable of type `std::ios_base::fmtflags`.
[[`b = s`][`B&`][Assignment from a string.][Throws a `std::runtime_error` if the string could not be interpreted as a valid number.]]
[[`b.swap(b)`][`void`][Swaps the contents of its arguments.][`noexcept`]]
[[`cb.str(ss, ff)`][`std::string`][Returns the string representation of `b` with `ss` digits and formatted according to the flags set in `ff`.
If `ss` is zero, then returns as many digits as are required to reconstruct the original value.][[space]]]
If `ss` is zero and `std::ios_base::fixed` is not set in `ff`, then returns as many digits as are required to reconstruct the original value.][[space]]]
[[`b.negate()`][`void`][Negates `b`.][[space]]]
[[`cb.compare(cb2)`][`int`][Compares `cb` and `cb2`, returns a value less than zero if `cb < cb2`, a value greater than zero if `cb > cb2` and zero
if `cb == cb2`.][`noexcept`]]

View File

@@ -58,7 +58,7 @@
bool is_zero()const;
int sign()const;
// string conversion:
std::string str()const;
std::string str(std::streamsize digits = 0, std::ios_base::fmtflags f = std::ios_base::fmtflags(0))const;
// Generic conversion mechanism
template <class T>
T convert_to()const;
@@ -416,10 +416,10 @@ Returns `true` is `*this` is zero, otherwise `false`.
Returns a value less than zero if `*this` is negative, a value greater than zero if `*this` is positive, and zero
if `*this` is zero.
std::string str(unsigned precision, bool scientific = true)const;
std::string str(std::streamsize digits = 0, std::ios_base::fmtflags f = std::ios_base::fmtflags(0))const;
Returns the number formatted as a string, with at least /precision/ digits, and in scientific format
if /scientific/ is true.
Returns the number formatted as a string, with at least /precision/ digits, and adhering to the format
flags in /f/ if provided.
template <class T>
T convert_to()const;

View File

@@ -1932,8 +1932,17 @@ std::string cpp_dec_float<Digits10, ExponentType, Allocator>::str(std::intmax_t
}
else if (f & std::ios_base::scientific)
++number_of_digits;
// Determine the number of elements needed to provide the requested digits from cpp_dec_float<Digits10, ExponentType, Allocator>.
const std::size_t number_of_elements = (std::min)(static_cast<std::size_t>(static_cast<std::size_t>(number_of_digits / static_cast<std::intmax_t>(cpp_dec_float_elem_digits10)) + 2u),
// Determine the number of elements needed to provide the requested
// digits from cpp_dec_float<Digits10, ExponentType, Allocator>.
const std::intmax_t
number_of_elements_signed
{
(std::max)(static_cast<std::intmax_t>(number_of_digits / static_cast<std::intmax_t>(cpp_dec_float_elem_digits10) + 2),
std::intmax_t { INT8_C(0) })
};
const std::size_t number_of_elements = (std::min)(static_cast<std::size_t>(number_of_elements_signed),
static_cast<std::size_t>(cpp_dec_float_elem_number));
// Extract the remaining digits from cpp_dec_float<Digits10, ExponentType, Allocator> after the decimal point.

View File

@@ -892,11 +892,6 @@ class cpp_double_fp_backend
auto str(std::streamsize number_of_digits, const std::ios::fmtflags format_flags) const -> std::string
{
if (number_of_digits == 0)
{
number_of_digits = cpp_double_fp_backend::my_digits10;
}
// Use cpp_bin_float when writing to string. This is similar
// to the use of cpp_bin_float when reading from string.

View File

@@ -1276,6 +1276,7 @@ test-suite misc :
[ run git_issue_626.cpp ]
[ run git_issue_636.cpp : : : [ check-target-builds ../config//has_float128 : <source>quadmath : <build>no ] ]
[ run git_issue_652.cpp ]
[ run git_issue_734.cpp ]
[ compile git_issue_98.cpp :
[ check-target-builds ../config//has_float128 : <define>TEST_FLOAT128 <source>quadmath : ]
[ check-target-builds ../config//has_gmp : <define>TEST_GMP <source>gmp : ]

86
test/git_issue_734.cpp Normal file
View File

@@ -0,0 +1,86 @@
// Copyright 2025 Christopher Kormanyos
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/core/lightweight_test.hpp>
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/cpp_double_fp.hpp>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <typeinfo>
namespace local {
template<typename BackendType>
auto my_stringify_via_top_level_number(const std::streamsize strm_size) -> std::string
{
using float_type = boost::multiprecision::number<BackendType, boost::multiprecision::et_off>;
#if defined(BOOST_MSVC)
using streamsize_type = std::streamsize;
#else
using streamsize_type = int;
#endif
float_type x("0.0000000000000000222222222222222");
std::stringstream strm { };
strm << std::setprecision(static_cast<streamsize_type>(strm_size)) << std::fixed;
strm << x;
return strm.str();
}
template<typename BackendType>
auto my_stringify_via_str_and_backend_str(const std::streamsize strm_size) -> std::string
{
using float_type = boost::multiprecision::number<BackendType, boost::multiprecision::et_off>;
#if defined(BOOST_MSVC)
using streamsize_type = std::streamsize;
#else
using streamsize_type = int;
#endif
float_type x("0.0000000000000000222222222222222");
std::stringstream strm { };
strm << std::setprecision(static_cast<streamsize_type>(strm_size)) << std::fixed;
return x.str(strm_size, strm.flags());
}
template<typename BackendType>
auto test() -> void
{
std::cout << "Testing type of test: " << typeid(BackendType).name() << std::endl;
BOOST_TEST(my_stringify_via_top_level_number<BackendType>(std::streamsize { INT8_C(0) }) == "0");
BOOST_TEST(my_stringify_via_top_level_number<BackendType>(std::streamsize { INT8_C(8) }) == "0.00000000");
BOOST_TEST(my_stringify_via_top_level_number<BackendType>(std::streamsize { INT8_C(12) }) == "0.000000000000");
BOOST_TEST(my_stringify_via_top_level_number<BackendType>(std::streamsize { INT8_C(31) }) == "0.0000000000000000222222222222222");
BOOST_TEST(my_stringify_via_str_and_backend_str<BackendType>(std::streamsize { INT8_C(0) }) == "0");
BOOST_TEST(my_stringify_via_str_and_backend_str<BackendType>(std::streamsize { INT8_C(8) }) == "0.00000000");
BOOST_TEST(my_stringify_via_str_and_backend_str<BackendType>(std::streamsize { INT8_C(12) }) == "0.000000000000");
BOOST_TEST(my_stringify_via_str_and_backend_str<BackendType>(std::streamsize { INT8_C(31) }) == "0.0000000000000000222222222222222");
}
} // namespace local
auto main() -> int
{
local::test<boost::multiprecision::cpp_bin_float<32>>();
local::test<boost::multiprecision::cpp_dec_float<32>>();
BOOST_IF_CONSTEXPR(std::numeric_limits<double>::digits >= 53)
{
local::test<boost::multiprecision::cpp_double_fp_backend<double>>();
}
return boost::report_errors();
}