モンテカルロ法(円周率の近似、時間計測)

■Python, Javascriptでの試し。
モンテカルロ法で円周率の近似をしているけど、ランダムの数値の発生と円の内外の判定部分の演算とグラフへの描画に対してそれぞれ時間計測を行う。あと、javascriptで同様のコードを試す。

演算部分が下のとおり。
Python(t1-t0 の時間差を繰り返し足すことで総時間を求める)

# ===== モンテカルロ演算時間計測 =====#############################
    t0 = time.perf_counter()

    for _ in range(STEP):
        x = random.uniform(-1, 1)
        y = random.uniform(-1, 1)
        total_count += 1

        if x * x + y * y <= 1.0:
            inside_count += 1

    t1 = time.perf_counter()
#########################################################

Javascript

// ===== モンテカルロ演算時間 =====/////////////////////////////////////
    const t0 = performance.now();

    for (let i = 0; i < STEP && totalCount < N_MAX; i++) {
      const x = Math.random() * 2 - 1;
      const y = Math.random() * 2 - 1;
      totalCount++;
      if (x * x + y * y <= 1) insideCount++;
    }

    const t1 = performance.now();
///////////////////////////////////////////////////////////////////////////

描画部分が下のとおり。
Python

# ===== グラフ更新時間計測 =====###################################################
    t2 = time.perf_counter()

    n_history.append(total_count)
    pi_history.append(pi_est)

    line_est.set_data(n_history, pi_history)

    info_text.set_text(
        f"N: {total_count}\n"
        f"π estimate: {pi_est:.10f}\n"
        f"MC step time: {mc_time:.4f} s\n"
        f"Plot time (total): {plot_time_total:.4f} s"
    )

    #    plt.pause(0)
    fig.canvas.draw()
    fig.canvas.flush_events()

    t3 = time.perf_counter()
#########################################################

Javascript(Reactでないもの)

// ===== 描画時間 =====    //////////////////////
    const t2 = performance.now();

    nHistory.push(totalCount);
    piHistory.push(piEst);

    drawAxes();
    drawLine();

    const t3 = performance.now();
////////////////////////////////////////////////////

Javascript(React。nHistory, piHistoryはuseStateを使ったもの)

////////////////////////////////////////////////////
        const t2 = performance.now();

        // 🔴 描画更新を React に渡す
        setPlotData(prev => ({
            nHistory: [...prev.nHistory, totalCount],
            piHistory: [...prev.piHistory, piEst]
        }));

        const t3 = performance.now();

///////////////////////////////////////////////////

結果が次。
1憶2000万の点を生成して、4万回に1度結果をグラフへ更新。上の秒数が演算部分、下の秒数が描画部分。

NoPythonJavascript (nonReact)Javascript (React)
196.65 s
220.25 s
8.76 s
0.85 s
6.68 s
0.07 s
2169.52 s
395.39 s
6.06 s
0.73 s
5.49 s
0.04 s
3124.56 s
273.23 s
6.37 s
0.75 s
5.36 s
0.04 s
480.61 s
179.30 s
5.30 s
0.66 s
3.70 s
0.06 s
580.34 s
184.25 s
5.27 s
0.67 s
6.26 s
0.04 s

5回の実行は多少パソコンの状況が違うけど、明らかにjavascriptの方が演算が速く終わっており、またReactを使った方が描画が速くなっている。なお、Reactを使っていないもの(canvas、左下)と使っているもの(右下)で表示のスタイルはやや違う。

演算部分は、単純にランダムで数値を作り、条件分けを行っているだけなので、コード内容自体に差があるわけではないと思う。Python内でもランダム生成で使うライブラリで差は出てくるかもしれない。Javascriptと比べて思いのほか演算に時間がかかっているので、この辺りの効率化とか見てみたい。

Javascript内の演算部分はそれぞれで同じような時間となっているが、全く同じコードのためもっともな結果。描画部分は見ている部分が同じ役割か検証する必要はあるけど、Reactを使った方が速いのは望ましいもの。コードの測定ポイントを増やして、Javascript内の比較とかも見てみたい。