{-# OPTIONS_GHC -O2 #-}
{-# LANGUAGE BangPatterns #-}
-- rosettacode.org/wiki/Hamming_numbers#Haskell
module Main where -- cf. ideone.com/k8PU3, GXh4P0, 01dpQu
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
print (hamming
!! 1690, hamming
!! 1691) print $ hamming
!! (1000000-1) -- 9 MB: releases the prefix of the list "b" -> do
print $ hamming
!! (1000000-1) print $ hamming
!! 1000000 -- 77 MB: does NOT release the prefix (is needed twice) "c" -> do
"d" -> do
let (_ ,(r,t)) = nthHam (1000000) -- 4 MB: stores upper band only
(_ ,(r2,t2)) = nthHam (1000001)
_ -> do -- 10^8: 4 MB 0.27 sec
let (nb
,(r
,t
)) = nthHam
(read s
) -- 10^9: 6 MB (-4=2) 1.42 sec ~n^0.7 print (nb
, t
, showLogVal
2 r
) -- 10^10: 14 MB (-4=10) 7.20 sec ~n^0.7 -- print (case t of (i,j,k)-> 2^i*3^j*5^k)
showLogVal base logval
= show (10**y
) ++ "E+" ++ show x
trival (i,j,k) = 2^i * 3^j * 5^k
-- directly find n-th Hamming number (base 1, from 2), in ~ O(n^{2/3}) time
-- based on "top band" idea by Louis Klauder from DDJ discussion,
-- by Will Ness, original post: drdobbs.com/blogs/architecture-and-design/228700538
{-
ln2 = log 2; ln3 = log 3; ln5 = log 5
logval (i,j,k) = fromIntegral i*ln2 + fromIntegral j*ln3 + fromIntegral k*ln5
estval n = (6*ln2*ln3*ln5* fromIntegral n)**(1/3) -- estimated logval
rngval 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)
| otherwise = (1.56 , 0.4000)
-- estval(n) = log (M[n]) = ln2 * logBase 2 (M[n])
-}
-- lb3 :: Double
lb3
= logBase 2 3; lb5
= logBase 2 5 -- lb3 == log 3/log 2, lb5 == log 5/log 2-- logval2 :: (Int,Int,Int) -> Double
-- estval2 :: Integer -> Double
estval2 n
= (6*lb3
*lb5
* fromIntegral n
)**(1/3) -- estimated logval **Base 2**rngval2 n -- -1/v +2/v seems to works too
| n > 500000 = (ww-(3/estval2 n), 6/estval2 n) -- space tweak !!! (thx, GBG!)
| n > 500000 = (2.4496 , 0.0076 ) -- empirical
| n > 50000 = (2.4424 , 0.0146 ) -- estimation
| n > 500 = (2.3948 , 0.0723 ) -- correction - base 2
| n > 1 = (2.2506 , 0.2887 ) -- (dist,width)
-- nthHam :: Integer -> ( (Int,Int), (Double, (Int, Int, Int))) -- ( 64-bits: use Int!! NB! )
-- _band size stuff_ -- (*1*)
-- _max logval, min delta in band_
nthHam n -- n: 1-based 1,2,3...
| w
>= 1 = error $ "Breach of contract: (w < 1): " ++ show (w
) | m
< 0 = error $ "Not enough triples generated: " ++ show (c
,n
) | m
>= nb
= error $ "Generated band is too narrow: " ++ show (m
,nb
) | True = -- ((m,nb),res) -- m=target index in band from top, nb=band's length
( ( isTrulySorted ,
, res)
where
(d,w) = rngval2 n -- correction dist, width
hi = estval2 n - d -- hi > logval2 > 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::Integer,[]) -- ( 64bit: use Int!!! NB! ) -- (sum *** concat) . unzip $
[ (r,(i,j,k)) | frac < w ] ) -- store it, if inside band
let (i,frac) = pr (hi-q) ; r = hi - frac -- r = i + q
(s
,res
) = ( sortBy
(flip compare `on`
fst) b
, s
!!m
) -- sorted decreasing, result
ey0jIE9QVElPTlNfR0hDIC1PMiAjLX0Key0jIExBTkdVQUdFIEJhbmdQYXR0ZXJucyAjLX0KCi0tIHJvc2V0dGFjb2RlLm9yZy93aWtpL0hhbW1pbmdfbnVtYmVycyNIYXNrZWxsICAgIAoKbW9kdWxlIE1haW4gd2hlcmUgICAgICAgICAtLSBjZi4gaWRlb25lLmNvbS9rOFBVMywgR1hoNFAwLCAwMWRwUXUKCmltcG9ydCBEYXRhLkxpc3QgCmltcG9ydCBEYXRhLkZ1bmN0aW9uCgpoYW1taW5nID0gMSA6IG1hcCAoMiopIGhhbW1pbmcgYHVuaW9uYCBtYXAgKDMqKSBoYW1taW5nIGB1bmlvbmAgbWFwICg1KikgaGFtbWluZwogIHdoZXJlCiAgICB1bmlvbiBhQCh4OnhzKSBiQCh5OnlzKSA9IGNhc2UgY29tcGFyZSB4IHkgb2YKICAgICAgICAgICAgTFQgLT4geCA6IHVuaW9uICB4cyAgYgogICAgICAgICAgICBFUSAtPiB4IDogdW5pb24gIHhzICB5cwogICAgICAgICAgICBHVCAtPiB5IDogdW5pb24gIGEgICB5cwoKbWFpbiA9CiBkbyAKICBzIDwtIGdldExpbmUKICBjYXNlIHMgb2YKICAgImEiIC0+IGRvIHByaW50ICQgdGFrZSAyMCBoYW1taW5nCiAgICAgICAgICAgICBwcmludCAgKGhhbW1pbmcgISEgMTY5MCwgaGFtbWluZyAhISAxNjkxKQogICAgICAgICAgICAgcHJpbnQgJCBoYW1taW5nICEhICgxMDAwMDAwLTEpICAgICAgICAgIC0tIDkgTUI6IHJlbGVhc2VzIHRoZSBwcmVmaXggb2YgdGhlIGxpc3QKICAgImIiIC0+IGRvCiAgICAgICAgICAgICBwcmludCAkIGhhbW1pbmcgISEgKDEwMDAwMDAtMSkKICAgICAgICAgICAgIHByaW50ICQgaGFtbWluZyAhISAgMTAwMDAwMCAgICAgIC0tIDc3IE1COiBkb2VzIE5PVCByZWxlYXNlIHRoZSBwcmVmaXggKGlzIG5lZWRlZCB0d2ljZSkKICAgImMiIC0+IGRvCiAgICAgICAgICAgICBtYXBNXyBwcmludCAkIHRha2UgMiAkIGRyb3AgOTk5OTk5IGhhbW1pbmcgIC0tIDkgTUI6IHVzZWQgb25jZSwgcHJlZml4IGdjLWQKICAgImQiIC0+IGRvCiAgICAgICAgICAgICBsZXQgKF8gLChyLHQpKSAgID0gbnRoSGFtICgxMDAwMDAwKSAgICAgICAgIC0tIDQgTUI6IHN0b3JlcyB1cHBlciBiYW5kIG9ubHkKICAgICAgICAgICAgICAgICAoXyAsKHIyLHQyKSkgPSBudGhIYW0gKDEwMDAwMDEpCiAgICAgICAgICAgICBwcmludCAodCx0cml2YWwgdCkgICAgICAgICAKICAgICAgICAgICAgIHByaW50ICh0Mix0cml2YWwgdDIpICAgICAgICAgCiAgIF8gICAtPiBkbyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0tICAgIDEwXjg6ICA0IE1CICAgICAgICAgIDAuMjcgc2VjCiAgICAgICAgICAgICBsZXQgKG5iLChyLHQpKSA9IG50aEhhbSAocmVhZCBzKSAgICAgICAgIC0tICAgIDEwXjk6ICA2IE1CICgtND0yKSAgIDEuNDIgc2VjICAgfm5eMC43CiAgICAgICAgICAgICBwcmludCAobmIsIHQsIHNob3dMb2dWYWwgMiByKSAgICAgICAgICAgLS0gICAxMF4xMDogMTQgTUIgKC00PTEwKSAgNy4yMCBzZWMgICB+bl4wLjcKICAgICAgICAgICAgIC0tIHByaW50IChjYXNlIHQgb2YgKGksaixrKS0+IDJeaSozXmoqNV5rKQoKc2hvd0xvZ1ZhbCA6OiBEb3VibGUgLT4gRG91YmxlIC0+IFN0cmluZwpzaG93TG9nVmFsIGJhc2UgbG9ndmFsID0gc2hvdyAoMTAqKnkpICsrICJFKyIgKysgc2hvdyB4CiAgIHdoZXJlICh4LHkpID0gcHJvcGVyRnJhY3Rpb24gKGxvZ0Jhc2UgMTAgYmFzZSAqIGxvZ3ZhbCkgCiAgIAp0cml2YWwgKGksaixrKSAgICA9IDJeaSAqIDNeaiAqIDVeawoKLS0gZGlyZWN0bHkgZmluZCBuLXRoIEhhbW1pbmcgbnVtYmVyIChiYXNlIDEsIGZyb20gMiksIGluIH4gTyhuXnsyLzN9KSB0aW1lCi0tIGJhc2VkIG9uICJ0b3AgYmFuZCIgaWRlYSBieSBMb3VpcyBLbGF1ZGVyIGZyb20gRERKIGRpc2N1c3Npb24sCi0tIGJ5IFdpbGwgTmVzcywgb3JpZ2luYWwgcG9zdDogZHJkb2Jicy5jb20vYmxvZ3MvYXJjaGl0ZWN0dXJlLWFuZC1kZXNpZ24vMjI4NzAwNTM4CnstCmxuMiA9IGxvZyAyOyAgbG4zID0gbG9nIDM7ICBsbjUgPSBsb2cgNQpsb2d2YWwgKGksaixrKSAgICA9IGZyb21JbnRlZ3JhbCBpKmxuMiArIGZyb21JbnRlZ3JhbCBqKmxuMyArIGZyb21JbnRlZ3JhbCBrKmxuNQplc3R2YWwgbiAgICAgICAgICA9ICg2KmxuMipsbjMqbG41KiBmcm9tSW50ZWdyYWwgbikqKigxLzMpICAtLSBlc3RpbWF0ZWQgbG9ndmFsCnJuZ3ZhbCBuICAgICAgIAogICAgfCBuID4gNTAwMDAwICA9ICgxLjY5OCAsIDAuMDA1MCkgICAgICAgICAgICAgICAgICAgICAgICAgIC0tIGVtcGlyaWNhbAogICAgfCBuID4gNTAwMDAgICA9ICgxLjY5MyAsIDAuMDEwMCkgICAgICAgICAgICAgICAgICAgICAgICAgIC0tICBlc3RpbWF0aW9uCiAgICB8IG4gPiA1MDAgICAgID0gKDEuNjYgICwgMC4wNTAwKSAgICAgICAgICAgICAgICAgICAgICAgICAgLS0gICBjb3JyZWN0aW9uICAKICAgIHwgbiA+IDEgICAgICAgPSAoMS41NiAgLCAwLjIwMDApICAgICAgICAgICAgICAgICAgICAgICAgICAtLSAgICAoZGlzdCx3aWR0aCkKICAgIHwgb3RoZXJ3aXNlICAgPSAoMS41NiAgLCAwLjQwMDApIAoKIC0tIGVzdHZhbChuKSA9IGxvZyAoTVtuXSkgPSBsbjIgKiBsb2dCYXNlIDIgKE1bbl0pCi19Cnd3ID0gbG9nQmFzZSAyIDMwIC8gMgotLSBsYjMgOjogRG91YmxlCmxiMyA9IGxvZ0Jhc2UgMiAzOyAgbGI1ID0gbG9nQmFzZSAyIDUgICAtLSBsYjMgPT0gbG9nIDMvbG9nIDIsICBsYjUgPT0gbG9nIDUvbG9nIDIKLS0gbG9ndmFsMiA6OiAoSW50LEludCxJbnQpIC0+IERvdWJsZQpsb2d2YWwyIChpLGosaykgICAgPSBmcm9tSW50ZWdyYWwgaSArIGZyb21JbnRlZ3JhbCBqKmxiMyArIGZyb21JbnRlZ3JhbCBrKmxiNQotLSBlc3R2YWwyIDo6IEludGVnZXIgLT4gRG91YmxlCmVzdHZhbDIgbiAgICAgICAgICA9ICg2KmxiMypsYjUqIGZyb21JbnRlZ3JhbCBuKSoqKDEvMykgIC0tIGVzdGltYXRlZCBsb2d2YWwgKipCYXNlIDIqKgpybmd2YWwyIG4gICAgICAgICAgIC0tICAtMS92ICAgICAgICAgICsyL3YgICAgICBzZWVtcyB0byB3b3JrcyB0b28KICAgIHwgbiA+IDUwMDAwMCAgPSAod3ctKDMvZXN0dmFsMiBuKSwgNi9lc3R2YWwyIG4pICAgICAgLS0gc3BhY2UgdHdlYWsgISEhICh0aHgsIEdCRyEpCiAgICB8IG4gPiA1MDAwMDAgID0gKDIuNDQ5NiAsIDAuMDA3NiApICAgICAgICAgICAgICAgICAgICAgICAgICAtLSBlbXBpcmljYWwKICAgIHwgbiA+IDUwMDAwICAgPSAoMi40NDI0ICwgMC4wMTQ2ICkgICAgICAgICAgICAgICAgICAgICAgICAgIC0tICBlc3RpbWF0aW9uCiAgICB8IG4gPiA1MDAgICAgID0gKDIuMzk0OCAsIDAuMDcyMyApICAgICAgICAgICAgICAgICAgICAgICAgICAtLSAgIGNvcnJlY3Rpb24gLSBiYXNlIDIKICAgIHwgbiA+IDEgICAgICAgPSAoMi4yNTA2ICwgMC4yODg3ICkgICAgICAgICAgICAgICAgICAgICAgICAgIC0tICAgIChkaXN0LHdpZHRoKQogICAgfCBvdGhlcndpc2UgICA9ICgyLjI1MDYgLCAwLjU3NzEgKSAgCiAKLS0gbnRoSGFtIDo6IEludGVnZXIgLT4gKCAoSW50LEludCksIChEb3VibGUsIChJbnQsIEludCwgSW50KSkpICAtLSAoIDY0LWJpdHM6IHVzZSBJbnQhISAgICBOQiEgKQotLSAgICAgICAgICAgICAgICAgICAgX2JhbmQgc2l6ZSBzdHVmZl8gIC0tICgqMSopCgpudGhIYW0gOjogSW50ZWdlciAtPiAoIChCb29sLCBEb3VibGUsIERvdWJsZSksIChEb3VibGUsIChJbnQsIEludCwgSW50KSkpCi0tICAgICAgICAgICAgICAgICAgICAgICBfbWF4IGxvZ3ZhbCwgbWluIGRlbHRhIGluIGJhbmRfCm50aEhhbSBuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLS0gbjogMS1iYXNlZCAxLDIsMy4uLgogIHwgdyA+PSAxICAgPSBlcnJvciAkICJCcmVhY2ggb2YgY29udHJhY3Q6ICh3IDwgMSk6ICAiICsrIHNob3cgKHcpCiAgfCBtIDwgIDAgICA9IGVycm9yICQgIk5vdCBlbm91Z2ggdHJpcGxlcyBnZW5lcmF0ZWQ6ICIgKysgc2hvdyAoYyxuKQogIHwgbSA+PSBuYiAgPSBlcnJvciAkICJHZW5lcmF0ZWQgYmFuZCBpcyB0b28gbmFycm93OiAiICsrIHNob3cgKG0sbmIpCiAgfCBUcnVlICAgICA9IC0tICgobSxuYikscmVzKSAtLSBtPXRhcmdldCBpbmRleCBpbiBiYW5kIGZyb20gdG9wLCBuYj1iYW5kJ3MgbGVuZ3RoICAKICAgICAgICAgICAgICAgKCAoIGlzVHJ1bHlTb3J0ZWQgLAogICAgICAgICAgICAgICAgICAgZnN0IChoZWFkIHMpLCAgICAgICAgIC0tICgqMSopCiAgICAgICAgICAgICAgICAgICAgICBtaW5pbXVtIC0tIEJ5IChjb21wYXJlIGBvbmAgYWJzKQogICAgICAgICAgICAgICAgICAgICAgICAgKHppcFdpdGggKC0pIChtYXAgZnN0IHMpICh0YWlsIChtYXAgZnN0IHMpKSkgKQogICAgICAgICAgICAgICAgICwgcmVzKQogd2hlcmUgCiAgaXNUcnVseVNvcnRlZCA9IGFuZCBbYT5iIHwgbGV0IHo9bWFwICh0cml2YWwuc25kKSBzLCAoYSxiKTwtemlwIHogKHRhaWwgeildCiAgKGQsdykgICA9IHJuZ3ZhbDIgbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLS0gY29ycmVjdGlvbiBkaXN0LCB3aWR0aAogIGhpICAgICAgPSBlc3R2YWwyIG4gLSBkICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0tICAgaGkgPiBsb2d2YWwyID4gaGktdyAKICAoYyxiKSAgID0gZm9sZGxfICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtLSB0b3RhbCBjb3VudCwgdGhlIGJhbmQKICAgICAgICAgICAgIChcKCFjLCFiKSAoaSx0KSAtPiBjYXNlIHQgb2YgW10gLT4gKGkrYyxiKSAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFt4XSAtPiAoaStjLHg6YikpIAogICAgICAgICAgICAgKDA6OkludGVnZXIsW10pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0tICggNjRiaXQ6IHVzZSBJbnQhISEgICAgIE5CISApIAogICAgICAgICAgICAgLS0gKHN1bSAqKiogY29uY2F0KSAuIHVuemlwICQKICAgICAgICAgICAgIFsgKCBmcm9tSW50ZWdyYWwgaSsxLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAtLSB0b3RhbCB0cmlwbGVzIHcvIHRoaXMgKGosaykKICAgICAgICAgICAgICAgICBbIChyLChpLGosaykpIHwgZnJhYyA8IHcgXSApICAgICAgICAgICAgICAgICAtLSBzdG9yZSBpdCwgaWYgaW5zaWRlIGJhbmQKICAgICAgICAgICAgICAgfCBrIDwtIFsgMCAuLiBmbG9vciAoIGhpICAgL2xiNSkgXSwgIGxldCBwID0gZnJvbUludGVncmFsIGsqbGI1LCAgICAKICAgICAgICAgICAgICAgICBqIDwtIFsgMCAuLiBmbG9vciAoKGhpLXApL2xiMykgXSwgIGxldCBxID0gZnJvbUludGVncmFsIGoqbGIzICsgcCwKICAgICAgICAgICAgICAgICBsZXQgKGksZnJhYykgPSBwciAgKGhpLXEpIDsgICAgICAgICAgICByID0gaGkgLSBmcmFjICAtLSByID0gaSArIHEgCiAgICAgICAgICAgICAgIF0gd2hlcmUgICAgIHByID0gcHJvcGVyRnJhY3Rpb24gICAgICAgICAgICAgICAgLS0gcHIgMS4yNCA9PiAoMSwwLjI0KQogIChtLG5iKSAgPSAoIGZyb21JbnRlZ3JhbCAkIGMgLSBuLCBsZW5ndGggYiApICAgICAgICAgICAgICAgIC0tIG0gMC1iYXNlZCBmcm9tIHRvcCwgfGJhbmR8CiAgKHMscmVzKSA9ICggc29ydEJ5IChmbGlwIGNvbXBhcmUgYG9uYCBmc3QpIGIsIHMhIW0gKSAgICAgICAgLS0gc29ydGVkIGRlY3JlYXNpbmcsIHJlc3VsdAogIGZvbGRsXyAgPSBmb2xkbCc=