3

我正在尝试使用蒙特卡洛方法计算 PI。无论 MAXLEN 有多大,我的代码都会给出 3.000 的结果。经过多次调试,我无法理解我做错了什么。

#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;   
}
4

6 回答 6

5

由于circlesrect都是int,结果4 * circles / rect将是int。请改用浮点数。

float PI = 4.0 * (float)circles / rect;
于 2013-07-15T16:59:02.743 回答
2

这个表达式都是整数:

4 * circles / rect;

因此,结果是一个整数(在这种情况下为 3)。

(作为一个类似的例子: 10 / 3 == 3,但是10.0 / 3.0 == 3.333333

请尝试:

4.0 * circles / rect;

只需将其更改(int)4为 a(double)4通过将其称为4.0甚至4.应该就足够了。


其他杂项观察

此行有一个额外的分号:

int circles = 0, rect = 0;;

您的函数circumscribed使用float. 你的变量PI也是一个float.
如果使用double,您将获得更高的精度。

于 2013-07-15T16:59:02.877 回答
2

你在integer Math这里做。circles并且rectint在您的代码中,因此 的结果4 * circles / rect也是int. 请改用浮点数。使用double以获得更好的精度。

double PI = 4.0 * (double)circles / rect;
于 2013-07-15T17:12:22.930 回答
1

你在这里执行整数数学:

float PI = 4 * circles / rect;

更改44.0足以解决问题:

float PI = 4.0 * circles / rect;

工作版本在这里

于 2013-07-15T17:03:00.687 回答
1
float PI = 4 * circles / rect;

这将在右侧执行整数数学运算,=从而将您的结果限制为 1 个有效数字。

反而:

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

细节

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

建议避免使用float。改为使用double以避免将此 Monte Carlo 限制为大约 7 位数。随着circles变大,它可能不会完全转换为相同的float值。相反,它会转换为圆角float. 在许多机器上,这发生在大约circles> 8,000,000 处。通过四舍五入,您不必要地限制了可达到的精度。使用 a double,直到circles大约 9e15 时才会发生这种舍入。

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

的显式(double) circles转换可能对读者有用,但无论有没有它,代码都会以相同的方式执行。4.0 是一个double并且会在多重性发生之前导致double提升circles,即使没有演员表。

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

由于4.0 * ...结果是双精度,因此通过保存为双精度来保持最佳精度。使用float PI导致乘法/除法,这是以双精度完成的,以降低其保存到浮点数的精度。

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

注意:这里,无论是否声明PI了PI或. 因此,可以通过将其声明为双精度来访问 PI 中的精度。printf()floatdouble


注意:int、float 和 double 范围和精度取决于机器。以上反映了一种常见的实现方式。

于 2013-07-15T19:39:36.687 回答
0

查看此代码:

#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;
}
于 2017-08-02T07:46:28.443 回答