This comment is reply for 6148 [1..100]>>=pen: ウサギとカメによる循環検出アルゴリズム ...(分数を小数に展開). Go to thread root.
[1..100]>>=pen #6175(2008/04/14 09:08 GMT) [ Haskell ] Rating1/1=1.00
http://en.wikipedia.org/wiki/Floyd's_cycle-finding_algorithm に書いてあったもう一つの循環検出アルゴリズム 「Brent のアルゴリズム」を使ったバージョン。 Brent によるとこの循環検出方法は Floyd の方法より平均で約36%速いそうです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
import List (unfoldr,findIndex) import Monad (msum) {- 余り列からμ(循環部より前の長さ)とλ(循環部の長さ)を求める (A) xs を1個、2個、4個、8個・・・からなる区間に分ける。 例えば xs = [1..] だったら [[1],[2,3],[4,5,6,7],..] に分けるように。 (本当はさらにもうちょっと加工している) (B) 各区間で先頭の値と同じものが区間中にあるか検索する (C) 最初に見つかった検索成功情報を取ってくる。 成功情報は Just i の形で i は λ-1 に等しい。 (D) インデックスを Just の中から取り出し1加える。 (E) λステップ進んだ位置とスタート位置から同時に進む(カウンタ付き)。 (F) 循環して出会うまで待つ。 -} muLam xs = (mu, if (d==0) then 0 else lam) where ys = unfoldr f (1,xs) -- (A) f (m,zs) = Just (splitAt 1 zs1, (2*m,zs2)) where (zs1,zs2) = splitAt m zs lam = maybe 0 (+1) -- (D) $ msum -- (C) $ zipWith (\([a],as) ([b],_) -> findIndex (==a) (as++[b])) -- (B) ys (tail ys) (_,d,mu) = head $ dropWhile (\(a,b,_) -> a/=b) -- (F) $ zip3 xs (drop lam xs) [0..] -- (E) toDecimal m n = show q0 ++ "." ++ (qs1 >>= show) ++ cyc where (q0,m') = divMod m n (_:qs,rs) = unzip $ iterate ((`divMod` n).(10*).snd) (0,m') (mu,lam) = muLam rs (qs1,qs2) = splitAt mu qs cyc | lam == 0 = "" | otherwise = "{" ++ (take lam qs2 >>= show) ++ "}"
Rating1/1=1.00-0+
[ reply ]
[1..100]>>=pen
#6175()
[
Haskell
]
Rating1/1=1.00
Rating1/1=1.00-0+