我使用cpp_dec_float
来获得任意精确度,这很棒,但我无法弄清楚如何打印所有有效数字。
例如,使用此代码进行设置
using boost::multiprecision::cpp_dec_float;
typedef boost::multiprecision::number<cpp_dec_float<100>> mp_type;
mp_type test_num("7.0710678118654752440084436210484903928483593768847403658833986900e-01");
如果我只是用
打印std::cout << std::scientific << test_num << std::endl;
结果为7.071068e-01
,因此即可结束。
如果我打破了
std::cout << std::setprecision(std::numeric_limits<mp_type>::digits) << std::scientific << test_num << std::endl;
我得到7.0710678118654752440084436210484903928483593768847403658833986900000000000000000000000000000000000000e-01
。我很高兴不会失去精确度,但它不太保守。
有没有办法删除尾随零而不会丢失现有工具的任何精度?如果不是,如何从结果字符串中删除尾随零?
如果可以使用现有工具来满足我的意图,那么如何以科学记数法输出cpp_dec_float
而不会丢失精度并将尾随零删除到字符串中?我只能找到stream examples。
更紧密
感谢模拟接口,我离得更近了。
我已将代码更改为:
using boost::multiprecision::cpp_dec_float;
typedef boost::multiprecision::number<cpp_dec_float<0>> mp_type;
mp_type test_num("7.0710678118654752440084436210484903928483593768847403658833986900e-01");
std::cout << test_num.str(0, std::ios_base::scientific) << std::endl;
具有潜在无限长度;但是,打印出来了:
7.0710678118654752440084436210484903928480e-01
哪个很接近但似乎很奇怪。在如此慷慨地向我指出的source模拟接口中,我发现了这些行
if(number_of_digits == 0)
number_of_digits = cpp_dec_float_total_digits10;
这告诉我它应该考虑所有有效数字,基本上输出因为无限长度而输入的内容。
我检查了cpp_dec_float_total_digits10
private:
static const boost::int32_t cpp_dec_float_elem_digits10 = 8L;
static const boost::int32_t cpp_dec_float_elem_mask = 100000000L;
BOOST_STATIC_ASSERT(0 == cpp_dec_float_max_exp10 % cpp_dec_float_elem_digits10);
// There are three guard limbs.
// 1) The first limb has 'play' from 1...8 decimal digits.
// 2) The last limb also has 'play' from 1...8 decimal digits.
// 3) One limb can get lost when justifying after multiply,
// as only half of the triangle is multiplied and a carry
// from below is missing.
static const boost::int32_t cpp_dec_float_elem_number_request = static_cast<boost::int32_t>((cpp_dec_float_digits10 / cpp_dec_float_elem_digits10) + (((cpp_dec_float_digits10 % cpp_dec_float_elem_digits10) != 0) ? 1 : 0));
// The number of elements needed (with a minimum of two) plus three added guard limbs.
static const boost::int32_t cpp_dec_float_elem_number = static_cast<boost::int32_t>(((cpp_dec_float_elem_number_request < 2L) ? 2L : cpp_dec_float_elem_number_request) + 3L);
public:
static const boost::int32_t cpp_dec_float_total_digits10 = static_cast<boost::int32_t>(cpp_dec_float_elem_number * cpp_dec_float_elem_digits10);
,我无法准确确定它是什么;虽然,我确实找到了似乎定义它的代码部分。
boost::multiprecision::cpp_dec_float::str()
是否可以确定有效位数并将其用作{{1}}的第一个参数?
答案 0 :(得分:2)
这结果很艰难。
短篇小说是:cpp_dec_float中没有这样的功能。更糟糕的是,cpp_dec_float没有跟踪已设置的有效数字的数量,因此没有“便宜”的方法来查找打印分数所需的长度。
思路:
对于某些边界情况(例如123.000000000000001),可以取整数部分的小数部分+ log10的倒数的log10。这完全不适用于一般情况。
如果您想使用实现细节,您可能会在后端数组中找到“last inhabited”元素,并进行数学运算。但是,这非常复杂(需要修改cpp_dec_float.hpp
和大量测试)。
最后,我发现.str()
的当前实施明显使零努力变得高效。完全没有。
总而言之,我有以下建议。任
切换到gmp
后端(如果你负担得起的话)。注意
gmp_float
确实具有任意精度,和 str()
实现确实考虑了尾数中零的重要性#include <boost/multiprecision/number.hpp>
#include <boost/multiprecision/gmp.hpp>
#include <iostream>
namespace mp = boost::multiprecision;
int main()
{
typedef mp::number<mp::gmp_float<100>> mp_type;
mp_type test_num("7.071067811865475244008443621048490392848359376884740365883398690000000000000000000e-01");
std::cout << test_num.str(0, std::ios_base::scientific) << '\n';
}
在不需要进一步操作的情况下打印7.071067811865475244008443621048490392848359376884740365883398690e-01
。
如果那不是一个选项,我只是对输出进行后处理,删除尾随的零:
template <typename T>
std::string to_pretty_string(T const& v)
{
std::string s = v.str(0, std::ios_base::scientific);
assert(s.length()>3); // min: 0.e
switch (s[0])
{ // normalized scientific always has #.####### form of mantissa
case '-':
case '+': assert(s[2] == '.'); break;
default: assert(s[1] == '.'); break;
}
auto exp = s.find('e');
if (std::string::npos != exp && exp > 0)
{
for(size_t pos = exp-1; pos; --pos)
{
if (s[pos] != '0')
{
// remove run of 0s if applicable
s.erase(pos+1, exp-pos-1);
break;
}
}
}
return std::move(s);
}
再次查看 Live On Coliru
答案 1 :(得分:1)
您可以使用cpp_dec_float::str()
方法明确说明需要输出的位数:
std::cout << std::scientific << test_num.str(75) << std::endl;
// output: 0.707106781186547524400844362104849039284835937688474036588339869