はじめに
Rubyの繰り返し処理の速さが気になったのでベンチマークで調べてみました。
whileを使うと速いと聞いたので、他の繰り返し処理も使い、実際に検証してみました。
Rubyのモジュールとして提供されているBenchmarkを使用してプログラム実行時のCPU処理にかかった時間を知ることができます。
繰り返す内容
1から3,000,000までの範囲の数値を加算していきます。
つまり↓のようになります
1 + 2 + 3 + 4 ・・・・・ 2999998 + 2999999 + 3000000 = 4,500,001,500,000
コード
require 'benchmark'
Benchmark.benchmark(Benchmark::CAPTION, 10, Benchmark::FORMAT) do |x|
x.report("each: ") {
counter = 0
[*1..3000000].each do |i|
counter += i
end
}
x.report("times: ") {
counter = 0
3000000.times do |i|
counter += i + 1
end
}
x.report("each range: ") {
counter = 0
(1..3000000).each do |i|
counter += i
end
}
x.report("times simple: ") {
counter = 0
(3000001).times do |i|
counter += i
end
}
x.report("upto: ") {
counter = 0
1.upto(3000000) do |i|
counter += i
end
}
x.report("while: ") {
counter,i = 0,1
while i != 3000001 do
counter += i
i += 1
end
}
end
実行結果
user system total real
each: 0.244779 0.016559 0.261338 ( 0.261447)
times: 0.166149 0.000000 0.166149 ( 0.166150)
each range: 0.154344 0.000083 0.154427 ( 0.154438)
times simple: 0.153153 0.000066 0.153219 ( 0.153221)
upto: 0.154999 0.000000 0.154999 ( 0.155002)
while: 0.079974 0.000000 0.079974 ( 0.079976)
上記からわかること
whileが一番速く、timesとuptoとeachがほぼ同じということがわかりました。
あとは[*1..3000000]と(1..3000000)やi + 1のように書き方により速度が変わることもわかりました。
特に[*1..3000000]にするとだいぶ速度が落ちるので、(1..3000000)を使うのを意識したいです。
ちなみに
ガウスの計算(足し算)を使うと計算が1回ですむので2〜3千倍速くなりました。
ガウスの計算(足し算)の公式:(初めの数+最後の数)×個数÷2
初めの数:1
最後の数:3,000,000
個数:3,000,000
つまり( 1 + 3000000) * ( 3000000 / 2 ) = 4,500,001,500,000
3000001 * 1500000 = 4,500,001,500,000
require 'benchmark'
Benchmark.benchmark(Benchmark::CAPTION, 10, Benchmark::FORMAT) do |x|
x.report("ガウス計算:") {
puts "計算結果は#{ ( 1 + 3000000 ) * ( 3000000 / 2 ) }"
}
end
実行結果
user system total real
ガウス計算: 計算結果は4500001500000
ガウス計算: 0.000026 0.000000 0.000026 ( 0.000026)
ガウスは偉大!