Calculating PI using Monte Carlo method gives imprecise answer

匿名 (未验证) 提交于 2019-12-03 01:39:01

问题:

I am trying to calculate PI using Monte Carlo method. My code gives the result 3.000 no matter how big MAXLEN is. After debugging it many times, I couldn't get what I'm doing wrong.

#include <stdio.h> #include <stdlib.h>  #define sqr2(x) ((x)*(x)) #define frand() ((double) rand() / (RAND_MAX)) #define MAXLEN 1000   int circumscribed(int radius){     float xcoord = frand();     float ycoord = frand();      float coord = sqr2(xcoord) + sqr2(ycoord);      if(coord <= radius)         return 1;     return -1;       }  int main() {     int i;     int circles = 0, rect = 0;;     for(i = 0; i < MAXLEN; i++)     {         if(circumscribed(1) > 0)   // if(circumscribed(1)) shoul be enough but it doesn't work. Very odd in my opinion.             circles++;         rect++;  //this is equal to MAXLEN, I just used it for debugging     }      float PI = 4 * circles / rect;     printf("PI is %2.4f: \n", PI);     return 0;    }

回答1:

Since circles and rect are both int, the result of 4 * circles / rect will be an int. Use floating point numbers instead.

float PI = 4.0 * (float)circles / rect;


回答2:

This expression is all integers:

4 * circles / rect;

Therefore, the result is an integer (3 in this case).

(as a similar example: 10 / 3 == 3, but 10.0 / 3.0 == 3.333333)

Try instead:

4.0 * circles / rect;

Just changing the (int)4 to a (double)4 by referring to it as 4.0 or even 4. should be enough.


Other Misc Observations

This line has an extra semi-colon:

int circles = 0, rect = 0;;

Your function circumscribed uses float. Your variable PI is also a float.
If you use double, you'll get greater precision.



回答3:

You are doing integer Math here. circles and rect are both int in your code, so the result of 4 * circles / rect is also an int. Use floating point numbers instead. Use double for better precision.

double PI = 4.0 * (double)circles / rect;


回答4:

You are performing integer math here:

float PI = 4 * circles / rect;

Changing 4 to 4.0 is sufficient to fix the problem:

float PI = 4.0 * circles / rect;

Working version here



回答5:

float PI = 4 * circles / rect;

This performs integer math to the right of the = thus limiting your result to 1 significant digit.

Instead:

double PI = 4.0 * circles / rect;  // Best

Details

float PI = 4.0 * (float)circles / rect;  // OK

Recommend avoid using float. Use double instead to avoid limiting this Monte Carlo to about 7 digits. As circles becomes large, it may not convert exactly into the same float value. Instead it converts into a rounded float. This happens at about circles > 8,000,000 on many machines. By rounding, you are unnecessarily limiting the attainable precision. Using a double, this rounding does not occur until circles is about 9e15.

float PI = 4.0 * (double) circles / rect; // Better

The explicit cast of (double) circles may be useful to the reader, but code will perform the same way with or without it. 4.0 is a double and will cause a double promotion to circles before the multiplicity occurs, even without the cast.

double PI = 4.0 * circles / rect; // Better

As the 4.0 * ... result is a double, best precision is retained by saving to a double. Using float PI causes the multiplication/division, which was done in double precision to reduce its precision on saving to a float.

float or double PI = ... printf("PI is %2.4f: \n", PI);

Note: Here, a PI converted to a double is passed to printf() regardless if PI was declared float or double. So might as access the precision in PI by declaring it double.


Note: int, float and double range and precision are machine dependent. The above reflects a common implementation.



回答6:

CHECK OUT THIS CODE:

#include <stdlib.h> #include <stdio.h> #include <math.h> #include <string.h> #define SEED 35791246  int main(int argc, char** argv) {    int niter=0;    double x,y;    int i,count=0; /* # of points in the 1st quadrant of unit circle */    double z;    double pi;     printf("Enter the number of iterations used to estimate pi: ");    scanf("%d",&niter);     /* initialize random numbers */    srand(SEED);    count=0;    for ( i=0; i<niter; i++) {       x = (double)rand()/RAND_MAX;       y = (double)rand()/RAND_MAX;       z = x*x+y*y;       if (z<=1) count++;       }    pi=(double)count/niter*4;    printf("# of trials= %d , estimate of pi is %g \n",niter,pi);  return 0; }


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!