0

重複の可能性:
大幅に異なる出力 C++ モンテカルロ近似

私の 64 ビット ubuntu コンピューターでは、次のコードは期待どおりに機能し、両方のアルゴリズムで pi の近似値を返します。しかし、コードのデモを行うラボ マシン (32 ビット rhel 3 マシン) では、2 番目のアルゴリズムは常に 4 を返し、その理由がわかりません。任意の洞察をいただければ幸いです。

/*
 * RandomNumber.h
 *
 *  
 *      
 */

#ifndef RANDOMNUMBER_H_
#define RANDOMNUMBER_H_

class RandomNumber {
public:
RandomNumber() {
    x = time(NULL);
    m = pow(2, 31); //some constant value
    M = 65915 * 7915; //multiply of some simple numbers p and q
    method = 1;
}
RandomNumber(int seed) {
    x = ((seed > 0) ? seed : time(NULL));
    m = pow(2, 31); //some constant value
    method = 1; //method number
    M = 6543 * 7915; //multiply of some simple numbers p and q
}
void setSeed(long int seed) {
    x = seed; //set start value
}

void chooseMethod(int method) {
    this->method = ((method > 0 && method <= 2) ? method : 1); //choose one of two method
}

long int linearCongruential() { //first generator, that uses linear congruential method
    long int c = 0; // some constant
    long int a = 69069; //some constant
    x = (a * x + c) % m; //solution next value
    return x;
}

long int BBS() { //algorithm Blum - Blum - Shub
    x = (long int) (pow(x, 2)) % M;
    return x;
}
double nextPoint() { //return random number in range (-1;1)
    double point;
    if (method == 1) //use first method
        point = linearCongruential() / double(m);
    else
        point = BBS() / double(M);
    return point;
}
private:
long int x; //current value
long int m; // some range for first method
long int M; //some range for second method
int method; //method number
};

#endif /* RANDOMNUMBER_H_ */

そしてテストクラス:

#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <iomanip>
#include "RandomNumber.h"
using namespace std;

int main() {
cout.setf(ios::fixed);
cout.precision(6);
RandomNumber random;
srand((unsigned) time(NULL));
cout << "---------------------------------" << endl;
cout << "   Monte Carlo Pi Approximation" << endl;
cout << "---------------------------------" << endl;
cout << " Enter number of points: ";
long int k1;
cin >> k1;
cout << "Select generator number: ";
int method;
cin >> method;
random.chooseMethod(method);
cout << "---------------------------------" << endl;
long int k2 = 0;
double sumX = 0;
double sumY = 0;
for (long int i = 0; i < k1; i++) {
    double x = pow(-1, int(random.nextPoint() * 10) % 2)
            * random.nextPoint();
    double y = pow(-1, int(random.nextPoint() * 10) % 2)
            * random.nextPoint();
    sumX += x;
    sumY += y;
    if ((pow(x, 2) + pow(y, 2)) <= 1)
        k2++;

}
double pi = 4 * (double(k2) / k1);
cout << "M(X)  = " << setw(10) << sumX / k1 << endl; //mathematical expectation of x
cout << "M(Y)  = " << setw(10) << sumY / k1 << endl; //mathematical expectation of y
cout << endl << "Pi = " << pi << endl << endl; //approximate Pi

return 0;
}
4

3 に答える 3

1

問題は、 が をpow返し、doubleローエンドで精度が失われることです。演算子に変換するlong int%常に同じ結果が返されるため、RNG は定数 -60614748 を出力します。

x = time(0)                 1354284781
pow(x, 2)                  1.83409e+18   0x1.973fdc9dc7787p+60
(long int) pow(x, 2)       -2147483648    0x80000000
(long int) pow(x, 2) % M     -60614748

修正は、 内ですべての演算を実行する に変更x = (long int) (pow(x, 2)) % M;することです。符号付きオーバーフローは定義されていないため、これは厳密には正しくないことに注意してください。より正確に使用することです。x = x * x % Mlong intunsigned long

于 2012-11-30T14:18:45.033 に答える
0

longinへの切り捨てBBS()により、同じ「乱数」が生成されます。

PS。関数からの戻り値は、マシンの型powで表すには大きすぎる数値です。longこれへの変換を行うとlong、未定義の動作が発生します。未定義の動作の特定の効果の 1 つは、変換の結果が になる可能性があるため0x800000000x7fffffff同じ数字のシーケンスになってしまう可能性があります。

于 2012-11-30T14:04:17.007 に答える
0
x = time(0)                 1354284781
pow(x, 2)                  1.83409e+18   0x1.973fdc9dc7787p+60

32 ビットの int は 2^31-1 までの値を保持し、x^2 の値はそれよりも大きくなります。

于 2012-11-30T14:39:57.850 に答える