[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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static int FuncC() | |
{ | |
return ((1 + 100) * 100) / 2; | |
} | |
MSIL:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.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
所以編譯器其實很聰明的直接算好當作常數回傳。
理論上值行會一樣快,冷知識阿