Монте-Карло Метод нахождения пи с помощью C - PullRequest
5 голосов
/ 13 марта 2019

Я написал функцию, которая принимает длинное длинное значение n и использует его в качестве числа проходящих итераций. Функция должна дать хорошую оценку числа пи, однако все значения для больших n стремятся к 3.000, а не к 3.1415, так что я не уверен, что происходит?

Есть что-то, что я сделал не так?

Это мой код:

double estimate_pi(long long n){
    double randomx, randomy, equation, pi;
    long long i, incircle = 0;

    for(i = 0; i < n; i++){
        randomx = (double)(rand() % (1+1-0) + 0);
        randomy = (double)(rand() % (1+1-0) + 0);

        equation = randomx * randomx + randomy * randomy;

        if(equation <= 1){
            incircle++;
        }
    }

    pi = (long double)4 * (long double)incircle / (long double)n;

    return pi;
}

в основной функции, чтобы вывести 10 значений числа пи:

int main(void){

    long long N;
    double pi_approx;
    int i;

    printf("Input a value of N: ");
    if(scanf("%ld", &N) != 1){
        printf("Error, input must be an integer!\n");
        exit(EXIT_SUCCESS);
    } 
    if(N < 1){
        printf("Error, the integer must be positive!\n");
        exit(EXIT_SUCCESS); 
    }

    srand(time(NULL));
    for(i = 0; i < 10; i++){
        pi_approx = estimate_pi(N);
        printf("%.10f\n", pi_approx);
    }
    return 0;
}

Ответы [ 4 ]

6 голосов
/ 13 марта 2019

Работает как надо.Проблема заключается в реализации.

Функция C rand() возвращает целое число в диапазоне от 0 до RAND_MAX.Ключевое слово: integer .

Затем вы вычисляете результат этого целого числа по модулю 2, которое может быть 0 или 1. Таким образом, у вас останется 4 возможных пункта: (0,0),(0,1), (1,0), (1,1).

Из этих 4 точек только 1 лежит вне круга радиуса 1: (1,1).То есть из 4 возможных точек 3 лежат в круге.

Этот код следует заменить на значения с плавающей точкой, а не на целые числа, чтобы вычислить соотношение точек внутри и снаружи круга.

5 голосов
/ 13 марта 2019

Вам нужно использовать рандомизацию с плавающей точкой или иным образом использовать круг с очень большим радиусом.

Поэтому вместо

    randomx = (double)(rand() % (1+1-0) + 0);
    randomy = (double)(rand() % (1+1-0) + 0);

вы используете

    randomx = rand();
    randomy = rand();

и вы считаете, попадает ли он в круг радиуса RAND_MAX

   #define RMAX ((double)RAND_MAX*(double)RAND_MAX)
   equation <= RMAX;

Вы делаете детали.Прочитайте man 3 rand, чтобы увидеть, что rand () возвращает целое число.

3 голосов
/ 13 марта 2019

Ваши переменные randomx и randomy ограничены значением integer , поскольку функции rand() возвращают целое число.

Смотрите вживую здесь .

Как следствие, каждая из двух ваших переменных будет либо 1, либо 0, поэтому ваша точка будет случайным образом равна одной из (0,0), (1,0), (0,1), (1,1), с шансом 3: 4 оказаться в круге. Отсюда твой результат 3.

Вы можете посмотреть Как сгенерировать случайное число с плавающей точкой в ​​C , если вам нужно случайное число от 0 до 1.

2 голосов
/ 13 марта 2019

Для вашего подхода к работе вам необходимо сгенерировать double значений, выведенных из равномерного распределения на интервале [0,1] (или примерно так). Вместо этого вы генерируете случайные целые числа, взятые из двухэлементного набора {0, 1}, и конвертируете их в тип double. Это не дает ничего такого, как дистрибутив, необходимый для ваших целей.

...