{-# OPTIONS_GHC -O2 #-}
{-# LANGUAGE BangPatterns #-}
-- http://r...content-available-to-author-only...e.org/wiki/Hamming_numbers#Haskell
module Main where
import Data.List
import Data.Function
hamming
= 1 :
map (2*) hamming `union`
map (3*) hamming `union`
map (5*) hamming
where
union a
@(x:xs
) b
@(y:ys
) = case compare x y
of LT -> x : union xs b
EQ -> x : union xs ys
GT -> y : union a ys
main = do
case s of
"1" -> do
print (hamming
!! 1690, hamming
!! 1691) print $ hamming
!! (1000000-1) -- 9 MB: releases the prefix of the list "2" -> do
print $ hamming
!! (1000000-1) print $ hamming
!! 1000000 -- 77 MB: does NOT release the prefix (is needed twice) "11" -> do
let (r,t) = nthHam (1000000-1) -- 4 MB: stores upper band only
_ -> do
let (r
,t
) = nthHam
(read s
) -- 10^8: 5 MB 0.29 sec print t
-- 10^9: 6 MB 1.52 sec O(n^0.7)
-- directly find n-th Hamming number (base 1, from 2), in ~ O(n^{2/3}) time
-- by Will Ness, based on "band" idea by Louis Klauder from DDJ discussion
-- http://d...content-available-to-author-only...s.com/blogs/architecture-and-design/228700538
trival (i,j,k) = 2^i * 3^j * 5^k
estval n
= (6*ln2
*ln3
*ln5
* fromIntegral n
)**(1/3) -- estimated logvalrngval n
| n > 500000 = (1.698 , 0.0050) -- empirical
| n > 50000 = (1.693 , 0.0100) -- estimation
| n > 500 = (1.66 , 0.0500) -- correction
| n > 1 = (1.56 , 0.2000) -- (dist,width)
nthHam n1 -- n1: 1-based 2,3...
| w
>= ln2
= error $ "Breach of contract: w >= ln2 " ++ show (w
,ln2
) | m
< 0 = error $ "Not enough triples generated: " ++ show (c
,n
) | m
>= nb
= error $ "Generated band is too narrow: " ++ show (m
,nb
) | True = res
where
n = n1 + 1 -- n: 1-based 1,2,3...
(d,w) = rngval n -- correction dist, width
(w2,hi) = ( w/ln2, estval n - d ) -- hi > logval > hi-w
(c
,b
) = foldl' -- total count, the band (\(!c,!b) (i,t) -> case t of [] -> (i+c,b)
[x] -> (i+c,x:b))
(0,[])
[ ( i+1, -- total triples w/ this (j,k)
[ (r,(i,j,k)) | frac < w2 ] ) -- store it, if inside band
| k <- [ 0 .. floor ( hi /ln5) ], let p = fromIntegral k*ln5,
j <- [ 0 .. floor ((hi-p)/ln3) ], let q = fromIntegral j*ln3 + p,
let (i,frac) = pr ((hi-q)/ln2) ; r = fromIntegral i*ln2 + q
] where pr = properFraction
(m,nb) = ( fromInteger $ c - n, length b ) -- m 0-based from top, |band|
(s,res) = ( sortBy (flip compare `on` fst) b, s!!m ) -- sorted decreasing, result
ey0jIE9QVElPTlNfR0hDIC1PMiAjLX0Key0jIExBTkdVQUdFIEJhbmdQYXR0ZXJucyAjLX0KCi0tIGh0dHA6Ly9yLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5lLm9yZy93aWtpL0hhbW1pbmdfbnVtYmVycyNIYXNrZWxsCgptb2R1bGUgTWFpbiB3aGVyZQppbXBvcnQgRGF0YS5MaXN0IAppbXBvcnQgRGF0YS5GdW5jdGlvbgoKaGFtbWluZyA9IDEgOiBtYXAgKDIqKSBoYW1taW5nIGB1bmlvbmAgbWFwICgzKikgaGFtbWluZyBgdW5pb25gIG1hcCAoNSopIGhhbW1pbmcKICB3aGVyZQogICAgdW5pb24gYUAoeDp4cykgYkAoeTp5cykgPSBjYXNlIGNvbXBhcmUgeCB5IG9mCiAgICAgICAgICAgIExUIC0+IHggOiB1bmlvbiAgeHMgIGIKICAgICAgICAgICAgRVEgLT4geCA6IHVuaW9uICB4cyAgeXMKICAgICAgICAgICAgR1QgLT4geSA6IHVuaW9uICBhICAgeXMKCm1haW4gPSBkbyAKICBzIDwtIGdldExpbmUKICBjYXNlIHMgb2YKICAgIjEiIC0+IGRvCiAgICAgICAgICAgICBwcmludCAkIHRha2UgMjAgaGFtbWluZwogICAgICAgICAgICAgcHJpbnQgIChoYW1taW5nICEhIDE2OTAsIGhhbW1pbmcgISEgMTY5MSkKICAgICAgICAgICAgIHByaW50ICQgaGFtbWluZyAhISAoMTAwMDAwMC0xKSAgICAgICAgICAtLSA5IE1COiByZWxlYXNlcyB0aGUgcHJlZml4IG9mIHRoZSBsaXN0CiAgICIyIiAtPiBkbwogICAgICAgICAgICAgcHJpbnQgJCBoYW1taW5nICEhICgxMDAwMDAwLTEpCiAgICAgICAgICAgICBwcmludCAkIGhhbW1pbmcgISEgIDEwMDAwMDAgICAgICAgICAgICAgLS0gNzcgTUI6IGRvZXMgTk9UIHJlbGVhc2UgdGhlIHByZWZpeCAoaXMgbmVlZGVkIHR3aWNlKQogICAiMTEiIC0+IGRvCiAgICAgICAgICAgICBsZXQgKHIsdCkgPSBudGhIYW0gKDEwMDAwMDAtMSkgICAgICAgICAgLS0gNCBNQjogc3RvcmVzIHVwcGVyIGJhbmQgb25seQogICAgICAgICAgICAgcHJpbnQgKHQsdHJpdmFsIHQpICAgICAgICAgCiAgIF8gICAtPiBkbyAgICAgICAgCiAgICAgICAgICAgICBsZXQgKHIsdCkgPSBudGhIYW0gKHJlYWQgcykgICAgICAgICAgICAgLS0gICAgMTBeODogNSBNQiAgIDAuMjkgc2VjCiAgICAgICAgICAgICBwcmludCB0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLS0gICAgMTBeOTogNiBNQiAgIDEuNTIgc2VjICAgTyhuXjAuNykKCi0tIGRpcmVjdGx5IGZpbmQgbi10aCBIYW1taW5nIG51bWJlciAoYmFzZSAxLCBmcm9tIDIpLCBpbiB+IE8obl57Mi8zfSkgdGltZQotLSBieSBXaWxsIE5lc3MsIGJhc2VkIG9uICJiYW5kIiBpZGVhIGJ5IExvdWlzIEtsYXVkZXIgZnJvbSBEREogZGlzY3Vzc2lvbgotLSAgIGh0dHA6Ly9kLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5zLmNvbS9ibG9ncy9hcmNoaXRlY3R1cmUtYW5kLWRlc2lnbi8yMjg3MDA1MzgKCmxuMiA9IGxvZyAyOyAgbG4zID0gbG9nIDM7ICBsbjUgPSBsb2cgNQpsb2d2YWwgKGksaixrKSAgICA9IGZyb21JbnRlZ3JhbCBpKmxuMiArIGZyb21JbnRlZ3JhbCBqKmxuMyArIGZyb21JbnRlZ3JhbCBrKmxuNQp0cml2YWwgKGksaixrKSAgICA9IDJeaSAqIDNeaiAqIDVeawplc3R2YWwgbiAgICAgICAgICA9ICg2KmxuMipsbjMqbG41KiBmcm9tSW50ZWdyYWwgbikqKigxLzMpICAtLSBlc3RpbWF0ZWQgbG9ndmFsCnJuZ3ZhbCBuICAgICAgIAogICAgfCBuID4gNTAwMDAwICA9ICgxLjY5OCAsIDAuMDA1MCkgICAgICAgICAgICAgICAgICAgICAgICAgIC0tIGVtcGlyaWNhbAogICAgfCBuID4gNTAwMDAgICA9ICgxLjY5MyAsIDAuMDEwMCkgICAgICAgICAgICAgICAgICAgICAgICAgIC0tICBlc3RpbWF0aW9uCiAgICB8IG4gPiA1MDAgICAgID0gKDEuNjYgICwgMC4wNTAwKSAgICAgICAgICAgICAgICAgICAgICAgICAgLS0gICBjb3JyZWN0aW9uICAKICAgIHwgbiA+IDEgICAgICAgPSAoMS41NiAgLCAwLjIwMDApICAgICAgICAgICAgICAgICAgICAgICAgICAtLSAgICAoZGlzdCx3aWR0aCkKICAgIHwgb3RoZXJ3aXNlICA9ICgxLjU2ICAsIDAuNDAwMCkgIAogCm50aEhhbSBuMSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLS0gbjE6IDEtYmFzZWQgMiwzLi4uCiAgfCB3ID49IGxuMiA9IGVycm9yICQgIkJyZWFjaCBvZiBjb250cmFjdDogdyA+PSBsbjIgICIgKysgc2hvdyAodyxsbjIpCiAgfCBtIDwgIDAgICA9IGVycm9yICQgIk5vdCBlbm91Z2ggdHJpcGxlcyBnZW5lcmF0ZWQ6ICIgKysgc2hvdyAoYyxuKQogIHwgbSA+PSBuYiAgPSBlcnJvciAkICJHZW5lcmF0ZWQgYmFuZCBpcyB0b28gbmFycm93OiAiICsrIHNob3cgKG0sbmIpCiAgfCBUcnVlICAgICA9IHJlcyAKIHdoZXJlIAogIG4gICAgICAgPSBuMSArIDEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0tIG46IDEtYmFzZWQgMSwyLDMuLi4KICAoZCx3KSAgID0gcm5ndmFsIG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtLSBjb3JyZWN0aW9uIGRpc3QsIHdpZHRoCiAgKHcyLGhpKSA9ICggdy9sbjIsIGVzdHZhbCBuIC0gZCApICAgICAgICAgICAgICAgICAgICAgICAgICAgLS0gICBoaSA+IGxvZ3ZhbCA+IGhpLXcgCiAgKGMsYikgICA9IGZvbGRsJyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLS0gdG90YWwgY291bnQsIHRoZSBiYW5kCiAgICAgICAgICAgICAoXCghYywhYikgKGksdCkgLT4gY2FzZSB0IG9mIFtdIC0+IChpK2MsYikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW3hdIC0+IChpK2MseDpiKSkgCiAgICAgICAgICAgICAoMCxbXSkKICAgICAgICAgICAgIFsgKCBpKzEsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtLSB0b3RhbCB0cmlwbGVzIHcvIHRoaXMgKGosaykKICAgICAgICAgICAgICAgICBbIChyLChpLGosaykpIHwgZnJhYyA8IHcyIF0gKSAgICAgICAgICAgICAgICAtLSBzdG9yZSBpdCwgaWYgaW5zaWRlIGJhbmQKICAgICAgICAgICAgICAgfCBrIDwtIFsgMCAuLiBmbG9vciAoIGhpICAgL2xuNSkgXSwgIGxldCBwID0gZnJvbUludGVncmFsIGsqbG41LCAgICAKICAgICAgICAgICAgICAgICBqIDwtIFsgMCAuLiBmbG9vciAoKGhpLXApL2xuMykgXSwgIGxldCBxID0gZnJvbUludGVncmFsIGoqbG4zICsgcCwKICAgICAgICAgICAgICAgICBsZXQgKGksZnJhYykgPSBwciAoKGhpLXEpL2xuMikgOyAgICAgICAgciA9IGZyb21JbnRlZ3JhbCBpKmxuMiArIHEgCiAgICAgICAgICAgICAgIF0gd2hlcmUgICAgIHByID0gcHJvcGVyRnJhY3Rpb24KICAobSxuYikgID0gKCBmcm9tSW50ZWdlciAkIGMgLSBuLCBsZW5ndGggYiApICAgICAgICAgICAgICAgLS0gbSAwLWJhc2VkIGZyb20gdG9wLCB8YmFuZHwKICAocyxyZXMpID0gKCBzb3J0QnkgKGZsaXAgY29tcGFyZSBgb25gIGZzdCkgYiwgcyEhbSApICAgICAgLS0gc29ydGVkIGRlY3JlYXNpbmcsIHJlc3VsdA==
[1 of 1] Compiling Main ( prog.hs, prog.o )
Linking prog ...
[1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36]
(2125764000,2147483648)
519312780448388736089589843750000000000000000000000000000000000000000000000000000000