[C#] 一個無聊的冷知識關於已知運算常數編譯後的MSIL

2023-02-06


寫一個有趣的小東西,大概算是 C# 冷知識,大概就跟台灣本島最北的國際機場是桃園中正機場而不是松山機場一樣冷知識

今天好奇問同事一個問題 假設我要 1+2+3+...+100 這答案

1. 我手動打 return 1+2+3+4+5+...+100; 

2. 我用迴圈  for (var i = 1; i <= 100; i++) 最後 return sum; 

3. 用梯形公式解  return ((1+100)*100)/2 

這三個到底 哪一個執行比較快


第二個會是最慢的應該是大家的共識,我的編譯器是 .NET 6


但是第三個跟第一個有爭論,有人說第三個會快點,我是贊成應該是差不多,原因是 現在 compiler 很聰明,這種應該會變成常數回傳

之後我就簡單寫了一個程式測試一下

並且透過 JetBrains dotPeek 看一下 MSIL CODE:


FuncA  (1 +2+3+4+...+100)

C# Code:

public static int FuncA()
{
return 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100;
}

MSIL:

.method public hidebysig static int32
FuncA() cil managed
{
.maxstack 1
.locals init (
[0] int32 V_0
)
// [51 9 - 51 10]
IL_0000: nop
// [52 13 - 52 510]
IL_0001: ldc.i4 5050 // 0x000013ba
IL_0006: stloc.0 // V_0
IL_0007: br.s IL_0009
// [54 9 - 54 10]
IL_0009: ldloc.0 // V_0
IL_000a: ret
} // end of method Program::FuncA


FuncC (梯形公式)

C# Code:

public static int FuncC()
{
return ((1 + 100) * 100) / 2;
}

MSIL:

.method public hidebysig static int32
FuncC() cil managed
{
.maxstack 1
.locals init (
[0] int32 V_0
)
// [34 9 - 34 10]
IL_0000: nop
// [36 13 - 36 42]
IL_0001: ldc.i4 5050 // 0x000013ba
IL_0006: stloc.0 // V_0
IL_0007: br.s IL_0009
// [37 9 - 37 10]
IL_0009: ldloc.0 // V_0
IL_000a: ret
} // end of method Program::FuncC


直接說重點

FuncA: IL_0001: ldc.i4       5050 // 0x000013ba

FuncC :IL_0001: ldc.i4       5050 // 0x000013ba


所以編譯器其實很聰明的直接算好當作常數回傳。

理論上值行會一樣快,冷知識阿


當麻許的超技八 2014 | Donma Hsu Design.