5

次の2つのループがあります。

#include <iostream>
#include <stdlib.h>
#include <time.h>

using namespace std;
int main(){

    int start=clock();
    for (int i=0;i<100;i++)
        cout<<i<<" "<<endl;
    cout<<clock()-start<<"\n"<<endl;
    cout<<"\n";

    int start1=clock();
    for (int j=0;j<100;++j)
        cout<<j<<" "<<endl;
    cout<<"\n";
    cout<<clock()-start1<<" \n "<<endl;

    return 0;
}

私はそれを3回実行しました。最初の2回の実行では、2番目のループが最速でしたが、3回目の実行では、最初のループが最速でした。これは何を意味するのでしょうか?どちらが良いですか?状況次第ですか?

4

8 に答える 8

10

ループの実行時間は、入出力操作によって圧倒的に支配されています。これは、1)ループの実際のパフォーマンス(つまり、 i++vs ++j)とは関係がなく、2)予測不可能で不安定な(本質的にランダムな)時間を観察することを意味します。

言い換えれば、あなたの実験は無意味です。それは絶対に何の意味もありません。

最後に、組み込み++演算子の結果が使用されない状況では、接尾辞と接頭辞の増分にまったく違いはありません。妥当なコンパイラでは、両方のループのパフォーマンスはまったく同じになります。

于 2010-08-02T07:18:36.903 に答える
5

あなたの場合、それはおそらく標準的な測定誤差であり、ポストインクリメントまたはプレインクリメントのどちらを使用するかは問題ではありません。標準型(int、byte ...)の場合、それは重要ではありません。

ただし、クラスでプレインクリメントを使用すると、それらの演算子の実装方法によってはパフォーマンスに影響するため、プレインクリメントの使用に慣れる必要があります。ポストインクリメント演算子i++は、オブジェクトのコピーを作成する必要があります

例えば:

class integer
{
public:
  integer(int t_value)
    : m_value(t_value)
  {
  }

  int get_value() { return m_value; }

  integer &operator++() // pre increment operator
  {
    ++m_value;
    return *this;
  }

  integer operator++(int) // post increment operator
  {
    integer old = *this; // a copy is made, it's cheap, but it's still a copy
    ++m_value;
    return old; // Return old copy
  }

private:
  int m_value;

次の答えを見てください

StackOverflow:i++は++iよりも効率が悪いですが、これを表示するにはどうすればよいですか?

于 2010-08-02T07:23:23.370 に答える
4

これらのループは、int型の誘導変数と同等です。ポストインクリメントとプレインクリメントの質問は、ここで数回回答されています。アーカイブを少し検索してみてください。

また、インクリメント操作は、標準のIOと比較してほんのわずかな時間しかかかりません。テストは、増分操作の速度ではなく、IOの速度を測定しています。

于 2010-08-02T07:17:00.947 に答える
3

古いGCC3.4.4はこれを行います:

最初のループ:

.L11:
        cmpl    $99, -8(%ebp)
        jg      .L12
        subl    $8, %esp
        pushl   $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        subl    $12, %esp
        pushl   $.LC0
        subl    $12, %esp
        pushl   -8(%ebp)
        pushl   $_ZSt4cout
.LCFI7:
        call    _ZNSolsEi
        addl    $20, %esp
        pushl   %eax
        call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        addl    $20, %esp
        pushl   %eax
.LCFI8:
        call    _ZNSolsEPFRSoS_E
        addl    $16, %esp
        leal    -8(%ebp), %eax
        incl    (%eax)
        jmp     .L11
.L12:

2番目のループ:

.L14:
        cmpl    $99, -12(%ebp)
        jg      .L15
        subl    $8, %esp
        pushl   $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        subl    $12, %esp
        pushl   $.LC0
        subl    $12, %esp
        pushl   -12(%ebp)
        pushl   $_ZSt4cout
.LCFI13:
        call    _ZNSolsEi
        addl    $20, %esp
        pushl   %eax
        call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        addl    $20, %esp
        pushl   %eax
.LCFI14:
        call    _ZNSolsEPFRSoS_E
        addl    $16, %esp
        leal    -12(%ebp), %eax
        incl    (%eax)
        jmp     .L14
.L15:

違いはありますか?:)(iとjがスタック-8(%ebp)と-12(%ebp)の異なる場所にあることに加えて)

于 2010-08-02T07:49:58.870 に答える
1

これは、統計的手法を使用して、どちらのループが高速であるかを判断する必要があることを意味します(そして、これらの手法が互いにほぼ同等であることを確立したことを願っています)。

ここに置いている負荷を超えて、CPUが何をしているかわかりません。

スケジュールされたタスクの開始、割り込みの処理、結果を歪めるあらゆる種類のことである可能性があります。

適切なサンプルを取得するには、100万回の実行を行い、外れ値を捨て、残りを平均化する必要があります。

その上、特にループ制御の実行に費やされる時間を浪費coutする可能性のある関数呼び出しを実行しているため、100回の反復はそれほど多くありません。

UNIXでチェックを実行するときは、まさにこの理由で経過時間を使用しません。システムとユーザーの時間は、経過時間に関係なく、特定のプロセスでCPUが使用されていた秒数を示します。

于 2010-08-02T07:14:29.610 に答える
1

++ iは、i ++と同じマシンコードになり、中途半端なコンパイラでは未使用の結果になります(ただし、intの場合はそうではない、派手な方法でオーバーロードされていない場合)。そして、そうでない場合でも(前世紀からかなり愚かなコンパイラーを掘り下げる必要があるでしょう)、違いは非常に小さいので、心配する必要はありません。さて、パフォーマンスのほんの少しを絞り出す必要がある場合もありますが、私たちの中で最も少ない人がこの状況に陥ります。そして、それでも、ループの本体には、はるかに多くの最適化の可能性があります(過度に単純化された例でも、I / Oはマシンワードをコピーするよりもはるかにコストがかかります)。

または一言で言えば:時期尚早の最適化はすべての悪の根源です。

于 2010-08-02T07:17:00.483 に答える
1

私が見るところ、ループの唯一の違いは、ループ変数の前後の増分です。プロセス時間の大部分は、coutに費やされます。増分は、比較すると無視できる時間になります。

于 2010-08-02T07:24:45.893 に答える
-1

++iはプリインクリメントです
i++はポストインクリメントです

詳細については、オペレーターを参照してください

于 2010-08-02T07:22:06.320 に答える