3

2 番目のフィールドでソートする必要がある任意の長さの整数を含む大きなデータ ファイルがある場合:

1 3 4 5
1 4 5 7
-1 34 56 7
124 58394 1384 -1938
1948 3848089 -14850 0
1048 01840 1039 888
//consider this is a LARGE file, the data goes on for quite some time

そして、ソート関数内で qsort を選択の武器にするように求めます。短縮形の IF を使用すると、データのソートにかかる全体的な時間のパフォーマンスが大幅に向上しますか? それとも、省略形の IF は、コードを整理するための便利なツールとしてのみ使用されますか?

num2 = atoi(Str);
num1 = atoi(Str2);
LoggNum = (num2 > num1) ? num2 : num1; //faster?

num2 = atoi(Str);
num1 = atoi(Str2);
if(num2 > num1)    //or the same?
    LoggNum = num2;
else
    LoggNum = num1;
4

5 に答える 5

10

最新のコンパイラは、これら 2 つのケースで同一のコードをビルドしますが、違いはスタイルと利便性の 1 つだけです。

于 2012-12-04T11:46:05.937 に答える
4

この質問に対する答えはありません...コンパイラは、適切と思われるコードを自由に生成できます。とはいえ、特に愚かなコンパイラだけが、これらのケースに対して大幅に異なるコードを生成します。あなたのプログラムがどのように機能するかを最もよく表現していると思うものは何でも書くべきです... 私にとっては、三項演算子バージョンの方が簡潔で読みやすいですが、C や C++ に慣れていない人は、最初は if/else バージョンの方が理解しやすいかもしれません。

このようなことに興味があり、コード生成をよりよく理解したい場合は、コンパイラを呼び出して、プログラムの CPU 命令を示すアセンブリ言語出力を生成する方法を学ぶ必要があります。たとえば、GNU コンパイラは、アセンブリ言語ファイル-Sを生成するフラグを受け入れます。.s

于 2012-12-04T11:47:08.003 に答える
3

この特定の最適化は、ロック関数で1つの形式から別の形式に変更することで、マクロベンチマークで実行時間を10%節約した実際のコードベースに私を悩ませました。

MacOSでgcc4.2.1を使用してこれをテストしてみましょう。

int global;

void
foo(int x, int y)
{
    if (x < y)
        global = x;
    else
        global = y;
}

void
bar(int x, int y)
{
    global = (x < y) ? x : y;
}

取得(クリーンアップ):

_foo:
        cmpl    %esi, %edi
        jge     L2
        movq    _global@GOTPCREL(%rip), %rax
        movl    %edi, (%rax)
        ret
L2:
        movq    _global@GOTPCREL(%rip), %rax
        movl    %esi, (%rax)
        ret

_bar:
        cmpl    %edi, %esi
        cmovle  %esi, %edi
        movq    _global@GOTPCREL(%rip), %rax
        movl    %edi, (%rax)
        ret

この種の操作のパフォーマンスを向上させるために(パイプラインストールを回避することにより)cmov命令が特別に追加されたことを考えると、この特定のコンパイラの「?:」の方が高速であることは明らかです。

どちらの場合も、コンパイラは同じコードを生成する必要がありますか?はい。しますか?もちろんそうではありません。完璧なコンパイラはありません。パフォーマンスに本当に関心がある場合(ほとんどの場合、そうすべきではありません)、テストして確認してください。

于 2012-12-04T12:31:57.433 に答える
3

VC2010で次の2つのステートメントをテストしました。

