Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding the given calculation (cast + multiplication)

Tags:

c#

.net

casting

(int)((float)10.9 * 10)

is evaluated to 108. Why?

IMO the (int)-cast should be evaluated after the multiplication.

like image 839
Tho Mai Avatar asked Nov 04 '15 06:11

Tho Mai


1 Answers

Amusingly enough, the issue here is that the expression is calculated at compile time, apparently using single precision math as expected. This happens in both debug and release builds:

    // 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)

While the case var f =((float)10.9 * 10);int i = (int)f; is still optimized for the multiplication, but using double precision. Because the cast is done in a separate step I guess it confuses the compiler (??):

    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)

Honestly I'd say the compiler is generating wrong code in the second case, which is probably why C++ avoids optimizing floating point code like the plague. Luckily, this is only an issue for this kind of test code which can be done fully at compile time, actual variable multiplication would be fine.

I actually tried this too:

Console.WriteLine((int)(float.Parse(Console.ReadLine()) * int.Parse(Console.ReadLine())));

and gave it 10.9 and 10, and the result was 108 as expected.

like image 190
Blindy Avatar answered Sep 22 '22 01:09

Blindy