3

私はプログラミング言語の比較を含むプロジェクトを行っています。アッカーマン関数を計算しています。Java、Python、Rubyをテストしたところ、10〜30ミリ秒の応答がありました。しかし、C++は125ミリ秒かかるようです。これは正常ですか、それとも問題gettimeofday()ですか? Gettimeofday()時間内です。h。

(仮想)Ubuntu NattyNarwhal32ビットでテストしています。私は処理能力が不足していません(クアッドコア2.13 GHz Intel Xeon)。

私のコードはここにあります:

#include <iostream>
#include <sys/time.h>
using namespace std;
int a(int m,int n) {
    if (m == 0) {
    return n + 1;
    } else if (m > 0 and n == 0) {
    return a(m-1,1);
    } else if (m > 0 and n > 0) {
    return a(m-1,a(m,n-1));
    }
}

int main() {
    timeval tim;
    gettimeofday(&tim,NULL);
    double t1 = tim.tv_usec;
    int v = a(3,4);           
    gettimeofday(&tim,NULL);
    double t2 = tim.tv_usec;
    cout << v << endl << t2-t1;
    return 0;
}       
4

1 に答える 1

11

返されるデータの解像度について話していると仮定すると、POSIX 仕様は次のようにgettimeofday述べています。

システム クロックの分解能は規定されていません。

これは、システムが短い期間を追跡する能力が大きく異なる可能性があるという事実によるものです。ISO規格のclock()機能でも、このような注意点があります。

それを呼び出すのにかかる時間について話している場合、標準はそれらの線に沿ったパフォーマンスについて保証しません。実装は、時間を与える前に完全に自由に125分待つことができますが、そのような実装が市場で多くの成功を収めるとは思えません:-)


限られた解像度の例として、次のコードを入力してシス​​テムで確認しました。

#include <stdio.h>
#include <sys/time.h>

#define NUMBER 30

int main (void) {
    struct timeval tv[NUMBER];
    int count[NUMBER], i, diff;

    gettimeofday (&tv[0], NULL);

    for (i = 1; i < NUMBER; i++) {
        gettimeofday (&tv[i], NULL);
        count[i] = 1;
        while ((tv[i].tv_sec == tv[i-1].tv_sec) &&
            (tv[i].tv_usec == tv[i-1].tv_usec))
        {
            count[i]++;
            gettimeofday (&tv[i], NULL);
        }
    }

    printf ("%2d: secs = %d, usecs = %6d\n", 0, tv[0].tv_sec, tv[0].tv_usec);
    for (i = 1; i < NUMBER; i++) {
        diff = (tv[i].tv_sec - tv[i-1].tv_sec) * 1000000;
        diff += tv[i].tv_usec - tv[i-1].tv_usec;

        printf ("%2d: secs = %d, usecs = %6d, count = %5d, diff = %d\n",
            i, tv[i].tv_sec, tv[i].tv_usec, count[i], diff);
    }

    return 0;
}

コードは基本的に、基になる時間の変化を記録しgettimeofday()、時間が実際に変化するまでにかかった呼び出しの数を数えます。これはかなり強力なマシン上にあるため、処理能力が不足しているわけではありません (カウントは、5,800 マーク前後の各時間クォンタムを呼び出すことができた頻度を示します。そのクォンタムでいつ開始したgettimeofday()かわからないため、最初のクォンタムは無視されます)測定値)。

出力は次のとおりです。

 0: secs = 1318554836, usecs = 990820
 1: secs = 1318554836, usecs = 991820, count =  5129, diff = 1000
 2: secs = 1318554836, usecs = 992820, count =  5807, diff = 1000
 3: secs = 1318554836, usecs = 993820, count =  5901, diff = 1000
 4: secs = 1318554836, usecs = 994820, count =  5916, diff = 1000
 5: secs = 1318554836, usecs = 995820, count =  5925, diff = 1000
 6: secs = 1318554836, usecs = 996820, count =  5814, diff = 1000
 7: secs = 1318554836, usecs = 997820, count =  5814, diff = 1000
 8: secs = 1318554836, usecs = 998820, count =  5819, diff = 1000
 9: secs = 1318554836, usecs = 999820, count =  5901, diff = 1000
10: secs = 1318554837, usecs =    820, count =  5815, diff = 1000
11: secs = 1318554837, usecs =   1820, count =  5866, diff = 1000
12: secs = 1318554837, usecs =   2820, count =  5849, diff = 1000
13: secs = 1318554837, usecs =   3820, count =  5857, diff = 1000
14: secs = 1318554837, usecs =   4820, count =  5867, diff = 1000
15: secs = 1318554837, usecs =   5820, count =  5852, diff = 1000
16: secs = 1318554837, usecs =   6820, count =  5865, diff = 1000
17: secs = 1318554837, usecs =   7820, count =  5867, diff = 1000
18: secs = 1318554837, usecs =   8820, count =  5885, diff = 1000
19: secs = 1318554837, usecs =   9820, count =  5864, diff = 1000
20: secs = 1318554837, usecs =  10820, count =  5918, diff = 1000
21: secs = 1318554837, usecs =  11820, count =  5869, diff = 1000
22: secs = 1318554837, usecs =  12820, count =  5866, diff = 1000
23: secs = 1318554837, usecs =  13820, count =  5875, diff = 1000
24: secs = 1318554837, usecs =  14820, count =  5925, diff = 1000
25: secs = 1318554837, usecs =  15820, count =  5870, diff = 1000
26: secs = 1318554837, usecs =  16820, count =  5877, diff = 1000
27: secs = 1318554837, usecs =  17820, count =  5868, diff = 1000
28: secs = 1318554837, usecs =  18820, count =  5874, diff = 1000
29: secs = 1318554837, usecs =  19820, count =  5862, diff = 1000

解像度が 1,000 マイクロ秒以下に制限されているように見えることを示しています。もちろん、システムはそれとは異なる場合があります。要するに、実装や環境に依存するということです。


この種の制限を回避する 1 つの方法は、何かを 1 回実行するのではなく、何回か実行してからN、経過時間を で割ることNです。

たとえば、関数を呼び出して、タイマーが 125 ミリ秒かかったと言っているとします。これは少し高いと思われます。次に、ループで1000回呼び出して、1000回全体にかかった時間を測定することをお勧めします。

それが 125 秒であることが判明した場合、はい、おそらく遅いです。ただし、27 秒しかかからない場合は、タイマーの解像度が一見大きな時間の原因であることを示しています。これは、反復ごとに 27 ミリ秒に相当するため、他の結果から見たものと同等です。

これを考慮してコードを変更すると、次のようになります。

int main() {
    const int count = 1000;
    timeval tim;

    gettimeofday(&tim, NULL);
    double t1 = 1.0e6 * tim.tv_sec + tim.tv_usec;

    int v;
    for (int i = 0; i < count; ++i)
        v = a(3, 4);           

    gettimeofday(&tim, NULL);
    double t2 = 1.0e6 * tim.tv_sec + tim.tv_usec;

    cout << v << '\n' << ((t2 - t1) / count) << '\n';

    return 0;
}
于 2011-10-13T22:06:58.480 に答える