2012-11-30 51 views
0

可能重复:
Vastly different output C++ monte carlo approximation不同的输出与C++ PI近似

在我的64位的ubuntu计算机,下面的代码按预期方式工作,并返回一个接近的近似为用PI两种算法。然而,在实验室机器上,我必须演示代码,一个32位rhel 3机器,第二个算法总是返回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; 
} 
+0

通常,在32位体系结构中,“long”是32位,在64位体系结构中是64位。也许你遇到了这种情况? – Angew

+0

@JoachimPileborg它是相似的,但答案是错误的,我不再使用参数来设置值,并且问题仍然存在。 – kqualters

+0

然后请取消接受已接受的答案,然后编辑旧的问题。编辑这个问题会碰撞它,所以它不会在“噪音”中丢失。 –

回答

0

BBS()截断到long导致产生相同的 “随机” 数。

PS。 pow函数的返回值是一个数字,它太大而无法在您的机器的long类型中表示。在转换为long时,会导致未定义的行为。未定义行为的一个特定影响可能是转换为0x800000000x7fffffff的结果,因此您最终得到的序列号相同。

+0

@chilll你能详细解释一下吗? – kqualters

+0

从上面的示例 –

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 % M,内long int执行所有算术。请注意,这仍然严格地说是不正确的,因为有符号溢出未定义;更正确的是使用unsigned long

+0

有趣的是,这会将输出从4.000不断变化为3.99480左右, – kqualters

+0

任何事情都可能发生,因为@ecatmur自己指出,这仍会触发未定义的行为。 – chill

0
x = time(0)     1354284781 
pow(x, 2)     1.83409e+18 0x1.973fdc9dc7787p+60 

32位int保存的值高达2^31-1,x^2的值大于该值。