0

给定以下代码:

istringstream i("2.11099999999999999999");

double d;
if (!(i >> d)) {d = 0;}

cout << d << endl;

输出是2.111

我希望能够处理长数字、浮点数(包括浮点数),但是当我将 my 转换istringstream为 double 时,我得到一个四舍五入的数字。

我怎样才能防止这种情况?如何保持给定的输入原样?

问候

4

5 回答 5

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 sf):

2.1109998999999999292

那是因为以二进制而不是十进制double存储值。所以它只能表示终止二进制分数。2.1109999 不是终止二进制分数,原因与三分之一不是终止十进制分数的原因基本相同。

因此,有两种方法可以使给定的输入保持原样(即精确地表示该数字):

  1. 不要转换为double,将其保留为字符串。
  2. 不要转换为double,而是查找或编写一个表示小数和/或有理数的库。例如,GMP 库有mpq_t或有Boost.Rational
于 2012-12-04T09:35:25.467 回答
0

正如所说,你不能有那种精确度。您可以随时增加显示的位数,如下所述:增加精度

于 2012-12-04T09:38:00.243 回答
0

在数学空间中有无限个数,adouble是有限的,即它适合 64 位,因此只有这些值的一个子集被精确表示。实际上 2.111 也没有精确表示,因为虽然数字是用小数点打印的,但在下面它们确实使用二进制,即尾数(52 位精度)和指数加符号位。

由于尾数的精度约为 52 位,因此 2 的 52 次方为 4,503,599,627,370,496

正如你所看到的,这个数字在最初的 4 之后有 15 位,因此你得到了 15 位小数精度。

对于大多数用途,这种精度已经足够了。对于那些需要更高精确度的场合,或者需要大数量和小改动的特殊情况,您需要采用专业技术。有一些图书馆可以为您提供。

于 2012-12-04T09:46:40.190 回答
0

您需要将数字存储在双精度以外的其他东西中,这是一种二进制表示。

看看一个将数字存储为十进制表示的库,我知道 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];
}
于 2012-12-04T11:00:50.580 回答
0

这里有两个单独的转换:从 text 到 double ( iss >> d) 的转换,以及从 double 到 text ( std::cout << d) 的转换。第一个将输入文本的最佳近似值存储到您的double变量中。第二个使用默认精度;它将值四舍五入以适应该精度,并抑制尾随零。这就是你看到的原因2.111。如果您想查看更多位数,请使用setprecision增加输出中的位数。正如其他人所说,超过 15 位数(输入或输出)的任何内容都是无稽之谈。

于 2012-12-04T14:46:54.733 回答