在科学记数法打印cpp_dec_float没有尾随零 [英] Print cpp_dec_float in scientific notation without trailing zeros
问题描述
我用<一个href=\"http://www.boost.org/doc/libs/1_55_0/libs/multi$p$pcision/doc/html/boost_multi$p$pcision/tut/floats/cpp_dec_float.html\"相对=nofollow> cpp_dec_float
任意precision,它的伟大,但我有麻烦找出如何打印所有显著数字。
I'm using cpp_dec_float
for arbitrary precision, and it's great, but I'm having trouble figuring out how to print all significant digits.
例如,有了这个code设置
For example, with this code to setup
using boost::multiprecision::cpp_dec_float;
typedef boost::multiprecision::number<cpp_dec_float<100>> mp_type;
mp_type test_num("7.0710678118654752440084436210484903928483593768847403658833986900e-01");
如果我简单地打印
and if I simply print with
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;
我得到<$c$c>7.0710678118654752440084436210484903928483593768847403658833986900000000000000000000000000000000000000e-01$c$c>.我很高兴没有失去precision,但它不是很保守的空间。
I get 7.0710678118654752440084436210484903928483593768847403658833986900000000000000000000000000000000000000e-01
. I'm happy not to lose the precision, but it's not very space conservative.
有没有办法去除尾随零,而不会丢失任何precision与现有的工具?如果没有,怎么能尾随零将从结果字符串中删除?
Is there a way to remove the trailing zeros without losing any precision with existing tools? If not, how can the trailing zeros be removed from the resultant string?
如果现有的工具可以用来满足我的意图,又怎能 cpp_dec_float
在不失去precision并移至一个字符串尾随零科学记数法输出?我只能找到流范例。
If existing tools can be used to satisfy my intent, how can cpp_dec_float
be output in scientific notation without lost precision and trailing zeros removed to a string? I can only find the stream examples.
更紧密
由于mockinterface,我非常接近。
Thanks to mockinterface, I'm much closer.
我已经改变了code这样:
I've changed the code to this:
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;
要具有潜在的无限长度;然而,这被打印
To have potentially unlimited length; however, this is printed:
7.0710678118654752440084436210484903928480e-01
这是接近,但似乎很奇怪。在源 mockinterface如此慷慨地向我指出,我发现这些行
Which is close but seems strange. In the source mockinterface so graciously pointed out to me, I found these lines
if(number_of_digits == 0)
number_of_digits = cpp_dec_float_total_digits10;
这表明,我认为它应该考虑到所有显著的数字,基本上什么输出是因为长度不受限制。
which suggests to me that it should take into account all significant digits, basically outputting what was input because of the unlimited length.
我查了<一个href=\"http://$c$c.woboq.org/boost/boost/boost/multi$p$pcision/cpp_dec_float.hpp.html#_ZN5boost14multi$p$pcision8backends13cpp_dec_float28cpp_dec_float_total_digits10E\"相对=nofollow>为 cpp_dec_float_total_digits10
>,我无法确定究竟是什么;虽然,我没有找到这个code节,似乎定义它。
I checked the source for cpp_dec_float_total_digits10
, and I am unable to determine exactly what it is; although, I did find this code section that seems to define it.
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 ::多precision :: cpp_dec_float :: STR()
?
推荐答案
这竟然是一个艰难的一个。
This turned out to be a tough one.
简短的故事是:没有在cpp_dec_float没有这样的功能。更糟的是,cpp_dec_float不跟踪的已设置显著的位数,所以没有廉价的方式找到打印的分数所需要的长度。
The short story is: there is no such functionality in cpp_dec_float. What's worse, cpp_dec_float doesn't track the number of significant digits that have been set, so there's no "cheap" way to find the length needed to print the fraction.
思路:
-
有关一些边境情况下(例如123.000000000000001)人们可以采取的小数部分的整数部分+ LOG10的倒数的LOG10。这完全不能是一般适用的。
For some border cases (e.g. 123.000000000000001) one could take the log10 of the reciprocal of the the fractional part + log10 of the integer part. This completely fails to be generically applicable.
如果你想使用实现细节你可能会发现后端阵列中的'最后一个有人居住的'元素,并做数学。然而,这是涉及到pretty(需要修改 cpp_dec_float.hpp
和大量的测试)。
If you want to use implementation details you might find the 'last inhabited' element in the backend array, and do the maths. However, this is pretty involved (requires modifying cpp_dec_float.hpp
and a lot of testing).
最后,我观察到,当前实施名为.str()
显然会让零的努力是有效的。在所有。
Finally, I observed that the current implementation for .str()
clearly makes zero effort to be efficient. At all.
所以,所有的一切我有以下几点建议。无论
So all in all I have the following suggestions. Either
-
切换到
GMP
后端(如果你能负担得起)。注意
switch to the
gmp
backend (if you can afford it). Note
- 这不是一个十进制浮点重新presentation AFAICT
- 这需要附加库(libgmp)被链接
-
gmp_float
的确实的具有任意precision不过,和 - 是
STR()
实施的确实的考虑尾数零的意义
- this is not a decimal float representation AFAICT
- this requires an additional library (libgmp) to be linked
gmp_float
does have arbitrary precision though, and- it's
str()
implementation does take into account the significance of zeroes in the mantissa
看它的 住在Coliru
See it Live On Coliru
#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
而无需进一步的行动。
如果这不是一种选择,我只是后期处理的输出,去除尾随零:
If that's not an option, I'd just post-process the output, removing the trailing zeroes:
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);
}
看它的 住在Coliru 再次
See it Live On Coliru again
这篇关于在科学记数法打印cpp_dec_float没有尾随零的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!