using Pkg
using BenchmarkTools
不使用 Julia 自带的 factorial(n)
函数, 用 for
编写一个计算 n ! n! n! (n 阶乘, n ! = n × ( n − 1 ) × ⋯ × 2 × 1 n! = n \times (n−1)\times \cdots \times 2 \times 1 n!=n×(n−1)×⋯×2×1) 的函数, 函数名称为 factorial2
factorial(3)
的计算结果为 6
factorial(3)
6
function factorial2(n::Int64)::Int64
res = 1
for i in 1:n
res = res*i
end
return res
end
factorial2 (generic function with 1 method)
# 不指定类型
function factorial3(n)
k = 1
for i in 1:n
k *= i # or k = k * i
end
return k
end
factorial3 (generic function with 1 method)
n s < μ s < m s < s ns < \mu s < ms <s ns<μs<ms<s
纳秒 < 毫秒 < 微妙 < 秒
n = 10
@benchmark factorial(n)
BenchmarkTools.Trial:
memory estimate: 16 bytes
allocs estimate: 1
--------------
minimum time: 19.658 ns (0.00% GC)
median time: 26.680 ns (0.00% GC)
mean time: 32.284 ns (7.24% GC)
maximum time: 3.939 μs (99.08% GC)
--------------
samples: 10000
evals/sample: 997
@benchmark factorial2(n)
BenchmarkTools.Trial:
memory estimate: 0 bytes
allocs estimate: 0
--------------
minimum time: 6.399 ns (0.00% GC)
median time: 7.700 ns (0.00% GC)
mean time: 9.307 ns (0.00% GC)
maximum time: 577.694 ns (0.00% GC)
--------------
samples: 10000
evals/sample: 1000
@benchmark factorial3(n)
BenchmarkTools.Trial:
memory estimate: 16 bytes
allocs estimate: 1
--------------
minimum time: 22.946 ns (0.00% GC)
median time: 30.461 ns (0.00% GC)
mean time: 36.722 ns (7.05% GC)
maximum time: 4.007 μs (98.62% GC)
--------------
samples: 10000
evals/sample: 998
从上面的速度测试来看, factorial2 和 factorial3 相比说明, 指定参数类型的函数比不指定参数类型的函数快; factorial 和 factorial2 相比说明规范的手写算法在某些情况下可能会比 Julia 自带的函数相比还要快, 这在 python 中是不常见的, 尤其是在使用 for
函数嵌套结构的情况下.
问题2: 二项分布随机变量 Y 表示了 n 次二元实验中成功的次数, 而每次实验成功的概率为 p. 用数学形式描述为, Y ∼ B i n ( n , p ) Y \sim Bin(n, p) Y∼Bin(n,p).
请使用 base 库的 rand
函数编写产生二项分布随机变量.
Hint: 如果 U U U 服从 (0, 1) 的均匀分布, 且 p ∈ ( 0 , 1 ) p \in (0, 1) p∈(0,1), 那么 U < p U \lt p U<p 意味着概率 p 条件下为真 (成功) 的情况
描述: 可以参考 Distributions 库的 Binomial
函数. Binomial
第一个参数为 n, 表示二元实验的次数; 第二个参数为 p, 表示实验成功的概率; 函数返回一个 0-n 的整数 k, 且可从 rand
函数中实现"抽样", "抽样次数"为 n_samples, 以下为二项分布公式:
P ( X = k ) = ( n k ) p k ( 1 − p ) n − k , for k = 0 , 1 , 2 , … , n . P(X = k) = {n \choose k}p^k(1-p)^{n-k}, \quad \text{ for } k = 0,1,2, \ldots, n. P(X=k)=(kn)pk(1−p)n−k, for k=0,1,2,…,n.
#Pkg.add("Distributions")
using Distributions
Binomial()
Binomial{Float64}(n=1, p=0.5)
n_samples = 10
rand(Binomial(), n_samples)
10-element Array{Int64,1}:
0
0
1
0
1
1
1
0
1
0
n = 4
p = 0.6
n_samples = 10
rd = rand(Binomial(n, p), n_samples)
ave = mean(rd)/n # 期望值
0.625
mean(rd)/n ≈ sum(rd)/n_samples/n
true
function binomial2(n::Int=1, p::Float64=.5)::Int
probs = rand(n)
count = 0.0
for prob in probs
count += prob
1
function binomial3(n::Int=1, p::Float64=.5)::Int
probs = rand(n)
res = sum(prob
1
function binomial1(n::Int=1, p::Float64=.5)::Int
count = 0
U = rand(n)
for i in eachindex(U)
if U[i] < p
count += 1 # or count = count + 1
end
end
return count
end
binomial1()
0
function binomial4(n::Int=1, p::Float64=.5)::Int
count = 0
U = rand(n)
for i in eachindex(U)
if U[i] < p
count += 1 # or count = count + 1
end
end
return count
end
binomial4()
1
n = 1000
p = 0.3
0.3
@benchmark binomial1(n, p)
BenchmarkTools.Trial:
memory estimate: 7.94 KiB
allocs estimate: 1
--------------
minimum time: 1.933 μs (0.00% GC)
median time: 2.772 μs (0.00% GC)
mean time: 4.237 μs (13.71% GC)
maximum time: 247.409 μs (96.89% GC)
--------------
samples: 10000
evals/sample: 9
@benchmark binomial2(n, p)
BenchmarkTools.Trial:
memory estimate: 7.94 KiB
allocs estimate: 1
--------------
minimum time: 2.300 μs (0.00% GC)
median time: 3.622 μs (0.00% GC)
mean time: 5.550 μs (20.27% GC)
maximum time: 539.228 μs (97.61% GC)
--------------
samples: 10000
evals/sample: 9
@benchmark binomial3(n, p)
BenchmarkTools.Trial:
memory estimate: 7.97 KiB
allocs estimate: 2
--------------
minimum time: 1.370 μs (0.00% GC)
median time: 1.920 μs (0.00% GC)
mean time: 2.990 μs (22.08% GC)
maximum time: 344.017 μs (96.31% GC)
--------------
samples: 10000
evals/sample: 10
@benchmark binomial4(n, p)
BenchmarkTools.Trial:
memory estimate: 7.94 KiB
allocs estimate: 1
--------------
minimum time: 1.956 μs (0.00% GC)
median time: 2.856 μs (0.00% GC)
mean time: 4.441 μs (14.11% GC)
maximum time: 292.842 μs (97.66% GC)
--------------
samples: 10000
evals/sample: 9
@benchmark rand(Binomial(n, p), 1)
BenchmarkTools.Trial:
memory estimate: 163 bytes
allocs estimate: 4
--------------
minimum time: 231.040 ns (0.00% GC)
median time: 335.251 ns (0.00% GC)
mean time: 379.145 ns (9.18% GC)
maximum time: 14.801 μs (96.91% GC)
--------------
samples: 10000
evals/sample: 451
问题3: 用蒙特卡罗方法近似计算 π \pi π . 只使用 rand()
函数生产随机数, 按照以下的提示:
hint: 由于 π \pi π 可以依据圆形公式计算得到( π = c i r c l e a r e a r a d i u s 2 \pi = \frac{circle\ area}{radius^2} π=radius2circle area ), 而圆形面积近似可以看成均匀分布于子集 B = { x , y : x 2 + y 2 < 1 } B = \{x, y: x^2+y^2<1\} B={x,y:x2+y2<1} 的概率. 进一步考虑圆形大小与单位平方区域, 即可得到 π \pi π.
n = 10E3
n = convert(Int, 10e3)
10000
function area(n::Int=1000)::Float64
x = rand(n)
y = rand(n)
count = 0
for (i, j) in zip(x, y)
if i^2+j^2<1
count += 1
end
end
s = 4count/n
return s
end
area()
3.152
function area2(n::Int=1000)::Float64
count = 0
for i in 1:n
i, j = rand(2)
if i^2+j^2<1
count += 1
end
end
s = 4count/n
return s
end
area2(n)
3.1348
n = convert(Int, 10e6)
10000000
@benchmark area(n)
BenchmarkTools.Trial:
memory estimate: 152.59 MiB
allocs estimate: 4
--------------
minimum time: 246.195 ms (62.99% GC)
median time: 252.388 ms (63.23% GC)
mean time: 254.003 ms (63.54% GC)
maximum time: 289.401 ms (67.12% GC)
--------------
samples: 20
evals/sample: 1
@benchmark area2(n)
BenchmarkTools.Trial:
memory estimate: 915.53 MiB
allocs estimate: 10000000
--------------
minimum time: 716.644 ms (16.27% GC)
median time: 729.055 ms (16.73% GC)
mean time: 729.189 ms (16.56% GC)
maximum time: 746.121 ms (16.73% GC)
--------------
samples: 7
evals/sample: 1
仅使用 rand()
函数产生随机数, 编写程序, 实现以下随机事件:
不偏不倚地投掷 10 次硬币
如果连续 3 次头朝上事件在此序列中出现一次或多次, 则付给 1 美元, 否则不付钱
"""
- `n::Int=10`: 扔 n 次硬币
- `p::Int=0.5`: 不偏不倚地扔
"""
function toss(n::Int=10, p::Float64=0.5)::Int
count = 0
payoff = 0
for i in 1:n
count = rand()>p ? count+1 : 0
if count==3
payoff += 1
count = 0
end
end
return payoff
end
toss()
1
"""
记录投掷硬币的过程
"""
function tossProcess(n::Int=10, p::Float64=0.5)::Tuple{Int64, Array{Int64,1}}
count = 0
payoff = 0
seq = Vector{Int}(undef, n)
for i in eachindex(seq)
count, seq[i] = rand()>p ? (count+1, 1) : (0, 0)
if count==3
payoff += 1
count = 0
end
end
return payoff, seq
end
toss3 (generic function with 3 methods)
tossProcess()
(1, [0, 0, 1, 1, 1, 0, 0, 1, 0, 0])
"""
重复试验函数
"""
function expriments(N::Int=100, n::Int=10)
trials = zeros(Int, N)
for i in eachindex(trials)
trials[i] = toss(n)
end
return trials
end
N, n = 100000000, 10
mean(expriments(N, n))
expriments (generic function with 3 methods)
N, n = 100000000, 10 # 进行 1亿次试验, 每次试验扔 10次硬币
@benchmark expriments(N, n)
BenchmarkTools.Trial:
memory estimate: 30.55 GiB
allocs estimate: 200000002
--------------
minimum time: 21.970 s (6.41% GC)
median time: 21.970 s (6.41% GC)
mean time: 21.970 s (6.41% GC)
maximum time: 21.970 s (6.41% GC)
--------------
samples: 1
evals/sample: 1
@benchmark toss()
BenchmarkTools.Trial:
memory estimate: 320 bytes
allocs estimate: 2
--------------
minimum time: 127.126 ns (0.00% GC)
median time: 180.920 ns (0.00% GC)
mean time: 218.137 ns (10.08% GC)
maximum time: 82.621 μs (99.61% GC)
--------------
samples: 10000
evals/sample: 870
@benchmark tossProcess()
BenchmarkTools.Trial:
memory estimate: 192 bytes
allocs estimate: 2
--------------
minimum time: 110.834 ns (0.00% GC)
median time: 152.979 ns (0.00% GC)
mean time: 183.500 ns (10.42% GC)
maximum time: 76.656 μs (99.72% GC)
--------------
samples: 10000
evals/sample: 923