Juliaの速さを体感する2 (参考 : Python(Numba)とFortranの速さも体感する)

# はじめに
[前回の記事](https://qiita.com/ceptree/items/b5cfca180e85e61c42a8)の最後でお知らせしていたPython(Numba)とFortranとの比較になります。またCythonについては、前回の記事のコメント欄で[@SatoshiTerasaki](https://qiita.com/ceptree/items/b5cfca180e85e61c42a8#comment-e81252566d0a7a2ffadc)さんにやって頂いたので参考にして下さい。

# 注意
私のプログラミング歴は5年程ですが、Pythonは１年、Juliaは先週から、Fortranは片手間程度というレベルです。プログラミング言語間の実行時間を、正確に検証出来るレベルではないですので、参考程度にして下さい。また間違い等あればコメント頂けると助かります。

# 結果(参考)
N = 100000000(1億)

|                |Time [s]|
|----------------|--------|
|Python(TopLevel)|44.55   |
|Python(Function)|35.52   |
|Python(Numba)   | 0.64   |
|Julia(TopLevel) |29.84   |
|Julia(Function) | 0.33   |
|Julia(inbounds) | 0.17   |
|Fortran         | 0.32   |
|Fortran(-O3)    | 0.14   |

N = 1000000000(10億)
(3回実行した中央値)

|                |Time [s]|
|----------------|--------|
|Python(Numba)   | 6.64   |
|Julia(Function) | 4.13   |
|Julia(inbounds) | 2.45   |
|Fortran         | 4.03   |
|Fortran(-O3)    | 2.34   |

# 環境
PC : MacBook Pro (Retina, 15-inch, Early 2013)
OS : macOS (x86_64-apple-darwin14.5.0)
CPU : Intel Core i7-3740QM @ 2.7 GHz
Memory : 16 GB 1600 MHz DDR3

Julia : 0.6.2

Python : 3.6.3 
numpy : 1.13.3

gfortran : GNU Fortran (Homebrew GCC 7.1.0) 7.1.0

# Python(TopLevel)
前回の記事で使用したコードです。

```py3:ODE.py
import numpy as np 
import time
# 点数
N = 100000000

# 刻み 
h = 0.00000004

# 初期化
y = np.zeros(N)

# 初期値
y[0] = 1

# 数値計算
start = time.time()
for n in range(N-1):
    y[n+1] = (1-h)*y[n]
elapsed_time = time.time() - start
print("Elapsed Time(Python): %.2f [s]" % elapsed_time)
```  

# Python(Function)
Python(TopLevel)を関数化したコードです。

```py3:ODE_Function.py
import numpy as np 
import time

def main():
    # 点数
    N = 100000000

    # 刻み 
    h = 0.00000004

    # 初期化
    y = np.zeros(N)

    # 初期値
    y[0] = 1

    # 数値計算
    start = time.time()
    for n in range(N-1):
        y[n+1] = (1-h)*y[n]
    elapsed_time = time.time() - start
    print("Elapsed Time(Python): %.2f [s]" % elapsed_time)
main()
```
# Python(Numba)
Python(Function)に[@jit](https://numba.pydata.org/)デコレータをつけただけです。
下記の記事を参考に引数化して型指定も試しましたが、間違いがあるのかあまり変わらなかったです。
[Python高速化　Numba入門　その2](http://yutori-datascience.hatenablog.com/entry/2014/12/10/123157)

```py3:ODE_Function_numba.py
import numpy as np 
import time
from numba import jit

@jit
def main():
    # 点数
    N = 100000000

    # 刻み 
    h = 0.00000004

    # 初期化
    y = np.zeros(N)

    # 初期値
    y[0] = 1

    # 数値計算
    start = time.time()
    for n in range(N-1):
        y[n+1] = (1-h)*y[n]
    elapsed_time = time.time() - start
    print("Elapsed Time(Python): %.2f [s]" % elapsed_time)
main()
```
# Julia(TopLevel)
前回の記事で使用したコードです。

```julia:ODE.jl
# 点数
N = 100000000

# 刻み 
h = 0.00000004

# 初期化
y = zeros(N)

# 初期値
y[1] = 1

# 数値計算
@time for n = 1:N-1
    y[n+1] = (1-h)y[n]
end
```
# Julia(Function)
前回の記事で使用したコードです。
(修正 : 2018/1/9 18:11)
[@inbounds](https://docs.julialang.org/en/latest/devdocs/boundscheck/)がついていたので修正、コメント欄で[@nakano_tomofumi](https://qiita.com/ceptree/items/0eabac1f2a2ca74a4ece#comment-65b9c3ef2c59c5ff7369)さんに指摘して頂きました。

```julia:ODE_Function.jl
function main()
    # 点数
    N = 100000000
    
    # 刻み 
    h = 0.00000004
    
    # 初期化
    y = zeros(N)
    
    # 初期値
    y[1] = 1
    
    # 数値計算
    @time for n = 1:N-1
        y[n+1] = (1-h)y[n]
    end
end
main()
```
# Julia(Inbounds)
Julia(Function)に[@inbounds](https://docs.julialang.org/en/latest/devdocs/boundscheck/)マクロを追加したコードです。

```julia:ODE_inbounds.jl
function main()
    # 点数
    N = 100000000
    
    # 刻み 
    h = 0.00000004
    
    # 初期化
    y = zeros(N)
    
    # 初期値
    y[1] = 1
    
    # 数値計算
    @time @inbounds for n = 1:N-1
        y[n+1] = (1-h)y[n]
    end
end
main()
```
# Fortran
Fortranは色々試行錯誤した結果下記のコードで行いました。

```fortran:ODE.f90
program ODE
call main()
contains
    subroutine main()
        implicit none
        integer, parameter :: n = 100000000
        real(8) :: y(n)
        real(8) h, elapsed_time
        integer i
        integer ti, tf, tr
    
        ! 刻み 
        h = 0.00000004d0
        
        ! 初期化
        y = 0

        ! 初期値
        y(1) = 1.0d0

        ! 数値計算
        call system_clock(ti)
        do i = 1,n-1
            y(i+1) = (1 - h) * y(i)
        end do
        call system_clock(tf,tr)
        elapsed_time = (tf-ti) / dble(tr)
        print "('Elapsed Time(Fortran):',f8.4,'[s]')", elapsed_time
    end subroutine
end program ODE
```