2017-04-02 45 views
0

我有以下的情况,让我27,而不是28:转换双为int误差(1个关)

double d = 0.35; 
int i = 80; 

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

printf("%d", ans); 

但我得到正确的答案,如果我用这个:

int ans = (int)(0.35 * 80); 
printf("%d", ans); 

或:

double ans = d * i; 
printf("%d", (int) ans); 

有人可以解释为什么第一种情况是1个关和其他人的工作?

我做了一些研究和人说双存储数字,如28 27.999 ...,但我很困惑,在什么情况下,这会发生。Britain

谢谢!

+0

你的问题是关于C,而不是C++。至于问题本身,我无法重现你的问题。在gcc(Ubuntu 4.8.1-2ubuntu1〜12.04)上的所有三种情况下,我得到了28分。 – DyZ

+2

[我尝试在ideone中,它返回28](https://ideone.com/6J4yMm)。你使用的是什么编译器和平台? – AntonH

+3

有帮助的阅读:[每个计算机科学家应该知道的关于浮点运算的内容](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – user4581301

回答

3

0.35的值没有精确的二进制浮点表示。因此,在使用基于IEEE 754的浮点支持的典型平台上,您的double d = 0.35;根本不是0.35,而是诸如0.34999999999999998之类的值 - 在此情况下的值恰好是,比原始的小。其余的如下:乘法产生小于28,它会被(int)截断为27。故事结局。

如果有人从这个例子中得到28这可能意味着他们的编译器使用不同的浮点评价模型,其中原始0.35可能代表两种正是或某个值略微更大0.35(说,0.35000000000012或类似的东西)。优化计算并在编译时执行它们的编译器也属于该类别。

的差异

之间

int ans = (int)(d * i); 
printf("%d", ans); 
double ans = d * i; 
printf("%d", (int) ans); 
可能很容易由编译器字面上存储在第二情况下的 double可变 ans中间结果而引起的。

实际乘法可能在CPU的高精度浮点寄存器中执行(其精度高于double)。在第一种情况下,结果直接存储到int中。在第二种情况下,它首先转换为较低精度的double,然后double转换为int。这种额外的中间转换为double可以轻松改变结果。

+0

你的回答并不能解释为什么'int ans =(int)(d * i)'与'double ans = d * i不同; INT(ANS)'。在后一种情况下,“d”不是被隐含地提升为“双”吗? – DyZ

+0

因此,如果ans = 0.35 * 80,则28.000将被存储到ans而不是27.999 ...对吗? – Rig

+0

@Rig:没有人知道将存储什么。这取决于您的编译器在计算此表达式时需要采取什么方法。编译它并查看机器代码,看看你的编译器决定做什么 - 这是知道的唯一方法。但不要把它当作绝对的事实,因为明天你的编译器可能会开始有不同的表现。 – AnT