Почему `(map digitToInt). show` так быстро?

Преобразование неотрицательного Целого числа в его список цифр обычно выполняется следующим образом:

import Data.Char

digits :: Integer -> [Int]
digits = (map digitToInt) . show

Я пытался найти более прямой способ выполнить задачу без преобразования строк, но я не могу придумать что-то более быстрое.

То, что я пробовал до сих пор:

Базовый уровень:

digits :: Int -> [Int]
digits = (map digitToInt) . show

Получил это из другого вопроса о StackOverflow:

digits2 :: Int -> [Int]
digits2 = map (`mod` 10) . reverse . takeWhile (> 0) . iterate (`div` 10)

Попытка свернуть свой собственный:

digits3 :: Int -> [Int]
digits3 = reverse . revDigits3

revDigits3 :: Int -> [Int]
revDigits3 n = case divMod n 10 of
               (0, digit) -> [digit]
               (rest, digit) -> digit:(revDigits3 rest)

Этот пример был вдохновлен showInt в Numeric :

digits4 n0 = go n0 [] where
    go n cs
        | n < 10    =  n:cs
        | otherwise =  go q (r:cs)
        where
        (q,r) = n `quotRem` 10

Теперь тест. Примечание: я принудительно выполняю оценку, используя фильтр .

λ>:set +s
λ>length $ filter (>5) $ concat $ map (digits) [1..1000000]
2400000
(1.58 secs, 771212628 bytes)

Это ссылка. Теперь для цифр2 :

λ>length $ filter (>5) $ concat $ map (digits2) [1..1000000]
2400000
(5.47 secs, 1256170448 bytes)

Это в 3,46 раз больше.

λ>length $ filter (>5) $ concat $ map (digits3) [1..1000000]
2400000
(7.74 secs, 1365486528 bytes)

цифр3 на 4,89 раз медленнее. Просто для развлечения, Я пробовал использовать только revDigits3 и избегать обратного .

λ>length $ filter (>5) $ concat $ map (revDigits3) [1..1000000]
2400000
(8.28 secs, 1277538760 bytes)

Как ни странно, это еще медленнее, 5,24 раз медленнее.

И последнее:

λ>length $ filter (>5) $ concat $ map (digits4) [1..1000000]
2400000
(16.48 secs, 1779445968 bytes)

Это на 10,43 времени медленнее.

У меня создалось впечатление, что только использование арифметики и cons превзойдет все, что связано с преобразованием строк. Видимо, я чего-то не понимаю.

Так в чем же фокус? Почему цифр так быстро?

Я использую GHC 6.12.3.

12
задан gawi 30 January 2011 в 21:13
поделиться