fork(1) download
  1. {-# OPTIONS -O2 -XBangPatterns #-}
  2.  
  3. import Data.Word
  4. import Data.List (sortBy)
  5. import Data.Function (on)
  6.  
  7. main = let t = nthHam 1000000000000 in print t
  8.  
  9. lb3 = logBase 2 3; lb5 = logBase 2 5
  10. lbrt30 = logBase 2 $ sqrt 30 :: Double -- estimate adjustment as per WP
  11. -- logval (i,j,k) = fromIntegral i + fromIntegral j*lb3 + fromIntegral k*lb5
  12. trival (i,j,k) = 2^i * 3^j * 5^k
  13. estval2 n = (6*lb3*lb5*n)**(1/3) - lbrt30 -- estimated logval, base 2
  14. crctn n
  15. | n < 1000 = 0.509 -- empirical correction terms
  16. | n < 1000000 = 0.206
  17. | n < 1000000000 = 0.122 -- further divisions have little effect as already small
  18. | otherwise = 0.105 -- very slowly decrease from this point for a billion
  19.  
  20. nthHam :: Word64 -> (Int, Int, Int)
  21. nthHam n -- n: 1-based 1,2,3...
  22. | n < 2 = case n of
  23. 0 -> error "nthHam: Argument is zero!"
  24. _ -> (0, 0, 0) -- trivial case for 1
  25. | m < 0 = error $ "Not enough triples generated: " ++ show (c,n)
  26. | m >= nb = error $ "Generated band is too narrow: " ++ show (m,nb)
  27. | otherwise = case res of (_, tv) -> tv -- 2^i * 3^j * 5^k
  28. where
  29. (fr,est)= (crctn n, estval2 $ fromIntegral n) -- fraction of log2 error, est val
  30. (hi,lo) = (estval2 (fromIntegral n + fr*est), 2*est-hi) -- hi > logval2 >= lo
  31. (c,b) = f ()
  32. f () =
  33. let klmt = floor (hi/lb5) in
  34. let loopk k !ck bndk =
  35. if k > klmt then (ck, bndk) else
  36. let p = fromIntegral k*lb5; jlmt = floor ((hi-p)/lb3) in
  37. let loopj j !cj bndj =
  38. if j > jlmt then loopk (k+1) cj bndj else
  39. let q = fromIntegral j*lb3 + p in
  40. let (i, frac) = properFraction (hi-q); r = hi-frac in
  41. if r < lo then loopj (j+1) (fromIntegral i+cj+1) bndj else
  42. loopj (j+1) (fromIntegral i+cj+1) ((r,(i,j,k)):bndj) in
  43. loopj 0 ck bndk in
  44. loopk 0 0 []
  45. (m,nb) = ( fromIntegral $ c - n, length b ) -- m 0-based from top, |band|
  46. (s,res) = ( sortBy (flip compare `on` fst) b, s!!m ) -- sorted decreasing, result
Success #stdin #stdout 3.75s 5760KB
stdin
Standard input is empty
stdout
(1126,16930,40)