转换浮点数到int(32位C)的差异 [英] Difference in casting float to int, 32-bit C

查看:350
本文介绍了转换浮点数到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\n",c1,c2,c1-c2,f10,f1*10.0);
   }
}

使用-m32修饰符直接在32位系统或64位系统上编译(使用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版本4.15.0-45-通用(buildd @ lgw01-amd64-031)(gcc版本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版本2.4.20-8(bhcompile@porky.devel.redhat.com)(gcc版本3.2.2 20030222(Red Hat Linux 3.2.2-5)),使用以下代码编译程序:gcc 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)), 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,然后将结果转换回float并存储,然后再次检索并放置在FPU堆栈上(并再次转换为double),以调用__ftol2_sse,这是一种运行时函数,用于将double转换为

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,中间值将 not 与float进行转换,并立即传递给__ftol2_sse函数.对于此功能,另请参见将double转换为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 

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

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