给出以下代码:
istringstream i("2.11099999999999999999");
double d;
if (!(i >> d)) {d = 0;}
cout << d << endl;
输出为2.111
。
我希望能够使用长数,浮点数(包括浮点数),但是当我将istringstream
转换为double时,我得到一个舍入数字。
我该怎样防止这种情况?如何保持给定输入的原样?
此致
答案 0 :(得分:2)
在这种情况下,你无法阻止它。 double
无法精确表示值2.11099999999999999999, 所代表的值均不能将2.11099999999999999999与2.111区分开来。
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html应告诉您需要了解的内容,以及更多内容。
如果您使用其他示例,double
可以表示区分舍入和未舍入值的值,则可以执行以下操作:
#include <iostream>
#include <sstream>
#include <iomanip>
int main() {
std::istringstream iss("2.1109999");
double d;
iss >> d;
std::cout << d << "\n";
std::cout << std::setprecision(10) << d << "\n";
}
输出:
2.111
2.1109999
但是,您应该知道,d
中存储的值并不完全是2.1109999
:
std::cout << std::setprecision(20) << d << "\n";
输出(在我的机器上,你的可能会有所不同,因为某些运行时库根本不打印到20 s.f):
2.1109998999999999292
那是因为double
将值存储在二进制中,而不是十进制。所以它只能代表终止二进制分数。 2.1109999不是终止二进制分数,基本上与三分之一不是终止小数部分的原因相同。
因此,有两种方法可以保持给定输入的原样(即准确地表示该数字):
double
,请将其保留为字符串。double
,而是查找或编写代表小数部分和/或有理数的库。例如,GMP库有mpq_t
或Boost.Rational。答案 1 :(得分:0)
如上所述,你无法达到那种精确度。 您可以随时增加显示的位数,如下所示:Increase precision
答案 2 :(得分:0)
在数学空间中存在无穷多个数,并且double
是有限的,即它适合64位,因此仅精确地表示这些值的子集。实际上2.111也没有完全表示,因为虽然数字是用小数点打印的,但在它们下面它们确实使用二进制,这是一个尾数(52位精度)和一个指数加号位。
尾数约为52位精度,2为52的幂为4,503,599,627,370,496
正如您所看到的,这个数字在初始4之后有15位数,因此您可以获得15位小数精度数字。
对于大多数用途,这种精度足够好。对于那些需要更高精度的场合,或者需要大量数据和小变化的特殊情况,您需要采用专业技术。有一些库可以为您提供。
答案 3 :(得分:0)
您需要将数字存储在double之外的其他内容中,这是二进制表示。
浏览一下将数字存储为十进制表示的库,我知道boost有一个http://svn.boost.org/svn/boost/sandbox/big_number/libs/multiprecision/doc/html/index.html,但还有很多其他的。
如果这似乎是一个重量级的解决方案,请尝试一次读取一个字符串istringstream,如果它是一个数字,将它从char转换为int,然后存储在数组中。
string s = "2.11099999999999999999";
char num[s.size()];
for (int i = 0; i < s.size(); ++i) {
if (isdigit(s[i])
num[i] = s[i] - '0';
else
num[i] = s[i];
}
答案 4 :(得分:0)
此处有两个单独的转换:从文本到双倍(iss >> d
)的转换,并且将该双重转换为文本(std::cout << d
)。第一个将输入文本的最佳近似值存储到double
变量中。第二个使用默认精度;它舍入值以适应该精度,并抑制尾随零。这就是你看2.111
的原因。如果要查看更多数字,请使用setprecision
增加输出中的位数。正如其他人所说,任何超过15位数(输入或输出)的东西都是无稽之谈。