【问题标题】:strange double to int conversion behavior in c++c++ 中奇怪的 double 到 int 的转换行为
【发布时间】:2009-12-07 15:41:54
【问题描述】:

以下程序显示了我在 c++ 中看到的奇怪的 double 到 int 转换行为:

#include <stdlib.h>
#include <stdio.h>

int main() {
  double d = 33222.221;
  printf("d = %9.9g\n",d);

  d *= 1000;
  int i = (int)d;

  printf("d = %9.9g | i = %d\n",d,i);

  return 0;
}

当我编译并运行程序时,我看到:

g++ test.cpp
./a.out
d = 33222.221
d =  33222221 | i = 33222220

为什么 i 不等于 33222221? 编译器版本为 GCC 4.3.0

【问题讨论】:

    标签: c++ type-conversion


    【解决方案1】:

    浮点表示几乎从不精确(仅在特殊情况下)。每个程序员都应该阅读:What Every Computer Scientist Should Know About Floating-Point Arithmetic

    简而言之 - 您的号码可能是 33222220.999999999999999999999999999999999999999999999999999998(或类似的东西),截断后变为 33222220。

    【讨论】:

    • 好的,谢谢,有道理。那么在不必担心这一点的情况下,转换为 int 的首选方法是什么?圆函数? (但这仍然涉及 double->int 转换..)
    • user924: int i = (int)(d>=0?d+0.5:d-0.5);解决您的问题
    • 添加 0.5 以“四舍五入”结束。如果您有点想要“向下取整”,但有一点空间来纠正这种不精确,那么您可以添加一个较小的值。例如(d+0.001)(d + d*DBL_EPSILON)。如果您要将数字乘以 1000 并希望得到正确的结果,那么最好获取一个用于十进制算术的库。
    • 或者只使用 C99 数学库中的 i = (int)nearbyint(d)
    • 当然,如果舍入模式与您想要的舍入方式匹配。
    【解决方案2】:

    当您附加调试器并检查值时,您会看到d 的值实际上是33222220.999999996,当转换为整数时,它被正确截断为 33222220。

    双变量中可以存储的数字是有限的,33222221 不是其中之一。

    【讨论】:

    • 其实33222221就是其中之一。这里的问题是 33222.221 不是。
    【解决方案3】:

    由于浮点近似,33222.221 实际上可能是 33222.220999999999999。乘以 1000 得到 33222220.999999999999。转换为整数会忽略所有小数(向下舍入),最终结果为 33222220。

    【讨论】:

      【解决方案4】:

      如果您将 printf() 调用中的“9.9g”更改为 17.17 以使用 64 位 IEEE 754 FP 编号恢复所有可能的精度数字,则双精度值将得到 33222220.999999996。然后 int 转换就有意义了。

      【讨论】:

        【解决方案5】:

        我不想重复其他cmets的解释。

        所以,这里只是一个避免上述问题的建议:

        1. 尽可能避免浮点运算(尤其是在涉及计算时)。

        2. 如果确实需要浮点运算,则绝对不能通过 operator== 来比较数字!改用您自己的比较函数(或使用某个库提供的比较函数),它使用某种 epsilon 比较(绝对或相对于数字的大小)进行类似“几乎相等”的比较。

          李>

        例如看优秀的文章

        http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
        

        由布鲁斯·道森代替!

        斯蒂芬

        【讨论】:

          猜你喜欢
          • 2015-11-19
          • 2021-05-03
          • 2012-09-03
          • 2015-10-07
          • 1970-01-01
          • 2017-07-10
          • 1970-01-01
          • 1970-01-01
          • 2017-03-16
          相关资源
          最近更新 更多