LoginSignup
6
2

More than 5 years have passed since last update.

ruby で最大値を求める方法の速度比較

Posted at

結論:ruby 2.4 は素晴らしい

http://qiita.com/Nabetani/items/b48f5cb6361496ca7712
で議論になった、最大値の求め方。

lazy_map_max
  size.times.lazy.map{ |x| f(x) }.max
inject_cond
  size.times.inject(0){ |acc,x| t=f(x);acc=t<acc ? acc : t }
inject_max
  size.times.inject(0){ |acc,x| [acc,f(x)].max }
map_max
  size.times.map{ |x| f(x) }.max

と、いろいろ方法がある。で。実行時間を比較する。

対象は ruby 2.3.3p222 と、ruby 2.4.0p0 。

Kobito.J9Rab0.png

実行時間なので、短いほど良い。

速度重視で選ぶなら、ruby2.3 だと、inject_cond 一択。ruby2.4 だと、lazy_map_max 以外ならどれでも同じ。という事になった。

https://docs.ruby-lang.org/ja/latest/doc/news=2f2_4_0.html

いくつかの条件で [x,y].max と [x,y].min が一時的な配列を生成しないよう最適化されました。

の効果によって、 ruby2.4 では inject_max が速くなっていて、inject_cond に追いついた感じ。
map_max も相当速くなっていて、こちらも inject_cond に追いついているけど、これはなんでなんだろう。

lazy を使ったコードはやっぱり遅かった。

実験に使ったのはこんなコード:

bench.rb
#encode:utf-8

(p RUBY_DESCRIPTION) rescue p "1.8.x or former"
require "benchmark"

def f(x)
  (x/3) & (x/7)
end

def map_max(size)
  size.times.map{ |x| f(x) }.max
end

def lazy_map_max(size)
  size.times.lazy.map{ |x| f(x) }.max
end

def inject_max(size)
  size.times.inject(0){ |acc,x| [acc,f(x)].max }
end

def inject_cond(size)
  size.times.inject(0){ |acc,x| t=f(x);acc=t<acc ? acc : t }
end

def run_bench( n, size )
  puts "n, size = #{n}, #{size}"

  m=[ :map_max, :inject_max, :inject_cond, :lazy_map_max ]
  len = m.map(&:to_s).map(&:size).max
  Benchmark.bmbm(len) do |x|
    m.each do |s|
      x.report(s.to_s){
        n.times do
          self.send(s, size)
        end
      }
    end
  end
end

run_bench( 100, 100000 )
6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2