[解決済み] C、Clojure、Python、Ruby、Scalaなどのベンチマークを解釈する [終了しました]。
質問
免責事項
私は、人工的なベンチマークが邪道であることを知っています。彼らは非常に特定の狭い状況に対してのみ結果を示すことができます。私はいくつかの愚かなベンチのために、1つの言語が他よりも優れていると仮定しません。しかし、なぜこれほどまでに結果が違うのでしょうか。一番下にある私の質問を参照してください。
数学ベンチマークの説明
ベンチマークは、6つずつ異なる素数の組を見つける簡単な数学の計算です。
セクシー素数
)
例えば、100以下のセクシーな素数は以下のようになる。
(5 11) (7 13) (11 17) (13 19) (17 23) (23 29) (31 37) (37 43) (41 47) (47 53) (53 59) (61 67) (67 73) (73 79) (83 89) (97 103)
結果一覧
表中:計算時間(秒 実行中: Factor 以外は VirtualBox で実行 (Debian unstable amd64 ゲスト, Windows 7 x64 ホスト) CPUは AMD A4-3305M
Sexy primes up to: 10k 20k 30k 100k
Bash 58.00 200.00 [*1] [*1]
C 0.20 0.65 1.42 15.00
Clojure1.4 4.12 8.32 16.00 137.93
Clojure1.4 (optimized) 0.95 1.82 2.30 16.00
Factor n/a n/a 15.00 180.00
Python2.7 1.49 5.20 11.00 119
Ruby1.8 5.10 18.32 40.48 377.00
Ruby1.9.3 1.36 5.73 10.48 106.00
Scala2.9.2 0.93 1.41 2.73 20.84
Scala2.9.2 (optimized) 0.32 0.79 1.46 12.01
[1] - どれくらい時間がかかるのか、想像するのが怖いです。
コード一覧
C:
int isprime(int x) {
int i;
for (i = 2; i < x; ++i)
if (x%i == 0) return 0;
return 1;
}
void findprimes(int m) {
int i;
for ( i = 11; i < m; ++i)
if (isprime(i) && isprime(i-6))
printf("%d %d\n", i-6, i);
}
main() {
findprimes(10*1000);
}
ルビーです。
def is_prime?(n)
(2...n).all?{|m| n%m != 0 }
end
def sexy_primes(x)
(9..x).map do |i|
[i-6, i]
end.select do |j|
j.all?{|j| is_prime? j}
end
end
a = Time.now
p sexy_primes(10*1000)
b = Time.now
puts "#{(b-a)*1000} mils"
Scalaです。
def isPrime(n: Int) =
(2 until n) forall { n % _ != 0 }
def sexyPrimes(n: Int) =
(11 to n) map { i => List(i-6, i) } filter { _ forall(isPrime(_)) }
val a = System.currentTimeMillis()
println(sexyPrimes(100*1000))
val b = System.currentTimeMillis()
println((b-a).toString + " mils")
Scalaの最適化
isPrime
(を最適化します(Clojureの最適化と同じ考え方です)。
import scala.annotation.tailrec
@tailrec // Not required, but will warn if optimization doesn't work
def isPrime(n: Int, i: Int = 2): Boolean =
if (i == n) true
else if (n % i != 0) isPrime(n, i + 1)
else false
Clojureです。
(defn is-prime? [n]
(every? #(> (mod n %) 0)
(range 2 n)))
(defn sexy-primes [m]
(for [x (range 11 (inc m))
:let [z (list (- x 6) x)]
:when (every? #(is-prime? %) z)]
z))
(let [a (System/currentTimeMillis)]
(println (sexy-primes (* 10 1000)))
(let [b (System/currentTimeMillis)]
(println (- b a) "mils")))
Clojureの最適化
is-prime?
:
(defn ^:static is-prime? [^long n]
(loop [i (long 2)]
(if (= (rem n i) 0)
false
(if (>= (inc i) n) true (recur (inc i))))))
Python
import time as time_
def is_prime(n):
return all((n%j > 0) for j in xrange(2, n))
def primes_below(x):
return [[j-6, j] for j in xrange(9, x+1) if is_prime(j) and is_prime(j-6)]
a = int(round(time_.time() * 1000))
print(primes_below(10*1000))
b = int(round(time_.time() * 1000))
print(str((b-a)) + " mils")
ファクター
MEMO:: prime? ( n -- ? )
n 1 - 2 [a,b] [ n swap mod 0 > ] all? ;
MEMO: sexyprimes ( n n -- r r )
[a,b] [ prime? ] filter [ 6 + ] map [ prime? ] filter dup [ 6 - ] map ;
5 10 1000 * sexyprimes . .
Bash(zsh)です。
#!/usr/bin/zsh
function prime {
for (( i = 2; i < $1; i++ )); do
if [[ $[$1%i] == 0 ]]; then
echo 1
exit
fi
done
echo 0
}
function sexy-primes {
for (( i = 9; i <= $1; i++ )); do
j=$[i-6]
if [[ $(prime $i) == 0 && $(prime $j) == 0 ]]; then
echo $j $i
fi
done
}
sexy-primes 10000
質問
- なぜScalaは速いのですか?それは 静的型付け ? それともJVMを非常に効率的に使っているだけなのでしょうか?
- なぜRubyとPythonはこんなに違うのでしょうか?私はこれらの2つがやや全く異なるものではないと思っていました。私のコードが間違っているのかもしれません。ご教示ください。ありがとうございます。 UPD はい、それは私のコードの誤りでした。PythonとRuby 1.9はかなり同等です。
- Ruby のバージョン間の生産性では本当に印象的なジャンプです。
- 型宣言を追加することで、Clojureコードを最適化することができますか?それは役に立ちますか?
どのように解決するのですか?
大まかな答えです。
- Scalaの静的型付けは、ここでかなり役に立っています。これは、あまり余分な努力をせずに、JVMをかなり効率的に使用することを意味します。
-
Ruby と Python の違いについては正確にはわかりませんが、おそらく
(2...n).all?
という関数の中でis-prime?
はRubyでかなりうまく最適化されているようです(EDIT: 実際そうなっているようです、詳しくはJulianの回答を見てください...)。 - Ruby 1.9.3 はより良く最適化されています。
- Clojureのコードは確かにたくさん高速化できます! Clojureはデフォルトで動的ですが、型ヒント、原始的な数学などを使用して、必要なときに多くのケースでScala / pure Javaに近い速度にすることができます。
Clojureのコードで最も重要な最適化は
is-prime?
のようなものです。
(set! *unchecked-math* true) ;; at top of file to avoid using BigIntegers
(defn ^:static is-prime? [^long n]
(loop [i (long 2)]
(if (zero? (mod n i))
false
(if (>= (inc i) n) true (recur (inc i))))))
この改善により、Clojureは10kを0.635秒で完了するようになりました(つまり、Scalaに勝って、リストの2番目に速いということです)。
P.S.
のような関数を使用している場合は特に、結果を歪めてしまうので良いアイデアではありません。
print
のような関数を初めて使用する場合、特に IO サブシステムの初期化などを引き起こすため、結果を歪めてしまいます!
関連
-
[解決済み] Pythonの旧スタイルのクラスと新スタイルのクラスの違いは何ですか?
-
[解決済み] を付けるべきでしょうか?(shebang)を付けるべきか、またどのような形で付けるべきか?
-
[解決済み] Pythonにおけるincrementとdecrement演算子の挙動
-
[解決済み] Pythonの__future__は何に使うのか、いつ、どのように使うのか、その仕組みについて
-
[解決済み] Scalaのオブジェクトとクラスの違い
-
[解決済み] RubyでBegin, Rescue, Ensure?
-
[解決済み] PythonでのAWS Lambdaのインポートモジュールエラー
-
[解決済み] Python 2.7サポート終了?
-
[解決済み] PythonからSMTPを使用してメールを送信する
-
[解決済み] pycharmがタブをスペースに自動変換する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] PythonでファイルのMD5チェックサムを計算するには?重複
-
[解決済み] PILからopenCVフォーマットへの変換
-
[解決済み] PythonでSVGからPNGに変換する
-
[解決済み] Scalaでfor-comprehensionとloopを最適化する方法とは?
-
[解決済み] DataFrameに日付間の日数カラムを追加する pandas
-
[解決済み] python-requests モジュールからのすべてのリクエストをログに記録します。
-
[解決済み] SQLAlchemy - テーブルのリストを取得する
-
[解決済み] tensorflowのCPUのみのインストールでダイナミックライブラリ 'cudart64_101.dll' を読み込めなかった
-
[解決済み] Pythonの文字列の前にあるbという接頭辞は何を意味するのですか?
-
[解決済み] Alembicアップグレードスクリプトでインサートやアップデートを実行するにはどうすればよいですか?