c - 将 float 转换为 int 的区别,32 位 C

标签 c casting 32-bit

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

似乎在 32 位 C 中从 float 到 int 的转换在变量或表达式上完成时表现不同。考虑程序:

#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\n",c1,c2,c1-c2,f10,f1*10.0);
   }
}

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

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 位,问题也不会出现。

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

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

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

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

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

最佳答案

使用 MS Visual C 2008 我能够重现这一点。

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

  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,结果会被转换回 float 并存储,然后再次检索并放置在 FPU 堆栈中(并再次转换为 double)以调用 __ftol2_sse,将 double 转换为 int 的运行时函数。

对于 c2,中间值 与 float 相互转换,并立即传递给 __ftol2_sse 函数。对于此功能,另请参阅 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 

关于c - 将 float 转换为 int 的区别,32 位 C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54881541/

相关文章:

c - 使用 open()、read() 和 write() 系统调用复制文件

c - 为什么输入缓冲区中只有一个(二分之一)空格被视为字符?

c++ - 转换不明确。标准隐式转换无法选择强制转换运算符

android - 32 位 x86 中的 VMALLOC 空间有多大?

mongodb - 在 Windows 7 [32 位] 中启动 MongoDB 时出错

c# - 我如何将此加密从 C# 转换为 C

C pthread : How to wake it up after some time?

c++ - 在 C++ 中从 char 类型转换为 int - 奇怪的值

java - 泛型需要类型转换

64-bit - 获取 64 位平台上非常大的 .gz 文件的文件大小