我注意到 C# 编译器的浮点舍入/截断有一个有趣的行为。也就是说,当浮点文字超出保证的可表示范围(7 位十进制数字)时,a)将浮点结果显式转换为浮点(语义上不必要的操作)和 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
在我的计算机上的 JITted 调试版本中,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 中的最后一个(已经无法表示)数字被删除甚至减少,则所有内容都会“就位”。