(int)((float)10.9 * 10)
Run Code Online (Sandbox Code Playgroud)
被评估为108.为什么?
IMO (int)-cast应在乘法后进行评估.
Bli*_*ndy 11
有趣的是,这里的问题是表达式是在编译时计算的,显然使用了预期的单精度数学.这在调试和发布版本中都会发生:
// this replaces the whole operation
IL_0001: ldc.i4.s 108
IL_0003: stloc.0
IL_0004: ldloc.0
IL_0005: call void [mscorlib]System.Console::WriteLine(int32)
Run Code Online (Sandbox Code Playgroud)
虽然案例var f =((float)10.9 * 10);int i = (int)f;仍然针对乘法进行了优化,但使用了双精度.因为演员是在一个单独的步骤完成的,我猜它会混淆编译器(??):
IL_000b: ldc.r4 109 // 109 result for the first part
IL_0010: stloc.1
IL_0011: ldloc.1
IL_0012: conv.i4 // separate conversion to int
IL_0013: stloc.2
// rest is printing it
IL_0014: ldloc.1
IL_0015: box [mscorlib]System.Single
IL_001a: ldstr " "
IL_001f: ldloc.2
IL_0020: box [mscorlib]System.Int32
IL_0025: call string [mscorlib]System.String::Concat(object, object, object)
IL_002a: call void [mscorlib]System.Console::WriteLine(string)
Run Code Online (Sandbox Code Playgroud)
老实说,我会说编译器在第二种情况下生成了错误的代码,这可能就是为什么C++避免优化像瘟疫那样的浮点代码.幸运的是,这只是这种测试代码的问题,可以在编译时完全完成,实际的变量乘法就可以了.
我其实也试过这个:
Console.WriteLine((int)(float.Parse(Console.ReadLine()) * int.Parse(Console.ReadLine())));
Run Code Online (Sandbox Code Playgroud)
并给出了10.9和10,结果是预期的108.
Joe*_*oey 10
情况确实如此.由于表示浮点数的方式,10.9 略低于 10.9(10.9无法准确表示,因此得到近似值,在这种情况下类似于10.89999999 ......).然后,强制转换会截断小数点后面的任何数字.所以你得到108.
这里的确切值如下(使用Jon Skeet的DoubleConverter类获得):
10.9 -> 10.9000000000000003552713678800500929355621337890625
(float) 10.9 -> 10.8999996185302734375
Run Code Online (Sandbox Code Playgroud)
将浮点数乘以10然后切掉所有小数位将显然导致108.