この記事の結果は間違っていましたm(_ _)m
正しい結果は、”PythonとCでモンテカルロ <訂正版>“を参照してください。
(それでも、この記事を見てくれると嬉しいな…。)
最近、自分はPythonに燃えています。そこで、練習に以前雑誌でちらっと見たことのあるモンテカルロ法を用いて円周率を求めるってのを実装してみました。モンテカルロ法を用いた円周率の求め方については、以前の記事を参考にしてください!
Pythonはインタプリタ型の言語だから遅いって事をよく聞きます。そこで、C言語でも同じようなプログラムを作成して比較してみました。
プログラム
プログラムの流れ
- ランダムに[0.0 < x < 1.0), [0.0 < y < 1.0)の範囲で乱数を発生させる。
- そのxとyの座標が半径1の円に入っているかどうかを判断する。
- 入っていれば、カウントを増加。入っていなければ、なにもしない。
- 1-3の操作を指定回数繰り返す
- 円に入った点の数 / 点の数の合計 = 円に入った割合 を計算する。
- 円に入った割合 * 4 = 円周率となる。
と、まぁこんな感じです。この時の指定回数を増やせば増やすほど、円周率の精度があがります。
(と思います…。)
Python
# 円周率を求めるPythonプログラム
import random
import math
LOOP_MAX = 10000000
# 中央からの距離が1以内であるか
def chk_pos(x,y,r):
dist_r = math.sqrt( math.pow(x,2) + math.pow(y,2))
if dist_r < r:
ret = True
else:
ret = False
return ret
cnt = 0
i = 0
while i < LOOP_MAX:
x = random.random()
y = random.random()
if chk_pos(x,y,1):
cnt += 1
i += 1
print("loop:%d Pi:%f" % ( LOOP_MAX, cnt / LOOP_MAX * 4))
C
/* 円周率を求めるC言語プログラム */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#define LOOP_MAX 10000000
int chk_pos( double, double, int);
int main(void){
srand((unsigned)time(NULL));
double x,y;
int i, cnt=0;
for(i=0; i<LOOP_MAX; i++){
x = rand() % 1000;
y = rand() % 1000;
x /= 1000;
y /= 1000;
cnt += chk_pos( x, y, 1);
}
printf("loop:%d pi:%f\n", LOOP_MAX, (double)cnt / LOOP_MAX * 4);
return 0;
}
// 中央からの距離が1以内であるか
int chk_pos( double x, double y, int r){
int ret;
double dist_r;
dist_r = sqrt(pow(x,2) + pow(y,2));
if (dist_r < r) ret = 1;
else ret = 0;
return ret;
}
Pythonは、randomモジュールをインポートして、random.random()を使うと、ランダムに生成された値が、[0.0 < X < 1.0)の範囲で生成されるので、そのまま利用しました。
C言語では、#include<stdlib>のrand()を用いると、乱数が[0 < X < 2147483647]で生成されます(Maxは環境依存>)。そこで、その数値を0.0〜1.0の値に変換する際に 1000で割った余り/1000という形にしました。
(このへんで、処理速度に差が出てくるきがしなくもない…。)
条件
PCスペック
OS : Mac OS X 10.10.3 (Yosemite)
CPU : Intel Core i5(1.3GHz)
Mem : 4GB
プログラムについて
ランダムで発生させる点の数 : 10000000 (一千万)
C言語のコンパイル
gcc -o pi pi.c -O3 -lm
C言語では、最適化オプション-O3で指定しました。
Pythonの実行
python --version
Pythonはよくしらないので普通に実行…。
Python 3.4.1を使用しました。
結果
比較には、timeコマンドを使用しました。timeはざっくりその後に実行されるコマンドの実行時間が調べられるコマンドです。
# C言語の実行ファイル time ./pi loop:10000000 pi:3.145705 ./pi 0.26s user 0.00s system 95% cpu 0.275 total #Pythonの実行 time python pi.py loop:10000000 Pi:3.142078 python pi.py 14.11s user 0.10s system 99% cpu 14.302 total
実行時間
Python : 14.11[s]
C言語 : 0.26[s]
…
……
………
…………
(゜□゜*)マジか
C言語がPyhonの約1/54の時間で終了!C言語が速いのか、Pythonが遅いのかわからないですけど、すごい差…。
例えて言うのならば、Pythonで2ヶ月かかる処理が、C言語だと1日で終わるぐらいの計算です。
これが、>>インタプリタ型の言語<< 自分の中でPythonは最強みたいなイメージあったんですけど、やはり適材適所で言語を選んでいかなきゃいけないみたいですね。
しかし、ソースコードの行数は、Pythonが25行/C言語が42行となっています。自分が書いたプログラムなので、ちょっとフェアな戦いじゃないですけど…それでも、Pythonの方が短いコードになっている!
ちょっと、乱数について調べてたら、乱数の精度によって生成にかかる時間がずいぶん変わるようで…もしかして、これら関連で処理速度がかわってるのかな…?
最後に、ループの回数を10倍(一億回)にして実行してみました。
# C言語の実行ファイル time ./pi loop:100000000 pi:3.145632 ./pi 2.45s user 0.00s system 99% cpu 2.464 total #Pythonの実行 time python pi.py loop:100000000 Pi:3.141701 python pi.py 159.83s user 1.68s system 94% cpu 2:51.18 total
…3分近く。。。マジか。
# プログラミング楽しい #
✌(‘ω’✌ )三✌(‘ω’)✌三( ✌’ω’)✌
訂正(4/27) :
- PythonとC言語の実行時間が逆になってましたm(_ _)m
Python :0.2614.11[s] C言語 :14.110.26[s] - C言語の乱数の作り方の説明が間違ってました
1000で割った余り×1000
1000で割った余り/1000