history

青木日記 RSS

<前の日 | この月 | 次の日>

2003-04-20

たらいまわしべんち

http://sheepman.parfait.ne.jp/20030418.html#p05

あ、sheepman さんのところに派生してる。

うーむ、おかしいなあ。 家だと lambda 使って遅延評価しても Hugs のほうが速いです。 GHC でコンパイルするとさらに激速。

~/c/test/haskell % cat lazy-tarai.rb
def tarai( x, y, z )
  if x.call <= y.call
  then y.call
  else tarai(lambda { tarai(lambda{x.call-1}, y, z) },
             lambda { tarai(lambda{y.call-1}, z, x) },
             lambda { tarai(lambda{z.call-1}, x, y) })
  end
end
 
puts tarai(lambda{48}, lambda{24}, lambda{0})
 
~/c/test/haskell % cat tarai.hs
module Main where
 
main :: IO ()
main = do
          print (tarai 48 24 0)
 
tarai :: Int -> Int -> Int -> Int
tarai x y z
    | x <= y    = y
    | otherwise = tarai (tarai (x-1) y z)
                        (tarai (y-1) z x)
                        (tarai (z-1) x y)
 
 
~/c/test/haskell % time ruby lazy-tarai.rb
48
ruby lazy-tarai.rb  0.44s user 0.00s system 104% cpu 0.419 total
 
~/c/test/haskell % time runhugs tarai.hs
48
runhugs tarai.hs  0.07s user 0.00s system 148% cpu 0.047 total
 
~/c/test/haskell % ghc -O -o tarai tarai.hs
~/c/test/haskell % time ./tarai
48
./tarai  0.00s user 0.00s system 0% cpu 0.000 total

つーか、GHC は速すぎだなあ。 定数畳み込みされてるのかと思ったんですが、 引数を大きくすると実行時間も増えていくところからすると ちゃんと計算しているようです。

3/22 の原先生の返り値をキャッシュするバージョンでも、 引数を (96,48,0) にすると Hugs に負けます。

~/c/test/haskell % time ruby memo-tarai.rb
96
ruby memo-tarai.rb  0.40s user 0.00s system 101% cpu 0.394 total
 
~/c/test/haskell % time runhugs tarai.hs
96
runhugs tarai.hs  0.10s user 0.00s system 107% cpu 0.093 total

ようするに、こないだのでは引数が小さすぎると。

ruby-dev summary

改めて見ると今週はすごい流量が少ないな。 _vsnprintf の話は結局結論が出てないっぽいし、 bigdecimal 関係だけか。まあこういう週もあるやね。

本日のツッコミ(全4件) [ツッコミを入れる]
shiro (2003-04-20 07:36)

lambdaだけでは計算量が完全な遅延評価ほど減らないように思います。
http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Scheme:たらいまわしべんち

shiro (2003-04-20 07:36)

おっと。リンク失敗しました。ごめんなさい。
http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Scheme%3a%a4%bf%a4%e9%a4%a4%a4%de%a4%ef%a4%b7%a4%d9%a4%f3%a4%c1&l=jp

ささだ (2003-04-20 18:22)

原先生版のは配列生成のコストが結構ありそうな予感.あと,コンパイルによる最適かもあるんでしょうね.

配列生成は,tarai(96,48,0) なので,[x,y,z] が 35K 作られる.なら,作らないようにしよう.

というわけで,

$memo = {}
def tarai2( x, y, z )
  getv(x,y,z) || putv(x,y,z)
end

def getv x,y,z
  ($memo[x] && $memo[x][y] && $memo[x][y][z])
end

def putv x,y,z
  r = if x <= y
    y
  else
    tarai2(
      tarai2(x-1,y,z),
      tarai2(y-1,z,x),
      tarai2(z-1,x,y))
  end
  x = $memo[x] ||= {x=>{}}
  #p x
  y = x[y] ||= {y=>{}}
  #p y
  y[z] = r
end
=>
  0.734000 0.000000 0.734000 ( 0.750000) # 原先生
  0.375000 0.000000 0.375000 ( 0.391000) # 今回の

しかし,われながらダサい.

はら (2003-04-20 20:33)

体裁を気にせずスピードを求めるなら:

def tarai( x, y )
  if x <= y
  then y
  else
    z = yield
    tarai(tarai(x-1, y){z}, tarai(y-1, z){x}){ tarai(z-1, x){y} }
  end
end

puts tarai(192, 96){0}

名前
メールアドレス

<前の日 | この月 | 次の日>
2002|04|05|06|07|08|09|10|11|12|
2003|01|02|03|04|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|04|05|06|09|10|
2009|07|
2010|09|

Copyright (c) 2002-2007 青木峰郎 / Minero Aoki. All rights reserved. LIRS