Skip to content

Commit ff6cbf1

Browse files
committed
Add implementation and note about Monte Carlo Simulation
1 parent 45be6f7 commit ff6cbf1

File tree

3 files changed

+111
-0
lines changed

3 files changed

+111
-0
lines changed

README.org

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,60 @@
3131
#+begin_src shell
3232
raco test chapter1/exercise1-10.scm
3333
#+end_src
34+
* 笔记
35+
** chapter3
36+
*** 蒙特卡罗模拟步骤来计算 π
37+
3.1 赋值与局部变量, 155 页
38+
#+begin_quote
39+
举例来说,6/π^2 是随机选取的两个整数之间没有公因子(也就是说,它们的最大公因子是1)的概率。我们可以利用这一事实做出π的近似值。
40+
#+end_quote
41+
42+
完全读不懂这段话,没理解是怎么可以算出π的近似值的。
43+
44+
查阅完资料都知道:
45+
46+
随机选取两个正整数,它们互质(即最大公约数GCD为1)的概率是 $\frac{6}{\pi^2}$ , 所谓的 互质指两个数没有公共因子(如8和15互质,但8和12不互质,因为公约数为4)。
47+
48+
而这一结论是源自数论中关于 **互质数的密度** 的研究,与黎曼ζ函数相关(难怪我看不懂了)。
49+
50+
而用蒙特卡罗模拟步骤来计算 ${\pi}$:
51+
52+
随机实验:重复多次随机选取两个整数,检查它们的GCD是否为1。
53+
54+
例如:
55+
- (3, 5) → GCD=1(计数+1)
56+
- (4, 6) → GCD=2(不计数)
57+
58+
统计概率:
59+
60+
若总实验次数为 N,其中 k 次GCD=1,则互质概率的估计值为 $\frac{k}{N}$
61+
62+
关联π:
63+
64+
根据数论结论 $\frac{k}{N} \approx \frac{6}{\pi^2}$,解得 $\pi \approx \sqrt{\frac{6N}{k}}$。
65+
66+
当直接计算π困难时,可通过概率实验间接逼近。
67+
68+
这里利用了数论中的概率规律,将π与随机事件联系起来。(对于高数也只是低分飘过的我来说,不知道数论的东西也太正常了)
69+
70+
#+begin_src racket
71+
#lang racket
72+
73+
(define (estimate-pi trials)
74+
(sqrt (/ 6 (monte-carlo trials cesaro-test))))
75+
76+
(define (cesaro-test)
77+
(= (gcd (rand) (rand)) 1))
78+
79+
(define (monte-carlo trials experiment)
80+
(define (iter trials-remaining trial-passed)
81+
(cond ((= trials-remaining 0)
82+
(/ trials-passed trials))
83+
((experiment)
84+
(iter (- trials-remaining 1) (+ trials-passed 1)))
85+
(else
86+
(iter (- trials-remaining 1) trials-passed))))
87+
(iter trials 0))
88+
#+end_src
89+
90+
这里的蒙特卡罗实现真的是优雅

chapter3/monte-calro.rkt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#lang racket
2+
(require "rand.rkt")
3+
(define (estimate-pi trials)
4+
(sqrt (/ 6 (monte-carlo trials cesaro-test))))
5+
6+
(define (cesaro-test)
7+
(= (gcd (rand) (rand)) 1))
8+
9+
(define (monte-carlo trials experiment)
10+
(define (iter trials-remaining trial-passed)
11+
(cond ((= trials-remaining 0)
12+
(/ trial-passed trials))
13+
((experiment)
14+
(iter (- trials-remaining 1) (+ trial-passed 1)))
15+
(else
16+
(iter (- trials-remaining 1) trial-passed))))
17+
(iter trials 0))
18+
19+
(module+ test
20+
(require rackunit)
21+
(require rackunit/text-ui)
22+
(define (estimate-pi-close? trials tolerance)
23+
(let ((pi-estimate (estimate-pi trials)))
24+
(< (abs (- pi-estimate 3.14159)) tolerance)))
25+
26+
(define module-test
27+
(test-suite
28+
"Tests for estimate-pi"
29+
(check-true (estimate-pi-close? 10000 0.1))
30+
(check-true (estimate-pi-close? 100000 0.01))
31+
(check-true (estimate-pi-close? 10000000 0.001))
32+
(check-exn exn:fail? (lambda () (estimate-pi 0)) "Should throw exception for 0 trials")
33+
))
34+
(run-tests module-test))

chapter3/rand.rkt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#lang racket
2+
3+
;; 线性同余生成器(Linear Congruential Generator, LCG)
4+
;; latex 公式: X_{n+1} = (a \cdot X_n + c) \pmod{m}
5+
;; https://en.wikipedia.org/wiki/Linear_congruential_generator
6+
;; 使用 C++11 minstd_rand 实现的参数
7+
(define (rand-update x)
8+
(let ((a 48271)
9+
(c 0)
10+
(m (- (expt 2 31) 1)))
11+
(modulo (+ (* a x) c) m)))
12+
13+
(define random-init 42)
14+
(define rand
15+
(let ((x random-init))
16+
(lambda ()
17+
(set! x (rand-update x))
18+
x)))
19+
20+
(provide rand)

0 commit comments

Comments
 (0)