简体   繁体   English

铸造时不同的截断结果

[英]Different Truncation Results When Casting

I'm having some some difficulty predicting how my C code will truncate results. 我在预测我的C代码将如何截断结果时遇到一些困难。 Refer to the following: 请参阅以下内容:

float fa,fb,fc;
short ia,ib;

fa=160
fb=0.9;
fc=fa*fb;
ia=(short)fc;
ib=(short)(fa*fb);

The results are ia=144, ib=143. 结果是ia = 144,ib = 143。

I can understand the reasoning for either result, but I don't understand why the two calculations are treated differently. 我可以理解这两种结果的推理,但我不明白为什么这两种计算的处理方式不同。 Can anyone refer me to where this behaviour is defined or explain the difference? 任何人都可以推荐我这个行为的定义或解释差异?

Edit: the results are compiled with MS Visual C++ Express 2010 on Intel core i3-330m. 编辑:结果使用英特尔酷睿i3-330m上的MS Visual C ++ Express 2010进行编译。 I get the same results on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) under Virtual Box on the same machine. 我在同一台机器上的Virtual Box下的gcc版本4.4.3(Ubuntu 4.4.3-4ubuntu5)上得到了相同的结果。

The compiler is allowed to use more precision for a subexpression like fa*fb than it uses when assigning to a float variable like fc . 允许编译器对fa*fb这样的子表达使用比分配给像fc这样的float变量时使用的精度更高的精度。 So it's the fc= part which is very slightly changing the result (and happening to then make a difference in the integer truncation). 所以它是fc= part,它会稍微改变结果(然后发生在整数截断中产生差异)。

aschepler explained the mechanics of what's going on well, but the fundamental problem with your code is using a value which does not exist as a float in code that depends upon the value of its approximation in an unstable way. aschepler解释了正在发生的事情的机制,但是你的代码的基本问题是使用一个值,该值在代码中不作为float 存在 ,它以不稳定的方式依赖于其近似值。 If you want to multiply by 0.9 (the actual number 0.9=9/10, not the floating point value 0.9 or 0.9f ) you should multiply by 9 then divide by 10, or forget about floating point types and use a decimal arithmetic library. 如果你想乘以0.9(实际数字0.9 = 0.9f ,而不是浮点值0.90.9f ),你应该乘以9然后除以10,或者忘记浮点类型并使用十进制算术库。

A cheap and dirty way around the problem, when the unstable points are isolated as in your example here, is to just add a value (typically 0.5) which you know will be larger than the error but smaller than the difference from the next integer before truncating. 解决问题的一种廉价而肮脏的方法,就像你的例子中的不稳定点被隔离一样,只是添加一个值(通常为0.5),你知道它将大于错误但小于之前的下一个整数的差值截断。

This is compiler dependent. 这取决于编译器。 On mine (gcc 4.4.3) it produces the same result for both expressions, namely -144, probably because the identical expression is optimized away. 在我的(gcc 4.4.3)中,它为两个表达式产生相同的结果,即-144,可能是因为相同的表达式被优化掉了。

Others explained well what happened. 其他人解释了发生的事情。 In other words I would say that the differences probably happens because your compiler internally promotes floats to 80 bits fpu registers before performing the multiplication, then convert back either to float or to short. 换句话说,我会说差异可能是因为你的编译器在执行乘法之前在内部将浮点数提升到80位fpu寄存器,然后转换回float或short。

If my hypothesis is true if you write ib = (short)(float)(fa * fb); 如果你写ib = (short)(float)(fa * fb);我的假设是真的ib = (short)(float)(fa * fb); you should get the same result than when casting fc to short. 你应该得到与将fc转换为short时相同的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM