6

モンテカルロ法で pi をカウントする 2 つの実装があります: スレッドありとスレッドなしです。スレッドを使用しない実装は問題なく機能しますが、スレッドを使用するメソッドには精度とパフォーマンスに問題があります。コードは次のとおりです。

スレッドなし:

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


int main()
{
    srand(time(NULL));

    unsigned long N = 0, Nin = 0;
    float x,y;

    while(N < 2E+9)
    {
        x = rand()/((float)RAND_MAX + 1.0)*10.0 - 5.0;
        y = rand()/((float)RAND_MAX + 1.0)*10.0 - 5.0;

        if(x*x + y*y < 25.0) Nin += 1;
        N++;
    }
    long double pi = 4.0 * (long double)Nin / (long double)N;

    printf("\tPi1: %.20Lf\n\t%lu %lu\n", pi, Nin, N);

    return 0;
}

そしてスレッドで:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>


typedef struct 
{
    unsigned long Nin;
    unsigned long N;
} nums;


void pi_counter(nums* a)
{
    float x,y;
    unsigned int N = 0, Nin = 0;

    while(N < 1E+9)
    {
        x = rand()/((float)RAND_MAX + 1.0)*10.0 - 5.0;
        y = rand()/((float)RAND_MAX + 1.0)*10.0 - 5.0;


        if(x*x + y*y < 25.0) Nin++;
        N++;
    }

    a -> Nin += Nin;
    a -> N   += N;
}


int main()
{
    pthread_t thread1, thread2, thread3;
    nums a;

    srand(time(NULL));

    pthread_create( &thread1, NULL, pi_counter, &a );
    pthread_create( &thread2, NULL, pi_counter, &a );

    pthread_join( thread1, NULL );
    pthread_join( thread2, NULL ); 

    long double pi = 4.0 * (long double)a.Nin / (long double)a.N;


    printf("\tPi2: %.20Lf\n\t%lu %lu\n", pi, a.Nin, a.N);

    return 0;
}

結果:

$ time ./pi2
    Pi2: 3.14147154999999999995
    1570735775 2000000000

real    1m1.927s
user    1m23.624s
sys 0m0.139s



$ time ./pi
    Pi1: 3.14158868600000000006
    1570794343 2000000000

real    0m49.956s
user    0m49.887s
sys 0m0.022s

私の間違いはどこですか?

4

3 に答える 3

11

randスレッドセーフではありません。複数のスレッドで同時に使用すると、未定義の動作が発生します。呼び出し中にミューテックスを取得して保持する関数でラップするか、代わりに使用する適切なPRNGをrand使用または(さらに良い方法で)作成することができます。rand_r

于 2011-06-05T23:03:19.177 に答える
2

他の回答に加えて、次のコードで

a -> Nin += Nin;
a -> N   += N;

a は共有されていますが、ミューテックスによって保護されていないため、追加が間違っています。この問題に遭遇していないかもしれませんが、最終的には直面するでしょう。

于 2011-06-06T00:24:38.033 に答える
1

他の結果が得られますが、アルゴリズムrand()問題ありません(確率的であり、何も保証されていないため)。なぜ同じシーケンスですか?シードランドインスタンスはプロセスごとであるため、スレッドはプロセスですが軽量です。

于 2011-06-05T22:56:36.733 に答える