我在另一个线程中的回答并不完全正确:实际上,在运行时计算时,(byte)(64 / 0.8f)
is 80.罢工>
当施放一个float
包含结果64 / 0.8f
, to byte
在运行时,结果实际上是 80。但是,当转换作为赋值的一部分完成时,情况并非如此:
float f1 = (64 / 0.8f);
byte b1 = (byte) f1;
byte b2 = (byte)(64 / 0.8f);
Console.WriteLine(b1); //80
Console.WriteLine(b2); //79
虽然 b1 包含预期结果,但 b2 关闭。根据反汇编,b2 的赋值如下:
mov dword ptr [ebp-48h],4Fh
因此,编译器计算出的结果似乎与运行时的结果不同。但是,我不知道这是否是预期的行为。
EDIT:也许这就是 Pascal Cuoq 所描述的效果:在编译时,C# 编译器使用double
来计算表达式。这会导致 79,xxx 被截断为 79(因为双精度数包含足够的精度,因此会导致问题)。
然而,使用浮点数,我们实际上并没有遇到问题,因为浮点“错误”发生在浮点数的范围内。
在运行时,这个也打印 79:
double d1 = (64 / 0.8f);
byte b3 = (byte) d1;
Console.WriteLine(b3); //79
EDIT2:根据 Pascal Cuoq 的要求,我运行了以下代码:
int sixtyfour = Int32.Parse("64");
byte b4 = (byte)(sixtyfour / 0.8f);
Console.WriteLine(b4); //79
结果是79。所以上面所说的编译器和运行时计算出不同结果的说法是不正确的。
EDIT3:将之前的代码更改为(再次归功于 Pascal Cuoq)时,结果为 80:
byte b5 = (byte)(float)(sixtyfour / 0.8f);
Console.WriteLine(b5); //80
但请注意,写入时情况并非如此(结果为 79):
byte b6 = (byte)(float)(64 / 0.8f);
Console.WriteLine(b6); //79
所以这似乎是发生的事情:(byte)(64 / 0.8f)
不被评价为float
,但评估为double
(在将其投射到byte
)。这会导致舍入误差(当使用以下方法完成计算时不会发生舍入误差)float
)。在转换为 double 之前显式转换为 float(顺便说一句,这被 ReSharper 标记为多余)“解决”了这个问题。但是,当计算在编译时完成时(仅使用常量时可能),显式转换为float
似乎被忽略/优化掉了。
TLDR:浮点计算比最初看起来更复杂。