Julia 科學計算應用算例 (1)

原文鏈接:https://lectures.quantecon.org/jl/getting_started_julia/julia_by_example.html

導入模塊

using Pkg

using BenchmarkTools

問題

Problem 1

不使用 Julia 自帶的 factorial(n) 函數, 用 for 編寫一個計算 n!n! (n 階乘, n!=n×(n1)××2×1n! = n \times (n−1)\times \cdots \times 2 \times 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)

速度對比

ns<μs<ms<sns < \mu 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 函數嵌套結構的情況下.

Problem2

問題2: 二項分佈隨機變量 Y 表示了 n 次二元實驗中成功的次數, 而每次實驗成功的概率爲 p. 用數學形式描述爲, YBin(n,p)Y \sim Bin(n, p).

請使用 base 庫的 rand 函數編寫產生二項分佈隨機變量.

Hint: 如果 UU 服從 (0, 1) 的均勻分佈, 且 p(0,1)p \in (0, 1), 那麼 U&lt;pU \lt p 意味着概率 p 條件下爲真 (成功) 的情況

描述: 可以參考 Distributions 庫的 Binomial函數. Binomial 第一個參數爲 n, 表示二元實驗的次數; 第二個參數爲 p, 表示實驗成功的概率; 函數返回一個 0-n 的整數 k, 且可從 rand 函數中實現"抽樣", "抽樣次數"爲 n_samples, 以下爲二項分佈公式:

P(X=k)=(nk)pk(1p)nk, 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.

示例

#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<p ? 1.0 : 0.0
    end
    return count
end
binomial2()
1
function binomial3(n::Int=1, p::Float64=.5)::Int
    probs = rand(n)
    res = sum(prob<p ? 1 : 0 for prob in probs)
  return res
end
binomial3()
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

Problem3

問題3: 用蒙特卡羅方法近似計算 π\pi . 只使用 rand() 函數生產隨機數, 按照以下的提示:

  1. 如果 UU 是單位平方 (0,1)2(0, 1)^2 區域的二元均勻隨機變量, 那麼 UU 落於 (0,1)2(0, 1)^2 區域子集 BB 的概率等於 BB 的面積.
  2. 如果 U_1,...,U_nU\_1, ..., U\_nUU 一樣是獨立同分布的, 那麼當 nn 逐漸增大時, 落入 BB 的部分收斂於落於 BB 的概率.
  3. 圓形的面積等於 π×radius2\pi \times radius^2.

hint: 由於 π\pi 可以依據圓形公式計算得到( π=circle arearadius2\pi = \frac{circle\ area}{radius^2} ), 而圓形面積近似可以看成均勻分佈於子集 B={x,y:x2+y2&lt;1}B = \{x, y: x^2+y^2&lt;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

Problem 4

僅使用 rand() 函數產生隨機數, 編寫程序, 實現以下隨機事件:

  1. 不偏不倚地投擲 10 次硬幣

  2. 如果連續 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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章