C言語で実験プログラムを作りました。
変数の型によって速度の差があるかを確かめました。
64bit整数型:C/C++における整数型には気をつけよ
#include<stdio.h> #include<time.h> #define N 100000000 int main(){ char c1, c2, c3; short s1, s2, s3; long l1, l2, l3; long long ll1, ll2, ll3; int start, end; long i; c1 = 123; c2 = 45; start = clock(); for(i = 0; i <= N; i++) c3 = c1 / c2; end = clock(); printf("8bit整数の処理時間 = %f秒\n", (double)(end - start) / CLOCKS_PER_SEC); s1 = 123; s2 = 45; start = clock(); for(i = 0; i <= N; i++) s3 = s1 / s2; end = clock(); printf("16bit整数の処理時間 = %f秒\n", (double)(end - start) / CLOCKS_PER_SEC); l1 = 123; l2 = 45; start = clock(); for(i = 0; i <= N; i++) l3 = l1 / l2; end = clock(); printf("32bit整数の処理時間 = %f秒\n", (double)(end - start) / CLOCKS_PER_SEC); ll1 = 123; ll2 = 45; start = clock(); for(i = 0; i<= N; i++) ll3 = ll1 / ll2; end = clock(); printf("64bit整数の処理時間 = %f秒\n", (double)(end - start) / CLOCKS_PER_SEC); return 0; }
gcc 64bitでコンパイルした結果を書きます。
8bit整数の処理時間 = 0.320907秒
16bit整数の処理時間 = 0.314072秒
32bit整数の処理時間 = 0.993952秒
64bit整数の処理時間 = 0.931070秒
なぜ、8bitや16bitの方が32bitや64bitより早いのでしょうか??
私の持っている本に、こう書いてあります。
CPUのレジスタ語長の整数倍のアドレスから始まるように置かれると、 CPUはその領域との読み書きを最も効率良く実行できます。
ということは、本来64bitシステムなら64bit整数型が最速になるはずではないでしょうか??
アライメントに関わる問題ですね。
アラインメントのサイズ
以前した質問の
CPUが64bitなら8バイト境界
というのは、アドレスバスの事かと思っていたのですが、どうもレジスタ長が64bitなら8の倍数で最速。という意味のようです。
では、なんで今回の実験では、64bit整数型が遅くなっているのでしょうか??
逆に、long long型を外して、32bitコンパイルをすると32bit型が最速になります。
32bitと64bitで結果が異なるようです。
32bitだと本の通りですね。
別の本には以下のようにあります。
32bit CPUでは、32bitのサイズで演算を行います。
32bitに満たない8bitや16bitはのデータは、32bitに拡張されてから演算されます。
32bitデータではこの拡張処理が不要なので、実行時間が短縮されるのです。
アライメントが超難しいです。
わかる方いますか??
Linux 64bit OS で実験しました。
[追記]
書くのを忘れていました。最適化は行っていません。
今回の場合、最適化を行うと実験の意味がなくなってしまいます。
Intel Core i7-4650U @ 4x 3.3GHz
Linux 64bit環境
[追記2]
objdump -d による結果を載せます。64bitコンパイルの方です。
main()を一応全部載せておきます。
000000000000068a <main>: 68a: 55 push %rbp 68b: 48 89 e5 mov %rsp,%rbp 68e: 48 83 ec 50 sub $0x50,%rsp 692: c6 45 f7 7b movb $0x7b,-0x9(%rbp) 696: c6 45 f6 2d movb $0x2d,-0xa(%rbp) 69a: e8 b1 fe ff ff callq 550 <clock@plt> 69f: 89 45 f0 mov %eax,-0x10(%rbp) 6a2: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp) 6a9: 00 6aa: eb 13 jmp 6bf <main+0x35> 6ac: 0f be 45 f7 movsbl -0x9(%rbp),%eax 6b0: 0f be 4d f6 movsbl -0xa(%rbp),%ecx 6b4: 99 cltd 6b5: f7 f9 idiv %ecx 6b7: 88 45 b5 mov %al,-0x4b(%rbp) 6ba: 48 83 45 f8 01 addq $0x1,-0x8(%rbp) 6bf: 48 81 7d f8 00 e1 f5 cmpq $0x5f5e100,-0x8(%rbp) 6c6: 05 6c7: 7e e3 jle 6ac <main+0x22> 6c9: e8 82 fe ff ff callq 550 <clock@plt> 6ce: 89 45 ec mov %eax,-0x14(%rbp) 6d1: 8b 45 ec mov -0x14(%rbp),%eax 6d4: 2b 45 f0 sub -0x10(%rbp),%eax 6d7: f2 0f 2a c0 cvtsi2sd %eax,%xmm0 6db: f2 0f 10 0d 95 02 00 movsd 0x295(%rip),%xmm1 # 978 <_IO_stdin_used+0xa8> 6e2: 00 6e3: f2 0f 5e c1 divsd %xmm1,%xmm0 6e7: 48 8d 3d ea 01 00 00 lea 0x1ea(%rip),%rdi # 8d8 <_IO_stdin_used+0x8> 6ee: b8 01 00 00 00 mov $0x1,%eax 6f3: e8 68 fe ff ff callq 560 <printf@plt> 6f8: 66 c7 45 ea 7b 00 movw $0x7b,-0x16(%rbp) 6fe: 66 c7 45 e8 2d 00 movw $0x2d,-0x18(%rbp) 704: e8 47 fe ff ff callq 550 <clock@plt> 709: 89 45 f0 mov %eax,-0x10(%rbp) 70c: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp) 713: 00 714: eb 14 jmp 72a <main+0xa0> 716: 0f bf 45 ea movswl -0x16(%rbp),%eax 71a: 0f bf 75 e8 movswl -0x18(%rbp),%esi 71e: 99 cltd 71f: f7 fe idiv %esi 721: 66 89 45 b6 mov %ax,-0x4a(%rbp) 725: 48 83 45 f8 01 addq $0x1,-0x8(%rbp) 72a: 48 81 7d f8 00 e1 f5 cmpq $0x5f5e100,-0x8(%rbp) 731: 05 732: 7e e2 jle 716 <main+0x8c> 734: e8 17 fe ff ff callq 550 <clock@plt> 739: 89 45 ec mov %eax,-0x14(%rbp) 73c: 8b 45 ec mov -0x14(%rbp),%eax 73f: 2b 45 f0 sub -0x10(%rbp),%eax 742: f2 0f 2a c0 cvtsi2sd %eax,%xmm0 746: f2 0f 10 0d 2a 02 00 movsd 0x22a(%rip),%xmm1 # 978 <_IO_stdin_used+0xa8> 74d: 00 74e: f2 0f 5e c1 divsd %xmm1,%xmm0 752: 48 8d 3d a7 01 00 00 lea 0x1a7(%rip),%rdi # 900 <_IO_stdin_used+0x30> 759: b8 01 00 00 00 mov $0x1,%eax 75e: e8 fd fd ff ff callq 560 <printf@plt> 763: 48 c7 45 e0 7b 00 00 movq $0x7b,-0x20(%rbp) 76a: 00 76b: 48 c7 45 d8 2d 00 00 movq $0x2d,-0x28(%rbp) 772: 00 773: e8 d8 fd ff ff callq 550 <clock@plt> 778: 89 45 f0 mov %eax,-0x10(%rbp) 77b: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp) 782: 00 783: eb 13 jmp 798 <main+0x10e> 785: 48 8b 45 e0 mov -0x20(%rbp),%rax 789: 48 99 cqto 78b: 48 f7 7d d8 idivq -0x28(%rbp) 78f: 48 89 45 b8 mov %rax,-0x48(%rbp) 793: 48 83 45 f8 01 addq $0x1,-0x8(%rbp) 798: 48 81 7d f8 00 e1 f5 cmpq $0x5f5e100,-0x8(%rbp) 79f: 05 7a0: 7e e3 jle 785 <main+0xfb> 7a2: e8 a9 fd ff ff callq 550 <clock@plt> 7a7: 89 45 ec mov %eax,-0x14(%rbp) 7aa: 8b 45 ec mov -0x14(%rbp),%eax 7ad: 2b 45 f0 sub -0x10(%rbp),%eax 7b0: f2 0f 2a c0 cvtsi2sd %eax,%xmm0 7b4: f2 0f 10 0d bc 01 00 movsd 0x1bc(%rip),%xmm1 # 978 <_IO_stdin_used+0xa8> 7bb: 00 7bc: f2 0f 5e c1 divsd %xmm1,%xmm0 7c0: 48 8d 3d 61 01 00 00 lea 0x161(%rip),%rdi # 928 <_IO_stdin_used+0x58> 7c7: b8 01 00 00 00 mov $0x1,%eax 7cc: e8 8f fd ff ff callq 560 <printf@plt> 7d1: 48 c7 45 d0 7b 00 00 movq $0x7b,-0x30(%rbp) 7d8: 00 7d9: 48 c7 45 c8 2d 00 00 movq $0x2d,-0x38(%rbp) 7e0: 00 7e1: e8 6a fd ff ff callq 550 <clock@plt> 7e6: 89 45 f0 mov %eax,-0x10(%rbp) 7e9: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp) 7f0: 00 7f1: eb 13 jmp 806 <main+0x17c> 7f3: 48 8b 45 d0 mov -0x30(%rbp),%rax 7f7: 48 99 cqto 7f9: 48 f7 7d c8 idivq -0x38(%rbp) 7fd: 48 89 45 c0 mov %rax,-0x40(%rbp) 801: 48 83 45 f8 01 addq $0x1,-0x8(%rbp) 806: 48 81 7d f8 00 e1 f5 cmpq $0x5f5e100,-0x8(%rbp) 80d: 05 80e: 7e e3 jle 7f3 <main+0x169> 810: e8 3b fd ff ff callq 550 <clock@plt> 815: 89 45 ec mov %eax,-0x14(%rbp) 818: 8b 45 ec mov -0x14(%rbp),%eax 81b: 2b 45 f0 sub -0x10(%rbp),%eax 81e: f2 0f 2a c0 cvtsi2sd %eax,%xmm0 822: f2 0f 10 0d 4e 01 00 movsd 0x14e(%rip),%xmm1 # 978 <_IO_stdin_used+0xa8> 829: 00 82a: f2 0f 5e c1 divsd %xmm1,%xmm0 82e: 48 8d 3d 1b 01 00 00 lea 0x11b(%rip),%rdi # 950 <_IO_stdin_used+0x80> 835: b8 01 00 00 00 mov $0x1,%eax 83a: e8 21 fd ff ff callq 560 <printf@plt> 83f: b8 00 00 00 00 mov $0x0,%eax 844: c9 leaveq 845: c3 retq 846: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 84d: 00 00 00
[追記3]
同じようなことを議論しているサイトを見つけました。
64bit化による処理速度の影響
整数の型にint型ばかりを使うのは何故でしょうか。
C言語の型による処理速度の違い
short と int の計算速度
最も速い数値型
CPUには得意なデータ型というものがあります。
とのことです。
これは、変数のサイズがCPUのレジスタ長と一致していれば相性が良いということなんでしょうかね??
C++だと、cstdintに「Nbitの精度を保証して、かつ処理効率が最速になる型」というものが定義されている
単に、機械語だけだとすると、上記のような型を定義する必要はありませんよね??
回答6件
あなたの回答
tips
プレビュー