Problem 14 (その2:未解決)

わからない・・・どうやっても1000000で処理すると

 *** Exception: stack overflow

がでるか,異常な時間がかかってやってられない・・・むむーー.

前のコード

{-
Project Euler Problem 14 e14.hs
-}

collatz::Integer -> [Integer]
collatz n
    | n == 1    = [1]
    | otherwise = n:((collatz.next) n)
      where next:: Integer->Integer
            next n 
                | n `mod` 2 == 0 = n `div` 2
                | otherwise      = 3*n+1

collatzLengthList::[Integer] -> [(Integer, Integer)]
collatzLengthList = (map (\x -> (head x, (toInteger.length) x))) . (map collatz) 

getMax::[(Integer, Integer)] -> Integer
getMax = maximum .  map (\x -> snd x)

answer n =  filter (\x -> snd x == max) ns
    where ns = collatzLengthList [1..n]
          max = getMax ns

だと

 *Main> answer 100000
[(77031,351)]
(92.81 secs, 3510422796 bytes)
*Main>

時間がかかりすぎるように思います.なお,問題の1000000だと,あえなく

 *Main> answer 1000000
*** Exception: stack overflow
*Main>

となってしまう体たらく.

追記(2008/5/19)

スタックの領域が足りない!というなら増やしてあげればいいので,そうしてみます.mainを

import System.Environment

main = do args <- getArgs
          print $ answer $ read $ head args

と追加して,ghcコンパイルして実行ファイル(e14)にして,

e14 1000000 +RTS -K30M

とやってみます(30Mは試行錯誤で適当に決定.デフォルトは8M).stack overflowはでなくなるのですが,やたらと長い間待たされたあと,OSごと落ちてしまいました(苦笑).やはり,こういう小手先では駄目そうです.

「計算を速くする」のと「stack overflowしない」のをうまく両立させる手を模索する方向で考えます.途中の計算結果を保持して計算量を減らす(キャッシュを作る)のはすでに5通りくらい作ったのですが,全部1000000でstack overflowを起こします(もっと実際はもっと小さい値で駄目).さらに「キャッシュを作ってそれを保持する」「キャッシュを探索する」方に逆に時間やメモリをとられたり,そもそも「ヒットするキャッシュが少ない?」というケースもあるようで,むずかしいです.