UP | HOME

Euler Problem 104

1. Solutions

There are two solutions below. One is written by me and another from haskell wiki.

They look quite similar and I can not figure out why the wiki solution can solve problem but not mine. (Actually mine take more than 15 minutes)

  • My Solution
  main = print $ snd $ head $
         dropWhile (\ (x,y) -> (not . isLastNinePandigit "123456789") x)
                   (zip fibs [1..])

  bothNinePandigit digits n =  isFirstNinePandigit digits n
                               && isLastNinePandigit digits n

  isLastNinePandigit  digits = (== digits) . sort . lastDigits 9
  isFirstNinePandigit digits = (== digits) . sort . firstDigits 9

  firstDigits k n = take k (show n)
  lastDigits  k n = show (n `mod` 10^k)
  • Haskell Wiki solution1
  fibs = 1 : 1 : zipWith (+) fibs (tail fibs)

  isFibPan n =
    let a = n `mod` 1000000000
        b = sort (show a)
        c = sort $ take 9 $ show n
    in  b == "123456789" && c == "123456789"

  ex_104 = snd $ head $
           dropWhile (\(x,y) -> (not . isFibPan) x) (zip fibs [1..])

2. Why the differences?

The key point here is should test start nine digits first or test end nine digits.

Two concerns here:

  1. show function is (relatively) slow which used in test first 9 digits function.
  2. quite few numbers are end in digits 1..9 in the first 329000 numbers

Therefore test last 9 digits first make great performance improvement.

Thanks Brent2 explanation this sneaky thing very comprehensively in haskell-beginner.

3. Profiling

What help to identify is the GHC profiling tool.

Several options used here are

  • prof: for basic time and allocation profiling
  • auto-all: auto insert cost centers on all top level functions. “cost center” is a location in the program like to collect statistics about and GHC will generate code to compute the cost of evalutating the expression at each location. e.g.
    mean  s = {-# SCC "mean" #-} sum  s / fromIntegral (length s)
  • caf-all: function with no parameters only computed once. CAF means constant applicative forms which used for calculate that once time evaluation.
  • fforce-recomp: force full recompilation.

More details could go to chapter 253 of [Real World Haskell] and GHC user guider chapter 54.

  # build with prof option on
  ghc --make -O2 -prof -auto-all -rtsopts p104.hs

  # then run
  ./p104 +RTS -p -RTS

4. Further

  1. Chapter 25 in Real Work Haskell about profile

Footnotes: