转换时不同的截断结果

发布于 2024-10-08 16:40:58 字数 391 浏览 8 评论 0原文

我在预测我的 C 代码将如何截断结果时遇到一些困难。参考如下:

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

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

结果ia=144,ib=143。

我可以理解这两个结果的推理,但我不明白为什么这两个计算的处理方式不同。任何人都可以向我介绍此行为的定义或解释其中的差异吗?

编辑:结果是在 Intel core i3-330m 上使用 MS Visual C++ Express 2010 编译的。我在同一台计算机上的 Virtual Box 下的 gcc 版本 4.4.3 (Ubuntu 4.4.3-4ubuntu5) 上得到了相同的结果。

I'm having some some difficulty predicting how my C code will truncate results. 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.

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. I get the same results on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) under Virtual Box on the same machine.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

故人爱我别走 2024-10-15 16:40:58

与分配给 float 变量(例如 fc)时相比,编译器可以对诸如 fa*fb 之类的子表达式使用更高的精度。因此,fc= 部分对结果进行了非常微小的改变(并且恰好在整数截断中产生了差异)。

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. So it's the fc= part which is very slightly changing the result (and happening to then make a difference in the integer truncation).

绅刃 2024-10-15 16:40:58

aschepler 解释了发生的事情的机制,但代码的根本问题是使用一个不存在的值作为代码中的浮点,该值取决于它以不稳定的方式近似。如果您想乘以 0.9(实际数字 0.9=9/10,而不是浮点值 0.90.9f),您应该乘以 9,然后除以 10 ,或者忘记浮点类型并使用十进制算术库。

解决这个问题的一种廉价而肮脏的方法是,当不稳定点被隔离时,就像你在这里的例子一样,就是添加一个值(通常是 0.5),你知道这个值将大于误差,但小于与之前的下一个整数的差值截断。

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. 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.

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.

那一片橙海, 2024-10-15 16:40:58

这是编译器相关的。在我的(gcc 4.4.3)上,它为两个表达式产生相同的结果,即 -144,可能是因为相同的表达式被优化掉了。

其他人很好地解释了发生的事情。换句话说,我想说,差异可能会发生,因为您的编译器在执行乘法之前在内部将浮点数提升为 80 位 fpu 寄存器,然后转换回浮点数或短整型。

如果我的假设成立,如果您编写 ib = (short)(float)(fa * fb); 您应该得到与将 fc 转换为 Short 相同的结果。

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.

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.

If my hypothesis is true if you write ib = (short)(float)(fa * fb); you should get the same result than when casting fc to short.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文