?=の生成されたアセンブリは次のとおりです。

 01207AE1 cmp byte ptr [ebp-101h],0
 01207AE8 jne CTestSOFDlg::OnBnClickedButton1+47h (1207AF7h)
 01207AEA push offset (1207BE5h)
 01207AEF call @ILT+840(__RTC_UninitUse) (120134Dh)
 01207AF4 add esp,4
 01207AF7 cmp byte ptr [ebp-0F5h],0
 01207AFE jne CTestSOFDlg::OnBnClickedButton1+5Dh (1207B0Dh)
 01207B00 push offset (1207BE0h)
 01207B05 call @ILT+840(__RTC_UninitUse) (120134Dh)
 01207B0A add esp,4
 01207B0D mov eax,dword ptr [num2]
 01207B10 cmp eax,dword ptr [num1]
 01207B13 jle CTestSOFDlg::OnBnClickedButton1+86h (1207B36h)
 01207B15 cmp byte ptr [ebp-101h],0
 01207B1C jne CTestSOFDlg::OnBnClickedButton1+7Bh (1207B2Bh)
 01207B1E push offset (1207BE5h)
 01207B23 call @ILT+840(__RTC_UninitUse) (120134Dh)
 01207B28 add esp,4
 01207B2B mov ecx,dword ptr [num2]
 01207B2E mov dword ptr [ebp-10Ch],ecx
 01207B34 jmp CTestSOFDlg::OnBnClickedButton1+0A5h (1207B55h)
 01207B36 cmp byte ptr [ebp-0F5h],0
 01207B3D jne CTestSOFDlg::OnBnClickedButton1+9Ch (1207B4Ch)
 01207B3F push offset (1207BE0h)
 01207B44 call @ILT+840(__RTC_UninitUse) (120134Dh)
 01207B49 add esp,4
 01207B4C mov edx,dword ptr [num1]
 01207B4F mov dword ptr [ebp-10Ch],edx
 01207B55 mov eax,dword ptr [ebp-10Ch]
 01207B5B mov dword ptr [LoggNum],eax

およびifelse演算子の場合:

 01207B5E cmp byte ptr [ebp-101h],0
 01207B65 jne CTestSOFDlg::OnBnClickedButton1+0C4h (1207B74h)
 01207B67 push offset (1207BE5h)
 01207B6C call @ILT+840(__RTC_UninitUse) (120134Dh)
 01207B71 add esp,4
 01207B74 cmp byte ptr [ebp-0F5h],0
 01207B7B jne CTestSOFDlg::OnBnClickedButton1+0DAh (1207B8Ah)
 01207B7D push offset (1207BE0h)
 01207B82 call @ILT+840(__RTC_UninitUse) (120134Dh)
 01207B87 add esp,4
 01207B8A mov eax,dword ptr [num2]
 01207B8D cmp eax,dword ptr [num1]
 01207B90 jle CTestSOFDlg::OnBnClickedButton1+100h (1207BB0h)
 01207B92 cmp byte ptr [ebp-101h],0
 01207B99 jne CTestSOFDlg::OnBnClickedButton1+0F8h (1207BA8h)
 01207B9B push offset (1207BE5h)
 01207BA0 call @ILT+840(__RTC_UninitUse) (120134Dh)
 01207BA5 add esp,4
 01207BA8 mov eax,dword ptr [num2]
 01207BAB mov dword ptr [LoggNum],eax
 01207BB0 cmp byte ptr [ebp-0F5h],0
 01207BB7 jne CTestSOFDlg::OnBnClickedButton1+116h (1207BC6h)
 01207BB9 push offset (1207BE0h)
 01207BBE call @ILT+840(__RTC_UninitUse) (120134Dh)
 01207BC3 add esp,4
 01207BC6 mov eax,dword ptr [num1]
 01207BC9 mov dword ptr [LoggNum],eax

ご覧のとおり、?=演算子にはさらに2つのasmコマンドがあります。

01207B4C mov edx,dword ptr [num1]
01207B4F mov dword ptr [ebp-10Ch],edx

これはより多くのCPUティックを必要とします。

それ以外の方が速い場合は、97000000サイズのループの場合。

于 2012-12-04T12:02:50.673 に答える
3

知る唯一の方法は、プロファイルすることです。ただし、三項演算子を使用すると、オブジェクトの初期化を行うことができます。

Sometype z = ( x < y) ? something : somethingElse; // copy initialization

ではif-else、同等の動作を得るために追加の割り当てを使用する必要があります。

SomeType z; // default construction
if ( x < y) {
  z = something; // assignment
} else {
  z = somethingElse; // assignment
}

への割り当てのオーバーヘッドが大きい場合、これは影響を与える可能性がありSomeTypeます。

于 2012-12-04T11:48:04.530 に答える