c - 将 float 转换为 int、32 位 C 的区别
问题描述
我目前正在使用需要运行 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 位系统上编译(使用 gcc)-m32
,程序的输出为:
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
更改为short
or long
,问题也存在,如果程序编译为 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.c
任何帮助我理解这里发生的事情的指针都值得赞赏。
解决方案
使用 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
然后将结果转换回浮点数并存储,然后再次检索并放置在 FPU 堆栈上(并再次转换为双精度数)以调用,这是一个将双精度__ftol2_sse
数转换为 int 的运行时函数。
因为c2
中间值不会与浮点数相互转换并立即传递给__ftol2_sse
函数。对于此函数,另请参阅将 double 转换为 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
推荐阅读
- javascript - 如何将 Chromium 中地址栏和选项卡的外观更改为与所附图像相似
- python - 带有三元运算符的海象运算符的正确语法是什么?
- python-3.x - 如何在一个“尝试”块中引发同一错误的多个异常
- powershell - 通过 power shell 脚本从 Outlook 中删除基于主题的邮件
- javascript - React 本机状态未使用 animated.start() 中的钩子更新
- hyperledger-fabric - 在超级账本结构中使用 Solidity 智能合约
- sql - 如何从另一个表插入更新数据?
- java - Spring MVC:通过 REST 端点将字符串日期转换为日期
- android - 未解决参考
- r - geom_text 删除其他几何图形(geom_point 和 geom_line)