我注意到了C#编译器在浮点数的四舍五入/截断方面有一个有趣的行为。当一个浮点字面量超出了可表示的范围(7位小数)时,a) 明确将float结果强制转换为float(在语义上不必要的操作)和b) 将中间计算结果存储在本地变量中都会改变输出结果。例如:
using System;
class Program
{
static void Main()
{
float f = 2.0499999f;
var a = f * 100f;
var b = (int) (f * 100f);
var c = (int) (float) (f * 100f);
var d = (int) a;
var e = (int) (float) a;
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
Console.WriteLine(e);
}
}
输出结果如下:
205
204
205
205
205
在我的电脑上,经过JIT编译的调试版本中,b的计算方法如下:
var b = (int) (f * 100f);
0000005a fld dword ptr [ebp-3Ch]
0000005d fmul dword ptr ds:[035E1648h]
00000063 fstp qword ptr [ebp-5Ch]
00000066 movsd xmm0,mmword ptr [ebp-5Ch]
0000006b cvttsd2si eax,xmm0
0000006f mov dword ptr [ebp-44h],eax
而d的计算方式如下:
var d = (int) a;
00000096 fld dword ptr [ebp-40h]
00000099 fstp qword ptr [ebp-5Ch]
0000009c movsd xmm0,mmword ptr [ebp-5Ch]
000000a1 cvttsd2si eax,xmm0
000000a5 mov dword ptr [ebp-4Ch],eax
最后,我的问题是:为什么输出的第二行与第四行不同?这额外的fmul有如此大的影响吗?还要注意,如果去掉甚至减少浮点数f中的最后一个(已经无法表示的)数字,一切都“就位”了。