#なぜ円周率を求めるのか
特に理由はなく、ゼミでとりあえず何かつくってみよう的なノリでした。ちなみにElixir歴一週間にも満たないひよっこが書いております。
ちなみにモンテカルロ法使うらしいです、僕もいまいちよくわからないので、気になる人は自分でググるなりしてください。
ちなみに僕は解けなかったのでHaskellのめっちゃできる先輩に解説してもらった後、自分で何も見ずにやってみました。ほぼコードは同じですが、、、
#とりあえず書いてみる
defmodult Pi do
def pi n do
Stream.repeatedly(fn -> [:rand.uniform(), :rand.uniform()] end)
|> Enum.take(n)
|> Enum.map(fn x -> dist(x) end)
|> Enum.map(fn x -> x < 1 end)
|> mond
end
def dist [x, y] do
x * x + y * y
end
def mond x do
t = x
|> Enum.filter(fn a -> a == true end)
|> Enum.count()
l = Enum.count(x)
(t / l) * 4
end
end
#どうやっているか
defmodult Pi do
def pi n do
Stream.repeatedly(fn -> [:rand.uniform(), :rand.uniform()] end)
|> Enum.take(n)
|> Enum.map(fn x -> dist(x) end)
|> Enum.map(fn x -> x < 1 end)
|> mond
end
まず、Stream.repeatedly(fn -> [:rand.uniform(), :rand.uniform()] end)
で1以下の乱数の無限リストを作ります(座標です)。次に|> Enum.take(n)
で最初のからn個とって、|> Enum.map(fn x -> dist(x) end)
dist関数を呼び出し、|> Enum.map(fn x -> x < 1 end)|> mond
返ってきた値をmond関数に渡す。
###dive関数とmond関数
def dist [x, y] do
x * x + y * y
end
def mond x do
t = x
|> Enum.filter(fn a -> a == true end)
|> Enum.count()
l = Enum.count(x)
(t / l) * 4
end
dive関数は距離を、mond関数は、$π=4t/l$でπが求まるそうなので計算していきます。ここら辺はモンテカルロ法 円周率計算 などでググってください。すみません。
#結果
$ iex pi.exs
Erlang/OTP 22 [erts-10.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]
Interactive Elixir (1.9.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Pi.pi(10)
3.2
iex(2)> Pi.pi(100)
3.24
iex(3)> Pi.pi(1000)
3.092
iex(4)> Pi.pi(10000)
3.1536
iex(5)> Pi.pi(100000)
3.14328
iex(6)> Pi.pi(1000000)
3.144968
iex(7)> Pi.pi(10000000)
3.142738
できた!ただ、100000000
までいくとsegmentation fault (core dumped)
が起こった。
#最後に
このコードをもっと良くするために間違っているところや、もっとこうした方がいいなどElixirの強い人アドバイスください。よろしくお願いします。
僕は関数型プログラミング言語は初めてでしたが、オブジェクト指向より自分に合っているのではと思うぐらい楽しいです、ここまで見てくだっさてありがとうございました。