fork(2) download
  1. {-# OPTIONS_GHC -O2 #-}
  2. {-# LANGUAGE BangPatterns #-}
  3.  
  4. -- rosettacode.org/wiki/Hamming_numbers#Haskell -- derived from ideone.com/q3fma
  5.  
  6. module Main where
  7. import Data.List
  8. import Data.Function
  9.  
  10. newtype Ham = Ham (Double,(Int,Int,Int)) -- 1M: OK: ("5.193127804483973E+83",(55,47,64))
  11.  
  12. instance Eq Ham where
  13. Ham (_,a) == Ham (_,b) = a == b
  14.  
  15. instance Ord Ham where
  16. compare (Ham (a,_)) (Ham (b,_)) = compare a b
  17.  
  18. instance Show Ham where
  19. show (Ham(x,(i,j,k))) = show (showLogVal 2 x,(i,j,k)) -- (x,2^i*3^j*5^k)
  20.  
  21. showLogVal base logval = show (10**y) ++ "E+" ++ show x
  22. where (x,y) = properFraction (logBase 10 base * logval)
  23.  
  24. _I i = fromIntegral i
  25.  
  26. mul2 (Ham (_,(b,c,d))) = Ham ((_I b+1.0) + _I c *lb3 + _I d *lb5, (b+1,c,d))
  27. mul3 (Ham (_,(b,c,d))) = Ham ( _I b + (_I c+1.0)*lb3 + _I d *lb5, (b,c+1,d))
  28. mul5 (Ham (_,(b,c,d))) = Ham ( _I b + _I c *lb3 + (_I d+1.0)*lb5, (b,c,d+1))
  29.  
  30. one = Ham (0.0,(0,0,0))
  31.  
  32. hamming = one : map mul2 hamming `union` map mul3 hamming `union` map mul5 hamming -- [Ham]
  33. -- 1 : map (2*) hamming `union` map (3*) hamming `union` map (5*) hamming -- [Integer]
  34. where
  35. union a@(x:xs) b@(y:ys) = case compare x y of
  36. LT -> x : union xs b
  37. EQ -> x : union xs ys
  38. GT -> y : union a ys
  39.  
  40. main = do
  41. s <- getLine
  42. case s of
  43. ('x':s) -> do print $ hamming !! (read s-1) -- 1-based: 1-st is (0.0,(0,0,0))
  44. "a" -> do print $ take 20 hamming
  45. print (hamming !! 1690, hamming !! 1691)
  46. print $ hamming !! (1000000-1) -- 9 MB: releases the prefix of the list
  47. "b" -> do
  48. print $ hamming !! (1000000-1) -- 77 MB: does NOT release the prefix
  49. print $ hamming !! 1000000 -- (is needed twice)
  50. "c" -> do
  51. mapM_ print $ take 2 $ drop 999999 hamming -- 9 MB: used once, prefix gc-d
  52. "d" -> do
  53. let (r,t) = nthHam (1000000) -- 4 MB: stores upper band only
  54. (r2,t2) = nthHam (1000001)
  55. print (t,trival t)
  56. print (t2,trival t2)
  57. _ -> do -- 10^8: 4 MB 0.27 sec
  58. let (r,t) = nthHam (read s) -- 10^9: 6 MB (-4=2) 1.42 sec O(n^0.7)
  59. print t -- 10^10: 14 MB (-4=10) 7.20 sec O(n^0.7)
  60.  
  61. -- directly find n-th Hamming number (base 1, from 2), in ~ O(n^{2/3}) time
  62. -- based on "top band" idea by Louis Klauder from DDJ discussion,
  63. -- by Will Ness, original post: drdobbs.com/blogs/architecture-and-design/228700538
  64.  
  65. ln2 = log 2; ln3 = log 3; ln5 = log 5
  66. logval (i,j,k) = fromIntegral i*ln2 + fromIntegral j*ln3 + fromIntegral k*ln5
  67. trival (i,j,k) = 2^i * 3^j * 5^k
  68. estval n = (6*ln2*ln3*ln5* fromIntegral n)**(1/3) -- estimated logval
  69. rngval n
  70. | n > 500000 = (1.698 , 0.0050) -- empirical
  71. | n > 50000 = (1.693 , 0.0100) -- estimation
  72. | n > 500 = (1.66 , 0.0500) -- correction
  73. | n > 1 = (1.56 , 0.2000) -- (dist,width)
  74. | otherwise = (1.56 , 0.4000)
  75.  
  76. -- estval(n) = log (M[n]) = ln2 * logBase 2 (M[n])
  77.  
  78. lb3 = logBase 2 3; lb5 = logBase 2 5 -- lb3 == log 3/log 2, lb5 == log 5/log 2
  79. logval2 (i,j,k) = fromIntegral i + fromIntegral j*lb3 + fromIntegral k*lb5
  80. estval2 n = (6*lb3*lb5* fromIntegral n)**(1/3) -- estimated logval **Base 2**
  81. rngval2 n
  82. | n > 500000 = (2.4496 , 0.0076 ) -- empirical
  83. | n > 50000 = (2.4424 , 0.0146 ) -- estimation
  84. | n > 500 = (2.3948 , 0.0723 ) -- correction - base 2
  85. | n > 1 = (2.2506 , 0.2887 ) -- (dist,width)
  86. | otherwise = (2.2506 , 0.5771 )
  87.  
  88. nthHam n -- n: 1-based 1,2,3...
  89. | w >= 1 = error $ "Breach of contract (w < 1): " ++ show (w)
  90. | m < 0 = error $ "The estimate is too small: " ++ show (c,n)
  91. | m >= nb = error $ "Generated band is too narrow: " ++ show (m,nb)
  92. | True = res
  93. where
  94. (d,w) = rngval2 n -- correction dist, width
  95. hi = estval2 n - d -- hi > logval2 > hi-w
  96. (c,b) = foldl_ -- total count, the band
  97. (\(!c,!b) (i,t) -> case t of { [] -> (i+c,b)
  98. ; [x] -> (i+c,x:b)})
  99. (0,[])
  100. [ ( i+1, -- total triples w/ this (j,k)
  101. [ (r,(i,j,k)) | frac < w ] ) -- store it, if inside band
  102. | k <- [ 0 .. floor ( hi /lb5) ], let p = fromIntegral k*lb5,
  103. j <- [ 0 .. floor ((hi-p)/lb3) ], let q = fromIntegral j*lb3 + p,
  104. let (i,frac) = pr (hi-q) ; r = hi - frac -- r = i + q
  105. ] where pr = properFraction
  106. (m,nb) = ( fromIntegral $ c - n, length b ) -- m 0-based from top, |band|
  107. (s,res) = ( sortBy (flip compare `on` fst) b, s!!m ) -- sorted decreasing, result
  108. foldl_ = foldl'
Success #stdin #stdout 3.19s 7972KB
stdin
x3000000
stdout
("1.1603310152181268E+121",(55,137,56))