C 언어로 몬테 카를로 시뮬레이션을 활용한 확률 계산

CBeginner
지금 연습하기

소개

이 실험에서는 C 프로그래밍에서 몬테 카를로 시뮬레이션을 사용하여 확률을 추정하는 방법을 탐구합니다. 동전 던지기와 같은 간단한 무작위 실험을 정의한 후 여러 번의 시행을 통해 성공적인 결과의 수를 계산합니다. 마지막으로, 총 시행 횟수로 성공 횟수를 나누어 추정 확률을 계산합니다. 이 실험은 데이터 분석 및 의사 결정에 필수적인 C 를 사용한 확률 및 조합론의 기본 개념에 대한 실질적인 소개를 제공합니다.

무작위 실험 정의

이 단계에서는 C 에서 몬테 카를로 시뮬레이션을 사용하여 무작위 실험을 정의하는 방법을 살펴봅니다. 무작위 실험은 확률 기술을 사용하여 시뮬레이션할 수 있는 불확실한 결과를 갖는 과정입니다.

무작위 실험 이해

간단한 무작위 실험인 동전 던지기 시뮬레이션을 보여주는 간단한 C 프로그램을 만들어 봅시다.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define NUM_TRIALS 1000

int main() {
    // 난수 생성기를 시드합니다.
    srand(time(NULL));

    // 앞면 횟수
    int heads_count = 0;

    // 동전 던지기 시뮬레이션
    for (int i = 0; i < NUM_TRIALS; i++) {
        // 0 또는 1 의 난수를 생성합니다.
        int flip = rand() % 2;

        // 앞면 횟수를 셉니다.
        if (flip == 0) {
            heads_count++;
        }
    }

    // 앞면의 확률을 계산합니다.
    double probability = (double)heads_count / NUM_TRIALS;

    printf("동전 던지기 실험:\n");
    printf("총 시행 횟수: %d\n", NUM_TRIALS);
    printf("앞면 횟수: %d\n", heads_count);
    printf("앞면의 추정 확률: %.2f\n", probability);

    return 0;
}

예시 출력:

동전 던지기 실험:
총 시행 횟수: 1000
앞면 횟수: 502
앞면의 추정 확률: 0.50

주요 개념 설명

  1. 난수 생성:

    • srand(time(NULL))는 난수 생성기를 시드합니다.
    • rand() % 2는 동일한 확률로 0 또는 1 을 생성합니다.
  2. 실험 설계:

    • 동전 던지기를 무작위 실험으로 정의합니다.
    • 여러 번의 시행 (이 경우 1000 번) 을 수행합니다.
    • 성공적인 결과 (앞면) 의 수를 셉니다.
  3. 확률 추정:

    • 확률 = (성공적인 결과의 수) / (총 시행 횟수)
    • 이 경우 앞면의 확률은 0.5 에 가까울 것으로 예상됩니다.

프로그램 컴파일 및 실행

## 소스 파일 생성
nano ~/project/coin_flip_experiment.c

## 프로그램 컴파일
gcc ~/project/coin_flip_experiment.c -o ~/project/coin_flip_experiment

## 실험 실행
~/project/coin_flip_experiment

예시 컴파일 및 실행 출력:

## 컴파일
gcc ~/project/coin_flip_experiment.c -o ~/project/coin_flip_experiment

## 실행
~/project/coin_flip_experiment
동전 던지기 실험:
총 시행 횟수: 1000
앞면 횟수: 502
앞면의 추정 확률: 0.50

여러 번의 무작위 시행 실행 및 성공 횟수 계산

이 단계에서는 여러 번의 무작위 시행을 실행하고 성공적인 결과를 정확하게 계산하여 몬테 카를로 시뮬레이션을 확장합니다. 이를 통해 더 복잡한 확률 실험인 난수 생성을 사용한 π(파이) 추정을 보여줍니다.

π 추정을 위한 몬테 카를로 방법

사분원이 포함된 정사각형 내에서 난수 점을 생성하여 기하학적 방법을 사용하여 π를 추정합니다.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#define NUM_TRIALS 100000

int main() {
    // 난수 생성기 시드
    srand(time(NULL));

    // 총 점과 원 내부 점 카운터
    int total_points = 0;
    int points_inside_circle = 0;

    // 여러 번의 시행 실행
    for (int i = 0; i < NUM_TRIALS; i++) {
        // 0 과 1 사이의 난수 x 및 y 좌표 생성
        double x = (double)rand() / RAND_MAX;
        double y = (double)rand() / RAND_MAX;

        // 점이 사분원 내부에 있는지 확인
        if (sqrt(x*x + y*y) <= 1.0) {
            points_inside_circle++;
        }
        total_points++;
    }

    // π 추정
    double pi_estimate = 4.0 * points_inside_circle / total_points;

    printf("π 추정 실험:\n");
    printf("총 점: %d\n", total_points);
    printf("원 내부 점: %d\n", points_inside_circle);
    printf("추정된 π: %.6f\n", pi_estimate);
    printf("실제 π:    %.6f\n", M_PI);

    return 0;
}

