给定以下代码:
istringstream i("2.11099999999999999999");
double d;
if (!(i >> d)) {d = 0;}
cout << d << endl;
输出是2.111
。
我希望能够处理长数字、浮点数(包括浮点数),但是当我将 my 转换istringstream
为 double 时,我得到一个四舍五入的数字。
我怎样才能防止这种情况?如何保持给定的输入原样?
问候
给定以下代码:
istringstream i("2.11099999999999999999");
double d;
if (!(i >> d)) {d = 0;}
cout << d << endl;
输出是2.111
。
我希望能够处理长数字、浮点数(包括浮点数),但是当我将 my 转换istringstream
为 double 时,我得到一个四舍五入的数字。
我怎样才能防止这种情况?如何保持给定的输入原样?
问候
在这种情况下,您无法阻止它。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 sf):
2.1109998999999999292
那是因为以二进制而不是十进制double
存储值。所以它只能表示终止二进制分数。2.1109999 不是终止二进制分数,原因与三分之一不是终止十进制分数的原因基本相同。
因此,有两种方法可以使给定的输入保持原样(即精确地表示该数字):
double
,将其保留为字符串。double
,而是查找或编写一个表示小数和/或有理数的库。例如,GMP 库有mpq_t
或有Boost.Rational。正如所说,你不能有那种精确度。您可以随时增加显示的位数,如下所述:增加精度
在数学空间中有无限个数,adouble
是有限的,即它适合 64 位,因此只有这些值的一个子集被精确表示。实际上 2.111 也没有精确表示,因为虽然数字是用小数点打印的,但在下面它们确实使用二进制,即尾数(52 位精度)和指数加符号位。
由于尾数的精度约为 52 位,因此 2 的 52 次方为 4,503,599,627,370,496
正如你所看到的,这个数字在最初的 4 之后有 15 位,因此你得到了 15 位小数精度。
对于大多数用途,这种精度已经足够了。对于那些需要更高精确度的场合,或者需要大数量和小改动的特殊情况,您需要采用专业技术。有一些图书馆可以为您提供。
您需要将数字存储在双精度以外的其他东西中,这是一种二进制表示。
看看一个将数字存储为十进制表示的库,我知道 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];
}
这里有两个单独的转换:从 text 到 double ( iss >> d
) 的转换,以及从 double 到 text ( std::cout << d
) 的转换。第一个将输入文本的最佳近似值存储到您的double
变量中。第二个使用默认精度;它将值四舍五入以适应该精度,并抑制尾随零。这就是你看到的原因2.111
。如果您想查看更多位数,请使用setprecision
增加输出中的位数。正如其他人所说,超过 15 位数(输入或输出)的任何内容都是无稽之谈。