将 float 转换为 int 的差异,32 位 C [英] Difference in casting float to int, 32-bit C

查看:35
本文介绍了将 float 转换为 int 的差异,32 位 C的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用需要运行 32 位系统的旧代码.在这项工作中,我偶然发现了一个问题(出于学术兴趣)我想了解其原因.

I currently working with an old code that needs to run a 32-bit system. During this work I stumbled across an issue that (out of academic interest) I would like to understand the cause of.

如果转换是在变量或表达式上完成的,那么在 32 位 C 中从 float 转换为 int 的行为似乎有所不同.考虑程序:

It seems that casting from float to int in 32-bit C behaves differently if the cast is done on a variable or on an expression. Consider the program:

#include <stdio.h>
int main() {
   int i,c1,c2;
   float f1,f10;
   for (i=0; i< 21; i++)  {
      f1 = 3+i*0.1;
      f10 = f1*10.0;
      c1 = (int)f10;
      c2 = (int)(f1*10.0);
      printf("%d, %d, %d, %11.9f, %11.9f
",c1,c2,c1-c2,f10,f1*10.0);
   }
}

直接在 32 位系统或 64 位系统上使用 -m32 修饰符编译(使用 gcc),程序的输出是:

Compiled (using gcc) either directly on a 32-bit system or on a 64-bit system using the -m32 modifier the output of the program is:

30, 30, 0, 30.000000000 30.000000000
31, 30, 1, 31.000000000 30.999999046
32, 32, 0, 32.000000000 32.000000477
33, 32, 1, 33.000000000 32.999999523
34, 34, 0, 34.000000000 34.000000954
35, 35, 0, 35.000000000 35.000000000
36, 35, 1, 36.000000000 35.999999046
37, 37, 0, 37.000000000 37.000000477
38, 37, 1, 38.000000000 37.999999523
39, 39, 0, 39.000000000 39.000000954
40, 40, 0, 40.000000000 40.000000000
41, 40, 1, 41.000000000 40.999999046
42, 41, 1, 42.000000000 41.999998093
43, 43, 0, 43.000000000 43.000001907
44, 44, 0, 44.000000000 44.000000954
45, 45, 0, 45.000000000 45.000000000
46, 45, 1, 46.000000000 45.999999046
47, 46, 1, 47.000000000 46.999998093
48, 48, 0, 48.000000000 48.000001907
49, 49, 0, 49.000000000 49.000000954
50, 50, 0, 50.000000000 50.000000000 

因此,很明显,转换变量和表达式之间存在差异.请注意,如果 float 更改为 double 和/或 int 更改为 shortlong,如果程序编译为 64 位也不会出现这个问题.

Hence, it is clear that a difference exists between casting a variable and an expression. Note, that the issue exists also if float is changed to double and/or int is changed to short or long, also the issue do not manifest if program is compiled as 64-bit.

澄清一下,我在这里试图理解的问题不是浮点算术/舍入,而是 32 位内存处理的差异.

To clarify, the issue that I'm trying to understand here is not about floating-point arithmetic/rounding, but rather differences in memory handling in 32-bit.

该问题在以下方面进行了测试:

The issue were tested on:

  • Linux version 4.15.0-45-generic (buildd@lgw01-amd64-031) (gcc version 7.3.0 (Ubuntu 7.3.0-16ubuntu3)),程序编译使用:gcc -m32 Cast32int.c

  • Linux version 4.15.0-45-generic (buildd@lgw01-amd64-031) (gcc version 7.3.0 (Ubuntu 7.3.0-16ubuntu3)), program compiled using: gcc -m32 Cast32int.c

Linux version 2.4.20-8 (bhcompile@porky.devel.redhat.com) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)),程序编译使用:gcc Cast32int.

Linux version 2.4.20-8 (bhcompile@porky.devel.redhat.com) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)), program compiled using: gcc Cast32int.c

感谢任何帮助我理解这里发生的事情的指针.

Any pointers to help me understand what is going on here are appreciated.

推荐答案

使用 MS Visual C 2008 我能够重现这个.

With MS Visual C 2008 I was able to reproduce this.

检查汇编器,两者之间的区别是中间存储和中间转换结果的获取:

Inspecting the assembler, the difference between the two is an intermediate store and fetch of a result with intermediate conversions:

  f10 = f1*10.0;          // double result f10 converted to float and stored
  c1 = (int)f10;          // float result f10 fetched and converted to double
  c2 = (int)(f1*10.0);    // no store/fetch/convert

汇编器生成的值压入 FPU 堆栈,这些值被转换为 64 位,然后相乘.对于 c1,结果将被转换回浮点数并存储,然后再次检索并放置在 FPU 堆栈上(并再次转换为双精度)以调用 __ftol2_sse,将 double 转换为 int 的运行时函数.

The assembler generated pushes values onto the FPU stack that get converted to 64 bits and then are multiplied. For c1 the result is then converted back to float and stored and is then retrieved again and placed on the FPU stack (and converted to double again) for a call to __ftol2_sse, a run-time function to convert a double to int.

对于c2,中间值转换为浮点数,并立即传递给__ftol2_sse函数.对于此函数,另请参见 Convert double to int? 中的答案.

For c2 the intermediate value is not converted to and from float and passed immediately to the __ftol2_sse function. For this function see also the answer at Convert double to int?.

汇编程序:

      f10 = f1*10;
fld         dword ptr [f1] 
fmul        qword ptr [__real@4024000000000000 (496190h)] 
fstp        dword ptr [f10] 

      c2 = (int)(f1*10);
fld         dword ptr [f1] 
fmul        qword ptr [__real@4024000000000000 (496190h)] 
call        __ftol2_sse
mov         dword ptr [c2],eax 

      c1 = (int)f10;
fld         dword ptr [f10] 
call        __ftol2_sse
mov         dword ptr [c1],eax 

这篇关于将 float 转换为 int 的差异,32 位 C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