【问题标题】:Doubles and Arithmetic双打和算术
【发布时间】:2012-03-10 20:13:27
【问题描述】:

我用 MSVC2008 编译并运行这段代码

long double x = 111111111;
long double y = 222222222;
long double Z = x * y;

cout << z << endl;

当我调试时,z 等于

24691357975308640

数学上z应该是

24691357975308642

发生了什么事?

【问题讨论】:

  • 我用 gcc 得到 24691357975308642。怪你的编译器。
  • @a-z 什么是 long long MAX 值以及 1 long long 需要多少字节?
  • 64位长,signed long long可以存储[-9223372036854775808, 9223372036854775807]

标签: c++ visual-c++ math numbers date-arithmetic


【解决方案1】:

双精度仅精确到 16 digits 附近。如果我数对了,那么你有 17 位数字,并且正确到 16 位。如果你想做这种数学,并且只有整数,那么使用整数。对于这么大的数字,您需要使用uint64_t

【讨论】:

  • @jonas:你总是可以使用长整数,它是 64 位整数。那应该没问题。
  • @Pearsonartphoto:long 不能保证保持 64 位。很长很长。
  • @Alex:这不是真的。 long long 只是保证至少和 long 一样大。
  • @sharth:请(重新)阅读 C 标准,5.2.4.2.1 Sizes of integer types &lt;limits.h&gt; 部分。
  • @Alex:我不知道。谢谢!
【解决方案2】:

什么都没有发生。双精度数的精度是有限的,对于该精度,您获得的值是正确的。不幸的是,您选择打印值的方式的一个缺点是有关精度的信息(即有效数字)丢失了。

例如,对于 1+11+(1)+52 浮点数 (see here),我们有 53 位精度,给我们 53 × log102 个十进制数字的精度,即 15。所以我们只打印 15 位数字:

#include <iomanip>
#include <iostream>

std::cout << std::setfill('0') << std::setprecision(15) << std::scientific
          << Z << std::endl;

结果是:

2.469135797530864e+16

现在我们把精度表现出来了,结果在那个精度上确实是正确的。

如果你不喜欢代码中的魔法15,你应该#include &lt;limits&gt; 并使用:

std::numeric_limits<decltype(Z)>::digits10

【讨论】:

    【解决方案3】:

    浮点运算正在进行。 This 是一本好书。基本上,计算机在存储和处理浮点数时会出现问题,因此会出现这些算术错误。

    【讨论】:

      【解决方案4】:

      一般来说,一个人可以写一本书来回答你的问题。长话短说 - 浮点运算正在进行中。见Floating Point。此外,将双精度值转换为 ASCII(用于显示)也很困难且不精确。您可能还想查看arbitrary precision arithmetics

      【讨论】:

        猜你喜欢
        • 2015-08-23
        • 1970-01-01
        • 1970-01-01
        • 2017-11-12
        • 1970-01-01
        • 2011-04-10
        • 2016-04-25
        • 2016-08-18
        • 2015-09-23
        相关资源
        最近更新 更多