Skip to content

Instantly share code, notes, and snippets.

@terasakisatoshi
Last active December 30, 2023 12:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save terasakisatoshi/0565ec8e6031cabdd2512989f0a8ae49 to your computer and use it in GitHub Desktop.
Save terasakisatoshi/0565ec8e6031cabdd2512989f0a8ae49 to your computer and use it in GitHub Desktop.
1.4 倍遅いは嘘な件
# Linear congruential generators (LCGs)
# Parameters are provided by Park and Miller
# See https://c-faq.com/lib/rand.html
function LCGs(seed::Integer)
a = 48271
m = 2147483647
q, r = divrem(m, a)
hi, lo = divrem(seed, q)
test = a * lo - r * hi
seed = ifelse(test > 0, test, test + m)
return seed, Float64(seed) / m
end
function main()
seed = 20231226
num_points = 1000000000
num_inside = 0
for i in eachindex(Base.OneTo(num_points))
seed, x = LCGs(seed)
seed, y = LCGs(seed)
r2 = x^2 + y^2
num_inside += (r2 < 1.0)
end
println("pi=", 4.0 * num_inside / num_points)
end
if abspath(PROGRAM_FILE) == @__FILE__
@time main()
end
from numba import jit
import time
# Linear congruential generators (LCGs)
# Parameters are provided by Park and Miller
# See https://c-faq.com/lib/rand.html
@jit(nopython=True)
def LCGs(seed):
a = 48271
m = 2147483647
q, r = divmod(m, a)
hi, lo = divmod(seed, q)
test = a * lo - r * hi
if test > 0:
seed = test
else:
seed = test + m
rand_num = seed / m
return seed, rand_num
@jit(nopython=True)
def main():
seed = 20231226
num_points = 1000000000
num_inside = 0
for i in range(num_points):
seed, x = LCGs(seed)
seed, y = LCGs(seed)
r2 = x**2 + y**2
num_inside += r2 < 1.0
print("pi =", 4.0 * float(num_inside) / num_points)
if __name__ == "__main__":
for _ in range(3):
s = time.perf_counter()
main()
e = time.perf_counter()
print(f"elapsed {e - s}")
@terasakisatoshi
Copy link
Author

terasakisatoshi commented Dec 29, 2023

参考にした記事

https://kamemori.com/research/fortran/speed_montecarlo_lcgs_ja.html

$ gfortran -O3 mc.f90
$ time ./a.out
 pi=   3.1415463479999999
./a.out  7.74s user 0.02s system 99% cpu 7.786 total

確かに Fortran は速いのですが

Python

Numba ぐらいは試しましょう.

docker run --rm -it -v $PWD:/work -w /work python:3.11.7 bash
root@8d4708baf43d:/work# pip3 install numba >/dev/null 2>&1
root@8d4708baf43d:/work# python mc.py
pi = 3.141546348
elapsed 11.547261276999961
pi = 3.141546348
elapsed 11.642988100000025
pi = 3.141546348
elapsed 11.440575886999966

Julia

せめて divrem ぐらいの存在は常識にしましょう.

https://docs.julialang.org/en/v1/base/math/#Base.divrem

書き方を統一したいという固執によって柔軟さに欠ける特定のプログラミング言語の実行速度を目立たせるような印象操作はかなり悪意を感じます.

また,使用している Julia が 1.7.3 らしいのですが,コミュニテイではすでにメンテナンスされていないバージョンのものです.
https://julialang.org/blog/2019/08/release-process/ の存在すら知らない素人でしょう.Julia のダウンロードページ https://julialang.org/downloads/ からリンクが付けられているので気づいて欲しいです.

julia> versioninfo()
Julia Version 1.10.0
Commit 3120989f39b (2023-12-25 18:01 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: macOS (x86_64-apple-darwin22.4.0)
  CPU: 16 × Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, skylake)
  Threads: 1 on 16 virtual cores
Environment:
  JULIA_EDITOR = subl
  JULIA_PROJECT = @.
  JULIA_PKG_USE_CLI_GIT = true
julia mc.jl
pi=3.141546348
  9.639376 seconds (11.28 k allocations: 879.625 KiB, 0.24% compilation time)
pi=3.141546348
  9.365997 seconds (10 allocations: 576 bytes)
pi=3.141546348
  9.267306 seconds (11 allocations: 880 bytes)

@terasakisatoshi
Copy link
Author

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment