理解给定的计算(cast + multiplication)

tho*_*mai 15 .net c# casting

(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.

  • 嗯,我不明白为什么要把它分成两个声明作品.`var f =((float)10.9*10); int i =(int)f;`给出109和109 (3认同)
  • @thomai:您可以使用[Jon Skeet](http://stackoverflow.com/users/22656/jon-skeet)的[DoubleConverter类](http://www.yoda.arachsys.com/csharp/DoubleConverter. cs)有一个`ToExactString`方法.代码可以很容易地适应`float`,但`float`的工作方式完全相同,只需少量十进制数. (3认同)