실험 컴파일 및 실행

## 소스 파일 생성
nano ~/project/pi_estimation.c

## 프로그램 컴파일(math 라이브러리 링크 주의)
gcc ~/project/pi_estimation.c -o ~/project/pi_estimation -lm

## 실험 실행
~/project/pi_estimation

예시 출력:

π 추정 실험:
총 점: 100000
원 내부 점: 78540
추정된 π: 3.141600
실제 π:    3.141593

주요 개념 설명

  1. 여러 번의 시행:

    • 많은 난수 시행 (10 만 번) 을 실행합니다.
    • 각 시행은 1x1 정사각형 내의 난수 점을 생성합니다.
  2. 성공 횟수 계산:

    • 총 점과 사분원 내부 점을 추적합니다.
    • 성공은 원 내부에 점이 떨어지는 것으로 정의됩니다.
  3. 확률 추정:

    • 확률 = (성공적인 점) / (총 점)
    • 사분원 방법으로 인해 π를 추정하기 위해 4 를 곱합니다.

중요한 기술

  • (double)rand() / RAND_MAX는 0 과 1 사이의 난수 소수를 생성합니다.
  • sqrt(x*x + y*y)는 원점으로부터의 거리를 계산합니다.
  • 많은 시행은 추정 정확도를 향상시킵니다.

확률 = 성공/시행 추정

이 마지막 단계에서는 실제 시나리오에서 성공적인 결과의 수와 총 시행 횟수의 비율을 분석하여 확률을 계산하는 방법을 보여줍니다.

주사위 굴림 확률 실험

두 개의 주사위를 굴리고 특정 합 (예: 7 의 합) 을 얻는 확률을 계산하는 시뮬레이션을 수행합니다.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define NUM_TRIALS 100000
#define TARGET_SUM 7

int roll_die() {
    return rand() % 6 + 1;
}

int main() {
    // 난수 생성기 시드
    srand(time(NULL));

    // 총 굴림 횟수와 성공적인 굴림 횟수 카운터
    int total_rolls = 0;
    int successful_rolls = 0;

    // 여러 번의 시행 실행
    for (int i = 0; i < NUM_TRIALS; i++) {
        // 두 개의 주사위 굴림
        int die1 = roll_die();
        int die2 = roll_die();

        // 합이 목표값과 일치하는지 확인
        if (die1 + die2 == TARGET_SUM) {
            successful_rolls++;
        }
        total_rolls++;
    }

    // 확률 계산
    double probability = (double)successful_rolls / total_rolls;

    printf("주사위 굴림 확률 실험:\n");
    printf("목표 합: %d\n", TARGET_SUM);
    printf("총 굴림 횟수: %d\n", total_rolls);
    printf("성공적인 굴림 횟수: %d\n", successful_rolls);
    printf("추정 확률: %.4f\n", probability);

    // 비교를 위한 이론적 확률
    printf("이론적 확률: %.4f\n", 1.0/6);

    return 0;
}

실험 컴파일 및 실행

## 소스 파일 생성
nano ~/project/dice_probability.c

## 프로그램 컴파일
gcc ~/project/dice_probability.c -o ~/project/dice_probability

## 실험 실행
~/project/dice_probability

예시 출력:

주사위 굴림 확률 실험:
목표 합: 7
총 굴림 횟수: 100000
성공적인 굴림 횟수: 16644
추정 확률: 0.1664
이론적 확률: 0.1667

주요 개념 설명

  1. 확률 계산:

    • 확률 = (성공적인 결과의 수) / (총 시행 횟수)
    • 이 경우: 성공적인 굴림 횟수 / 총 굴림 횟수
  2. 몬테 카를로 시뮬레이션:

    • 많은 시행 (10 만 번) 은 정확한 추정을 제공합니다.
    • 시뮬레이션된 확률은 이론적 확률과 매우 가깝습니다.
  3. 무작위성 및 정확도:

    • srand(time(NULL))는 다른 난수 시퀀스를 보장합니다.
    • 더 많은 시행은 추정 정확도를 높입니다.

확률 해석

  • 추정 확률 (0.1664) 은 이론적 확률 (1/6 ≈ 0.1667) 과 매우 가깝습니다.
  • 몬테 카를로 방법이 확률을 추정하는 방법을 보여줍니다.

요약

이 실험에서 C 언어를 사용하여 몬테 카를로 시뮬레이션을 이용하여 무작위 실험을 정의하는 방법을 배웠습니다. 주요 개념을 보여주기 위해 간단한 동전 던지기 시뮬레이션을 만들었습니다. 먼저, 난수 생성기를 시드하고 동전 던지기를 시뮬레이션하여 성공적인 결과 (앞면) 의 수를 계산했습니다. 그런 다음, 성공적인 결과의 수를 총 시행 횟수로 나누어 앞면이 나올 확률을 추정했습니다. 출력 결과는 공정한 동전 던지기의 예상값인 0.5 에 가까운 추정 확률을 보여주었습니다.