你們都知道,當進行嵌套循環時,大循環放最外面和放最裏面所形成的執行效率會不一樣,本篇文章會經過彙編代碼進行分析具體狀況。ubuntu
測試代碼:測試
1 #include <stdio.h> 2 3 /* 大循環在外 */ 4 void big_in_out (void) 5 { 6 int i; 7 int j; 8 int k; 9 10 for (i = 10000; i != 0; i--) 11 for (j = 1000; j != 0; j--) 12 for (k = 100; k != 0; k--) 13 ; 14 } 15 16 /* 大循環在內 */ 17 void big_in_in (void) 18 { 19 int i; 20 int j; 21 int k; 22 23 for (i = 100; i != 0; i--) 24 for (j = 1000; j != 0; j--) 25 for (k = 10000; k != 0; k--) 26 ; 27 } 28 29 int main (int argc, char * argv[]) 30 { 31 return 0; 32 }
經過objdump命令,獲取其彙編代碼,以下:spa
1 #include <stdio.h> 2 3 void big_in_out (void) 4 { 5 4004ed: 55 push %rbp 6 4004ee: 48 89 e5 mov %rsp,%rbp 7 int i; 8 int j; 9 int k; 10 11 for (i = 10000; i != 0; i--) 12 4004f1: c7 45 f4 10 27 00 00 movl $0x2710,-0xc(%rbp) # i = 10000 13 4004f8: eb 2a jmp 400524 <big_in_out+0x37> # 跳轉至400524 14 for (j = 1000; j != 0; j--) 15 4004fa: c7 45 f8 e8 03 00 00 movl $0x3e8,-0x8(%rbp) # j = 1000 16 400501: eb 17 jmp 40051a <big_in_out+0x2d> # 跳轉至40051a 17 for (k = 100; k != 0; k--) 18 400503: c7 45 fc 64 00 00 00 movl $0x64,-0x4(%rbp) # k = 100 19 40050a: eb 04 jmp 400510 <big_in_out+0x23> # 跳轉至400510 20 40050c: 83 6d fc 01 subl $0x1,-0x4(%rbp) # k = k - 1 21 400510: 83 7d fc 00 cmpl $0x0,-0x4(%rbp) # 判斷k是否爲0 22 400514: 75 f6 jne 40050c <big_in_out+0x1f> # 不爲0跳轉至40050c 23 int i; 24 int j; 25 int k; 26 27 for (i = 10000; i != 0; i--) 28 for (j = 1000; j != 0; j--) 29 400516: 83 6d f8 01 subl $0x1,-0x8(%rbp) # j = j - 1 30 40051a: 83 7d f8 00 cmpl $0x0,-0x8(%rbp) # 判斷j是否爲0 31 40051e: 75 e3 jne 400503 <big_in_out+0x16> # j不爲0跳轉至400503 32 { 33 int i; 34 int j; 35 int k; 36 37 for (i = 10000; i != 0; i--) 38 400520: 83 6d f4 01 subl $0x1,-0xc(%rbp) # i = i - 1 39 400524: 83 7d f4 00 cmpl $0x0,-0xc(%rbp) # 判斷i是否爲0 40 400528: 75 d0 jne 4004fa <big_in_out+0xd> # i不爲0跳轉至4004fa 41 for (j = 1000; j != 0; j--) 42 for (k = 100; k != 0; k--) 43 ; 44 } 45 40052a: 5d pop %rbp 46 40052b: c3 retq 47 48 000000000040052c <big_in_in>: 49 50 void big_in_in (void) 51 { 52 40052c: 55 push %rbp 53 40052d: 48 89 e5 mov %rsp,%rbp 54 int i; 55 int j; 56 int k; 57 58 for (i = 100; i != 0; i--) 59 400530: c7 45 f4 64 00 00 00 movl $0x64,-0xc(%rbp) # i = 100 60 400537: eb 2a jmp 400563 <big_in_in+0x37> # 跳轉至400563 61 for (j = 1000; j != 0; j--) 62 400539: c7 45 f8 e8 03 00 00 movl $0x3e8,-0x8(%rbp) # j = 1000 63 400540: eb 17 jmp 400559 <big_in_in+0x2d> # 跳轉至400559 64 for (k = 10000; k != 0; k--) 65 400542: c7 45 fc 10 27 00 00 movl $0x2710,-0x4(%rbp) # k = 10000 66 400549: eb 04 jmp 40054f <big_in_in+0x23> # 跳轉至40054f 67 40054b: 83 6d fc 01 subl $0x1,-0x4(%rbp) # k = k - 1 68 40054f: 83 7d fc 00 cmpl $0x0,-0x4(%rbp) # 判斷k是否爲0 69 400553: 75 f6 jne 40054b <big_in_in+0x1f> # 不爲0跳轉至40054b 70 int i; 71 int j; 72 int k; 73 74 for (i = 100; i != 0; i--) 75 for (j = 1000; j != 0; j--) 76 400555: 83 6d f8 01 subl $0x1,-0x8(%rbp) # j = j - 1 77 400559: 83 7d f8 00 cmpl $0x0,-0x8(%rbp) # 判斷j是否爲0 78 40055d: 75 e3 jne 400542 <big_in_in+0x16> # j不爲0跳轉至400542 79 { 80 int i; 81 int j; 82 int k; 83 84 for (i = 100; i != 0; i--) 85 40055f: 83 6d f4 01 subl $0x1,-0xc(%rbp) # i = i - 1 86 400563: 83 7d f4 00 cmpl $0x0,-0xc(%rbp) # 判斷i是否爲0 87 400567: 75 d0 jne 400539 <big_in_in+0xd> # i不爲0跳轉至400539 88 for (j = 1000; j != 0; j--) 89 for (k = 10000; k != 0; k--) 90 ; 91 } 92 400569: 5d pop %rbp 93 40056a: c3 retq 94 95 000000000040056b <main>: 96 97 int main (int argc, char * argv[]) 98 { 99 40056b: 55 push %rbp 100 40056c: 48 89 e5 mov %rsp,%rbp 101 40056f: 89 7d fc mov %edi,-0x4(%rbp) 102 400572: 48 89 75 f0 mov %rsi,-0x10(%rbp) 103 return 0; 104 400576: b8 00 00 00 00 mov $0x0,%eax 105 }
因爲是嵌套循環,即便循環0次,好比for(i = 0; i != 0; i--)狀況,都須要執行4條指令,分別是:賦值、跳轉、比較、判斷跳轉。具體的例子如18行~22行彙編代碼所體現的狀況(假設k賦值爲0)。而for的主循環結構爲3條指令,分別爲:賦值、比較、判斷跳轉。具體例子一樣也是18行~22行的彙編代碼所體現。因此在嵌套循環中,假如其中一個循環結構須要循環n次,它所須要執行的指令量爲:操作系統
指令量 = 4 + 3n
好的,根據以上所得的結論,咱們能夠很輕鬆的計算出大循環在外的整個三層循環所須要執行的指令數量,以下:code
i = 10000 j = 1000 k = 100 i循環結構指令數量 = 4 + i * 3 = 30004 j循環結構指令數量 = 4 + j * 3 = 3004 k循環結構指令數量 = 4 + k * 3 = 304 i循環結構被循環次數 = 1 j循環結構被循環次數 = i k循環結構被循環次數 = i * j 整個結構指令數量 = i循環結構指令數量 * i循環結構被循環次數 + j循環結構指令數量 * j循環結構被循環次數 + k循環結構指令數量 * k循環結構被循環次數 整個結構指令數量 = 30004 * 1 + 3004 * 10000 + 304 * 1000 * 10000 = 3070070004
同上,咱們也能夠計算出大循環在內的整個三層循環所須要執行的指令數量,以下:blog
i = 100 j = 1000 k = 10000 i循環結構指令數量 = 4 + i * 3 = 304 j循環結構指令數量 = 4 + j * 3 = 3004 k循環結構指令數量 = 4 + k * 3 = 30004 i循環結構被循環次數 = 1 j循環結構被循環次數 = i k循環結構被循環次數 = i * j 整個結構指令數量 = i循環結構指令數量 * i循環結構被循環次數 + j循環結構指令數量 * j循環結構被循環次數 + k循環結構指令數量 * k循環結構被循環次數 整個結構指令數量 = 304 * 1 + 3004 * 100 + 30004 * 100 * 1000 = 3000700704
能夠很清楚得看出來,大循環在內所須要執行的指令數量 < 大循環在外所需執行的指令數量。表示在嵌套循環中,把大循環放入內層比把大循環放入外層的代碼要高。而爲何會這樣,咱們能夠經過數學進行計算,以下:get
假設 X1,X2,X3,X4,X5,...,Xn都爲正整數,他們表明着循環次數,而且 0 < X1 < X2 < X3 < X4 < X5 < ..... < Xn。
大循環在外的狀況
第n層(最內層)的循環結構所須要執行的指令次數爲: (4 + 3X1)X2X3X4X5...Xn
第n-1層循環結構所須要執行的指令次數爲: (4 + 3X2)X3X4X5...Xn
第n-2層循環結構所須要執行的指令次數爲: (4 + 3X3)X4X5...Xn
....................
第2層循環結構所須要執行指令次數爲: (4 + 3Xn-1)Xn
第1層循環結構所須要執行的指令次數爲: (4 + 3Xn)
總指令數爲編譯器
ALL1 = (4 + 3X1)X2X3X4X5...Xn + (4 + 3X2)X3X4X5...Xn + (4 + 3X3)X4X5...Xn + (4 + 3X4)X5...Xn +...+ (4 + 3Xn-1)Xn + (4 + 3Xn)數學
ALL1 = 4X2X3X4X5...Xn + 3X1X2X3X4X5...Xn + 4X3X4X5...Xn + 3X2X3X4X5...Xn + 4X4X5...Xn + 3X2X3X4...Xn + 4X5...Xn + 3X4X5...Xn +...+ 4Xn + 3Xn-1Xn + 4 + 3Xnit
合併同類項後,得
ALL1 = 4 + 3X1X2X3X4X5...Xn + 7X2X3X4X5...Xn + 7X3X4X5...Xn + 7X4X5...Xn +7X5...Xn + ... + 7Xn-1Xn + 7Xn
總指令數爲
ALL2 = (4 + 3Xn)Xn-1Xn-2Xn-3Xn-4...X1 + (4 + 3Xn-1)Xn-2Xn-3Xn-4...X1 + (4 + 3Xn-2)Xn-3Xn-4...X1 + (4 + 3Xn-3)Xn-4...X1 +...+ (4 + 3X2)X1 + (4 + 3X1)
ALL2 = 4X1X2X3X4...Xn-1 + 3X1X2X3X4X5...Xn + 4X1X2X3...Xn-2 + 3X1X2X3X4...Xn-1 + 4X1X2...Xn-3 + 3X1X2X3...Xn-2 + 4X1...Xn-4 + 3X1X2...Xn-3 +...+ 4X1 + 3X2X1 + 4 + 3X1
合併同類項後,得
ALL2 = 4 + 3X1X2X3X4X5...Xn + 7X1X2X3X4...Xn-1 + 7X1X2X3...Xn-2 + 7X1X2...Xn-3 +7X1...Xn-4 + ... + 7X2X1 + 7X1
結果
大循環在外的總指令數爲ALL1,大循環在內的總指令數爲ALL2,咱們用ALL1的每一項除以ALL2中對應的每一項,結果爲R,以下
R1 = 4 / 4 = 1
R2 = 3X1X2X3X4X5...Xn / 3X1X2X3X4X5...Xn = 1
R3 = 7X2X3X4X5...Xn / 7X1X2X3X4...Xn-1 = Xn / X1 > 1
R4 = 7X3X4X5...Xn / 7X1X2X3...Xn-2 = XnXn-1 / X1X2 > 1
R5 = 7X4X5...Xn / 7X1X2...Xn-3 = XnXn-1Xn-2 / X1X2X3 > 1
R6 = 7X5...Xn / 7X1...Xn-4 = XnXn-1Xn-2Xn-3 / X1X2X3X4 > 1
......
Rm-1 = 7Xn-1Xn / 7X2X1 > 1
Rm = 7Xn / 7X1 > 1
從以上結果能夠很明顯的看出,除了ALL1和ALL2公有項4,3X1X2X3X4X5...Xn相除爲1,其餘ALL1的每一項對應除以ALL2的每一項,結果R都大於1,說明ALL1中的每一項都大於ALL2中對應的每一項,即說明了ALL1 > ALL2 ,同時也證實了大循環在外所須要執行的指令數量大於大循環在內所須要執行的指令數量,也就是將大循環放在內層時比大循環放在外層的循環效率要高的。