2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,12 +1,20 @@
|
|||
'''[[wp:Hamming numbers|Hamming numbers]]''' are numbers of the form
|
||||
: <math>H = 2^i \cdot 3^j \cdot 5^k, \; \mathrm{where} \; i, j, k \geq 0</math>.
|
||||
''Hamming numbers'' are also known as ''ugly numbers'' and also ''5-smooth numbers'' (numbers whose prime divisors are less or equal to 5).
|
||||
'''[[wp:Hamming numbers|Hamming numbers]]''' are numbers of the form
|
||||
<big><big> H = 2<sup>i</sup> × 3<sup>j</sup> × 5<sup>k</sup> </big></big>
|
||||
where
|
||||
<big> i, j, k ≥ 0 </big>
|
||||
|
||||
Generate the sequence of Hamming numbers, ''in increasing order''. In particular:
|
||||
# Show the first twenty Hamming numbers.
|
||||
# Show the 1691st Hamming number (the last one below <math>2^{31}</math>).
|
||||
# Show the one millionth Hamming number (if the language – or a convenient library – supports arbitrary-precision integers).
|
||||
'''References'''
|
||||
# [[wp:Hamming numbers|Hamming numbers]]
|
||||
# [[wp:Smooth number|Smooth number]]
|
||||
# [http://dobbscodetalk.com/index.php?option=com_content&task=view&id=913&Itemid=85 Hamming problem] from Dr. Dobb's CodeTalk (dead link as of Sep 2011; parts of the thread [http://drdobbs.com/blogs/architecture-and-design/228700538 here] and [http://www.jsoftware.com/jwiki/Essays/Hamming%20Number here]).
|
||||
''Hamming numbers'' are also known as ''ugly numbers'' and also ''5-smooth numbers'' (numbers whose prime divisors are less or equal to 5).
|
||||
|
||||
|
||||
;Task:
|
||||
Generate the sequence of Hamming numbers, ''in increasing order''. In particular:
|
||||
# Show the first twenty Hamming numbers.
|
||||
# Show the 1691<sup>st</sup> Hamming number (the last one below 2<sup>31</sup>).
|
||||
# Show the one million<sup>th</sup> Hamming number (if the language – or a convenient library – supports arbitrary-precision integers).
|
||||
|
||||
|
||||
;References:
|
||||
* [[wp:Hamming numbers|Hamming numbers]]
|
||||
* [[wp:Smooth number|Smooth number]]
|
||||
* [http://dobbscodetalk.com/index.php?option=com_content&task=view&id=913&Itemid=85 Hamming problem] from Dr. Dobb's CodeTalk (dead link as of Sep 2011; parts of the thread [http://drdobbs.com/blogs/architecture-and-design/228700538 here] and [http://www.jsoftware.com/jwiki/Essays/Hamming%20Number here]).
|
||||
<br><br>
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
"Computes the unbounded sequence of Hamming 235 numbers."
|
||||
[]
|
||||
(letfn [(merge [xs ys]
|
||||
(let [xv (first xs), yv (first ys)]
|
||||
(if (< xv yv) (cons xv (lazy-seq (merge (next xs) ys)))
|
||||
(cons yv (lazy-seq (merge xs (next ys))))))),
|
||||
(if (nil? xs) ys
|
||||
(let [xv (first xs), yv (first ys)]
|
||||
(if (< xv yv) (cons xv (lazy-seq (merge (next xs) ys)))
|
||||
(cons yv (lazy-seq (merge xs (next ys)))))))),
|
||||
(smult [m s] ;; equiv to map (* m) s -- faster
|
||||
(cons (*' m (first s)) (lazy-seq (smult m (next s)))))]
|
||||
(do (def s5 (cons 5 (lazy-seq (smult 5 s5))))
|
||||
(def s35 (cons 3 (lazy-seq (merge s5 (smult 3 s35)))))
|
||||
(def s235 (cons 2 (lazy-seq (merge s35 (smult 2 s235)))))
|
||||
(cons 1 (lazy-seq s235)))))
|
||||
(cons (*' m (first s)) (lazy-seq (smult m (next s))))),
|
||||
(u [s n] (let [r (atom nil)]
|
||||
(reset! r (merge s (smult n (cons 1 (lazy-seq @r)))))))]
|
||||
(cons 1 (lazy-seq (reduce u nil (list 5 3 2))))))
|
||||
|
|
|
|||
110
Task/Hamming-numbers/Go/hamming-numbers-3.go
Normal file
110
Task/Hamming-numbers/Go/hamming-numbers-3.go
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
// Hamming project main.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
type lazyList struct {
|
||||
head *big.Int
|
||||
tail *lazyList
|
||||
contf func() *lazyList
|
||||
}
|
||||
|
||||
func (oll *lazyList) next() *lazyList {
|
||||
if oll.contf != nil { // not thread-safe
|
||||
oll.tail = oll.contf()
|
||||
oll.contf = nil
|
||||
}
|
||||
return oll.tail
|
||||
}
|
||||
|
||||
func merge(a *lazyList, b *lazyList) *lazyList {
|
||||
rslt := new(lazyList)
|
||||
x := a.head
|
||||
y := b.head
|
||||
if x.Cmp(y) < 0 {
|
||||
rslt.head = x
|
||||
rslt.contf = func() *lazyList {
|
||||
return merge(a.next(), b)
|
||||
}
|
||||
} else {
|
||||
rslt.head = y
|
||||
rslt.contf = func() *lazyList {
|
||||
return merge(a, b.next())
|
||||
}
|
||||
}
|
||||
return rslt
|
||||
}
|
||||
|
||||
func llmult(m *big.Int, ll *lazyList) *lazyList {
|
||||
rslt := new(lazyList)
|
||||
rslt.head = new(big.Int).Set(big.NewInt(0)).Mul(m, ll.head)
|
||||
rslt.contf = func() *lazyList {
|
||||
return llmult(m, ll.next())
|
||||
}
|
||||
return rslt
|
||||
}
|
||||
|
||||
func u(s *lazyList, n *big.Int) *lazyList {
|
||||
rslt := new(lazyList)
|
||||
cr := new(lazyList)
|
||||
cr.head = big.NewInt(1)
|
||||
cr.contf = func() *lazyList {
|
||||
return rslt
|
||||
}
|
||||
if s == nil {
|
||||
rslt = llmult(n, cr)
|
||||
} else {
|
||||
rslt = merge(s, llmult(n, cr))
|
||||
}
|
||||
return rslt
|
||||
}
|
||||
|
||||
func Hamming() func() *big.Int {
|
||||
prms := []int64{5, 3, 2}
|
||||
curr := new(lazyList)
|
||||
curr.head = big.NewInt(1)
|
||||
curr.contf = func() *lazyList {
|
||||
var r *lazyList = nil
|
||||
for _, v := range prms {
|
||||
r = u(r, big.NewInt(v))
|
||||
}
|
||||
return r
|
||||
}
|
||||
return func() *big.Int {
|
||||
temp := curr
|
||||
curr = curr.next()
|
||||
return temp.head
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
n := 1000000
|
||||
|
||||
hamiter := Hamming()
|
||||
rarr := make([]*big.Int, 20)
|
||||
for i, _ := range rarr {
|
||||
rarr[i] = hamiter()
|
||||
}
|
||||
fmt.Println(rarr)
|
||||
|
||||
hamiter = Hamming()
|
||||
for i := 1; i < 1691; i++ {
|
||||
hamiter()
|
||||
}
|
||||
fmt.Println(hamiter())
|
||||
|
||||
strt := time.Now()
|
||||
|
||||
hamiter = Hamming()
|
||||
for i := 1; i < n; i++ {
|
||||
hamiter()
|
||||
}
|
||||
rslt := hamiter()
|
||||
|
||||
end := time.Now()
|
||||
fmt.Printf("Found the %vth Hamming number as %v in %v.\r\n", n, rslt.String(), end.Sub(strt))
|
||||
}
|
||||
148
Task/Hamming-numbers/Go/hamming-numbers-4.go
Normal file
148
Task/Hamming-numbers/Go/hamming-numbers-4.go
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
// constants as expanded integers to minimize round-off errors, and
|
||||
// reduce execution time using integer operations not float...
|
||||
const cLAA2 uint64 = 35184372088832 // 2.0f64.ln() * 2.0f64.powi(45)).round() as u64;
|
||||
const cLBA2 uint64 = 55765910372219 // 3.0f64.ln() / 2.0f64.ln() * 2.0f64.powi(45)).round() as u64;
|
||||
const cLCA2 uint64 = 81695582054030 // 5.0f64.ln() / 2.0f64.ln() * 2.0f64.powi(45)).round() as u64;
|
||||
|
||||
type logelm struct { // log representation of an element with only allowable powers
|
||||
exp2 uint16
|
||||
exp3 uint16
|
||||
exp5 uint16
|
||||
logr uint64 // log representation used for comparison only - not exact
|
||||
}
|
||||
|
||||
func (self *logelm) lte(othr *logelm) bool {
|
||||
if self.logr <= othr.logr {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
func (self *logelm) mul2() logelm {
|
||||
return logelm{
|
||||
exp2: self.exp2 + 1,
|
||||
exp3: self.exp3,
|
||||
exp5: self.exp5,
|
||||
logr: self.logr + cLAA2,
|
||||
}
|
||||
}
|
||||
func (self *logelm) mul3() logelm {
|
||||
return logelm{
|
||||
exp2: self.exp2,
|
||||
exp3: self.exp3 + 1,
|
||||
exp5: self.exp5,
|
||||
logr: self.logr + cLBA2,
|
||||
}
|
||||
}
|
||||
func (self *logelm) mul5() logelm {
|
||||
return logelm{
|
||||
exp2: self.exp2,
|
||||
exp3: self.exp3,
|
||||
exp5: self.exp5 + 1,
|
||||
logr: self.logr + cLCA2,
|
||||
}
|
||||
}
|
||||
|
||||
func log_nodups_hamming(n uint) *big.Int {
|
||||
if n < 1 {
|
||||
panic("log_nodups_hamming: argument < 1!")
|
||||
}
|
||||
if n < 2 { // trivial case of first in sequence
|
||||
return big.NewInt(1)
|
||||
}
|
||||
if n > 1.2e15 {
|
||||
panic("log_nodups_hamming: argument too large!")
|
||||
}
|
||||
|
||||
one := logelm{}
|
||||
next5, merge := one.mul5(), one.mul3()
|
||||
next53, next532 := merge.mul3(), one.mul2()
|
||||
|
||||
g := make([]logelm, 1, 65536)
|
||||
g[0] = one // never used, just so append works
|
||||
h := make([]logelm, 1, 65536)
|
||||
h[0] = one // never used, just so append works
|
||||
|
||||
i, j := 1, 1
|
||||
for m := uint(1); m < n; m++ {
|
||||
cph := cap(h)
|
||||
if i >= cph/2 {
|
||||
nm := copy(h[0:i], h[i:])
|
||||
h = h[0:nm:cph]
|
||||
i = 0
|
||||
}
|
||||
if next532.lte(&merge) {
|
||||
h = append(h, next532)
|
||||
next532 = h[i].mul2()
|
||||
i++
|
||||
} else {
|
||||
h = append(h, merge)
|
||||
if next53.lte(&next5) {
|
||||
merge = next53
|
||||
next53 = g[j].mul3()
|
||||
j++
|
||||
} else {
|
||||
merge = next5
|
||||
next5 = next5.mul5()
|
||||
}
|
||||
cpg := cap(g)
|
||||
if j >= cpg/2 {
|
||||
nm := copy(g[0:j], g[j:])
|
||||
g = g[0:nm:cpg]
|
||||
j = 0
|
||||
}
|
||||
g = append(g, merge)
|
||||
}
|
||||
}
|
||||
|
||||
two, three, five := big.NewInt(2), big.NewInt(3), big.NewInt(5)
|
||||
o := h[len(h)-1] // convert last element to big integer...
|
||||
ob := big.NewInt(1)
|
||||
for i := uint16(0); i < o.exp2; i++ {
|
||||
ob.Mul(two, ob)
|
||||
}
|
||||
for i := uint16(0); i < o.exp3; i++ {
|
||||
ob.Mul(three, ob)
|
||||
}
|
||||
for i := uint16(0); i < o.exp5; i++ {
|
||||
ob.Mul(five, ob)
|
||||
}
|
||||
return ob
|
||||
}
|
||||
|
||||
func main() {
|
||||
n := uint(1e6)
|
||||
|
||||
rarr := make([]*big.Int, 20)
|
||||
for i, _ := range rarr {
|
||||
rarr[i] = log_nodumps_hamming(i)
|
||||
}
|
||||
fmt.Println(rarr)
|
||||
|
||||
fmt.Println(log_nodups_hamming(1691))
|
||||
|
||||
strt := time.Now()
|
||||
|
||||
rslt := log_nodups_hamming(n)
|
||||
|
||||
end := time.Now()
|
||||
|
||||
rs := rslt.String()
|
||||
lrs := len(rs)
|
||||
fmt.Printf("%v digits:\r\n", lrs)
|
||||
ndx := 0
|
||||
for ; ndx < lrs-100; ndx += 100 {
|
||||
fmt.Println(rs[ndx : ndx+100])
|
||||
}
|
||||
fmt.Println(rs[ndx:])
|
||||
|
||||
fmt.Printf("This last found the %vth hamming number in %v.\r\n", n, end.Sub(strt))
|
||||
}
|
||||
122
Task/Hamming-numbers/Go/hamming-numbers-5.go
Normal file
122
Task/Hamming-numbers/Go/hamming-numbers-5.go
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
type logrep struct {
|
||||
lg float64
|
||||
x2, x3, x5 uint32
|
||||
}
|
||||
type logreps []logrep
|
||||
func (s logreps) Len() int { // necessary methods for sorting
|
||||
return len(s)
|
||||
}
|
||||
func (s logreps) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
func (s logreps) Less(i, j int) bool {
|
||||
return s[j].lg < s[i].lg // sort in decreasing order (reverse order compare)
|
||||
}
|
||||
|
||||
func nthHamming(n uint64) (uint32, uint32, uint32) {
|
||||
if n < 2 {
|
||||
if n < 1 {
|
||||
panic("nthHamming: argument is zero!")
|
||||
}
|
||||
return 0, 0, 0
|
||||
}
|
||||
const lb3 = 1.5849625007211561814537389439478 // math.Log2(3.0)
|
||||
const lb5 = 2.3219280948873623478703194294894 // math.Log2(5.0)
|
||||
fctr := 6.0 * lb3 * lb5
|
||||
crctn := math.Log2(math.Sqrt(30.0)) // from WP formula
|
||||
lgest := math.Pow(fctr*float64(n), 1.0/3.0) - crctn
|
||||
var frctn float64
|
||||
if n < 1000000000 {
|
||||
frctn = 0.509
|
||||
} else {
|
||||
frctn = 0.106
|
||||
}
|
||||
lghi := math.Pow(fctr*(float64(n)+frctn*lgest), 1.0/3.0) - crctn
|
||||
lglo := 2.0*lgest - lghi // and a lower limit of the upper "band"
|
||||
var count uint64 = 0
|
||||
bnd := make(logreps, 0) // give it one value so doubling size works
|
||||
klmt := uint32(lghi/lb5) + 1
|
||||
for k := uint32(0); k < klmt; k++ {
|
||||
p := float64(k) * lb5
|
||||
jlmt := uint32((lghi-p)/lb3) + 1
|
||||
for j := uint32(0); j < jlmt; j++ {
|
||||
q := p + float64(j)*lb3
|
||||
ir := lghi - q
|
||||
lg := q + math.Floor(ir) // current log value estimated
|
||||
count += uint64(ir) + 1
|
||||
if lg >= lglo {
|
||||
bnd = append(bnd, logrep{lg, uint32(ir), j, k})
|
||||
}
|
||||
}
|
||||
}
|
||||
if n > count {
|
||||
panic("nthHamming: band high estimate is too low!")
|
||||
}
|
||||
ndx := int(count - n)
|
||||
if ndx >= bnd.Len() {
|
||||
panic("nthHamming: band low estimate is too high!")
|
||||
}
|
||||
sort.Sort(bnd) // sort decreasing order due definition of Less above
|
||||
|
||||
rslt := bnd[ndx]
|
||||
return rslt.x2, rslt.x3, rslt.x5
|
||||
}
|
||||
|
||||
func convertTpl2BigInt(x2, x3, x5 uint32) *big.Int {
|
||||
result := big.NewInt(1)
|
||||
two := big.NewInt(2)
|
||||
three := big.NewInt(3)
|
||||
five := big.NewInt(5)
|
||||
for i := uint32(0); i < x2; i++ {
|
||||
result.Mul(result, two)
|
||||
}
|
||||
for i := uint32(0); i < x3; i++ {
|
||||
result.Mul(result, three)
|
||||
}
|
||||
for i := uint32(0); i < x5; i++ {
|
||||
result.Mul(result, five)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func main() {
|
||||
for i := 1; i <= 20; i++ {
|
||||
fmt.Printf("%v ", convertTpl2BigInt(nthHamming(uint64(i))))
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Println(convertTpl2BigInt(nthHamming(1691)))
|
||||
|
||||
strt := time.Now()
|
||||
x2, x3, x5 := nthHamming(uint64(1e6))
|
||||
end := time.Now()
|
||||
|
||||
fmt.Printf("2^%v times 3^%v times 5^%v\r\n", x2, x3, x5)
|
||||
lrslt := convertTpl2BigInt(x2, x3, x5)
|
||||
lgrslt := (float64(x2) + math.Log2(3.0)*float64(x3) +
|
||||
math.Log2(5.0)*float64(x5)) * math.Log10(2.0)
|
||||
exp := math.Floor(lgrslt)
|
||||
mant := math.Pow(10.0, lgrslt-exp)
|
||||
fmt.Printf("Approximately: %vE+%v\r\n", mant, exp)
|
||||
rs := lrslt.String()
|
||||
lrs := len(rs)
|
||||
fmt.Printf("%v digits:\r\n", lrs)
|
||||
if lrs <= 10000 {
|
||||
ndx := 0
|
||||
for ; ndx < lrs-100; ndx += 100 {
|
||||
fmt.Println(rs[ndx : ndx+100])
|
||||
}
|
||||
fmt.Println(rs[ndx:])
|
||||
}
|
||||
|
||||
fmt.Printf("This last found the %vth hamming number in %v.\r\n", n, end.Sub(strt))
|
||||
}
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
hamming = 1:foldl u [] [5,3,2] where
|
||||
u s n = ar where
|
||||
ar = merge s (n:map (n*) ar)
|
||||
merge [] b = b
|
||||
merge a@(x:xs) b@(y:ys)
|
||||
| x < y = x:merge xs b
|
||||
| otherwise = y:merge a ys
|
||||
hamming = 1 : foldr u [] [2,3,5] where
|
||||
u n s = -- fix (merge s . map (n*) . (1:))
|
||||
r where
|
||||
r = merge s (map (n*) (1:r))
|
||||
|
||||
merge [] b = b
|
||||
merge a@(x:xs) b@(y:ys) | x < y = x : merge xs b
|
||||
| otherwise = y : merge a ys
|
||||
|
||||
main = do
|
||||
print $ take 20 hamming
|
||||
print $ hamming !! 1690
|
||||
print $ hamming !! (1000000-1)
|
||||
print $ take 20 (hamming ())
|
||||
print $ (hamming ()) !! 1690
|
||||
print $ (hamming ()) !! (1000000-1)
|
||||
|
|
|
|||
|
|
@ -1,44 +1,40 @@
|
|||
-- directly find n-th Hamming number, in ~ O(n^{2/3}) time
|
||||
-- by Will Ness, based on "top band" idea by Louis Klauder, from DDJ discussion
|
||||
-- http://drdobbs.com/blogs/architecture-and-design/228700538
|
||||
-- based on "top band" idea by Louis Klauder, from DDJ discussion
|
||||
-- by Will Ness, original post: drdobbs.com/blogs/architecture-and-design/228700538
|
||||
|
||||
{-# OPTIONS -O2 -XBangPatterns #-}
|
||||
import Data.List (sortBy)
|
||||
import Data.Function (on)
|
||||
import Data.List
|
||||
import Data.Function
|
||||
|
||||
main = let (r,t) = nthHam 1000000 in print t >> print (trival t)
|
||||
|
||||
lg3 = logBase 2 3; lg5 = logBase 2 5
|
||||
logval (i,j,k) = fromIntegral i + fromIntegral j*lg3 + fromIntegral k*lg5
|
||||
lb3 = logBase 2 3; lb5 = logBase 2 5; lb30_2 = logBase 2 30 / 2
|
||||
trival (i,j,k) = 2^i * 3^j * 5^k
|
||||
estval n = (6*lg3*lg5* fromIntegral n)**(1/3) -- estimated logval, base 2
|
||||
rngval n
|
||||
| n > 500000 = (2.4496 , 0.0076 ) -- empirical estimation
|
||||
| n > 50000 = (2.4424 , 0.0146 ) -- correction, base 2
|
||||
| n > 500 = (2.3948 , 0.0723 ) -- (dist,width)
|
||||
| n > 1 = (2.2506 , 0.2887 ) -- around (log $ sqrt 30),
|
||||
| otherwise = (2.2506 , 0.5771 ) -- says WP
|
||||
estval n
|
||||
| n > 500000 = (v - lb30_2 + (3/v), 6/v) -- the space tweak! (thx, GBG!)
|
||||
| n > 500000 = (v - 2.4496 , 0.0076 ) -- empirical estimation
|
||||
| n > 50000 = (v - 2.4424 , 0.0146 ) -- correction, base 2
|
||||
| n > 500 = (v - 2.3948 , 0.0723 ) -- (dist,width)
|
||||
| n > 1 = (v - 2.2506 , 0.2887 ) -- around (log $ sqrt 30),
|
||||
| otherwise = (v - 2.2506 , 0.5771 ) -- says WP
|
||||
where v = (6*lb3*lb5* fromIntegral n)**(1/3) -- estimated logval, base 2
|
||||
|
||||
nthHam :: Int -> (Double, (Int, Int, Int))
|
||||
nthHam n -- n: 1-based: 1,2,3...
|
||||
nthHam :: Integer -> (Double, (Int, Int, Int)) -- ( 64bit: use Int!!! NB! )
|
||||
nthHam n -- n: 1-based: 1,2,3...
|
||||
| n <= 0 = error $ "n is 1--based: must be n > 0: " ++ show n
|
||||
| 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)
|
||||
| otherwise = res
|
||||
| otherwise = sortBy (flip compare `on` fst) b !! m -- m-th from top in sorted band
|
||||
where
|
||||
(d,w) = rngval n -- correction dist, width
|
||||
hi = estval n - d -- hi > logval > hi-w
|
||||
(m,nb) = ( fromIntegral $ c - n, length b ) -- m 0-based from top, |band|
|
||||
(s,res) = ( sortBy (flip compare `on` fst) b, s!!m ) -- sorted decreasing, result
|
||||
(c,b) = f 0 -- total count, the band
|
||||
[ ( i+1, -- total triples w/ this (j,k)
|
||||
[ (r,(i,j,k)) | frac < w ] ) -- store it, if inside band
|
||||
| k <- [ 0 .. floor ( hi /lg5) ], let p = fromIntegral k*lg5,
|
||||
j <- [ 0 .. floor ((hi-p)/lg3) ], let q = fromIntegral j*lg3 + p,
|
||||
let (i,frac) = pr (hi-q) ; r = hi-frac ] -- r = i + q
|
||||
-- f 0 z == (sum $ map fst z, concat $ map snd z)
|
||||
where pr = properFraction
|
||||
f !c [] = (c,[]) -- code as a loop
|
||||
f !c ((c1,b1):r) = let (cr,br) = f (c+c1) r -- to prevent space leak
|
||||
in case b1 of { [v] -> (cr,v:br)
|
||||
; _ -> (cr, br) }
|
||||
(hi,w) = estval n -- hi > logval > hi-w
|
||||
m = fromIntegral (c - n) -- target index, from top
|
||||
nb = length b -- length of the band
|
||||
(c,b) = foldl_ (\(c,b) (i,t)-> let c2=c+i in c2`seq` -- ( total count, the band )
|
||||
case t of []-> (c2,b);[v]->(c2,v:b) ) (0,[]) -- ( =~= mconcat )
|
||||
[ ( fromIntegral i+1, -- total triples w/ this (j,k)
|
||||
[ (r,(i,j,k)) | frac < w ] ) -- store it, if inside band
|
||||
| k <- [ 0 .. floor ( hi /lb5) ], let p = fromIntegral k*lb5,
|
||||
j <- [ 0 .. floor ((hi-p)/lb3) ], let q = fromIntegral j*lb3 + p,
|
||||
let (i,frac) = pr (hi-q) ; r = hi - frac -- r = i + q
|
||||
] where pr = properFraction -- pr 1.24 => (1,0.24)
|
||||
foldl_ = foldl'
|
||||
|
|
|
|||
43
Task/Hamming-numbers/Haskell/hamming-numbers-6.hs
Normal file
43
Task/Hamming-numbers/Haskell/hamming-numbers-6.hs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{-# OPTIONS -O2 -XBangPatterns #-}
|
||||
|
||||
import Data.Word
|
||||
import Data.List (sortBy)
|
||||
import Data.Function (on)
|
||||
|
||||
main = let t = nthHam 1000000000000 in print t >> print (trival t)
|
||||
|
||||
lb3 = logBase 2 3; lb5 = logBase 2 5
|
||||
lbrt30 = logBase 2 $ sqrt 30 :: Double -- estimate adjustment as per WP
|
||||
trival (i,j,k) = 2^i * 3^j * 5^k
|
||||
estval2 n = (6*lb3*lb5*n)**(1/3) - lbrt30 -- estimated logval, base 2
|
||||
crctn n
|
||||
| n < 1000 = 0.509 -- empirical correction terms
|
||||
| n < 1000000 = 0.206
|
||||
| n < 1000000000 = 0.122 -- further divisions have little effect as already small
|
||||
| otherwise = 0.105 -- very slowly decrease from this point for a billion
|
||||
|
||||
nthHam :: Word64 -> (Int, Int, Int)
|
||||
nthHam n -- n: 1-based 1,2,3...
|
||||
| n < 2 = case n of
|
||||
0 -> error "nthHam: Argument is zero!"
|
||||
_ -> (0, 0, 0) -- trivial case for 1
|
||||
| m < 0 = error $ "Not enough triples generated: " ++ show (c,n)
|
||||
| m >= nb = error $ "Generated band is too narrow: " ++ show (m,nb)
|
||||
| otherwise = case res of (_, tv) -> tv -- 2^i * 3^j * 5^k
|
||||
where
|
||||
(fr,est)= (crctn n, estval2 $ fromIntegral n) -- fraction of log2 error, est val
|
||||
(hi,lo) = (estval2 (fromIntegral n + fr*est), 2*est-hi) -- hi > logval2 > hi-w
|
||||
(c,b) = let klmt = floor (hi/lb5) in
|
||||
let loopk k !ck bndk =
|
||||
if k > klmt then (ck, bndk) else
|
||||
let p = fromIntegral k*lb5; jlmt = floor ((hi-p)/lb3) in
|
||||
let loopj j !cj bndj =
|
||||
if j > jlmt then loopk (k+1) cj bndj else
|
||||
let q = fromIntegral j*lb3 + p in
|
||||
let (i, frac) = properFraction (hi-q); r = hi-frac in
|
||||
if r < lo then loopj (j+1) (fromIntegral i+cj+1) bndj else
|
||||
loopj (j+1) (fromIntegral i+cj+1) ((r,(i,j,k)):bndj) in
|
||||
loopj 0 ck bndk in
|
||||
loopk 0 0 []
|
||||
(m,nb) = ( fromIntegral $ c - n, length b ) -- m 0-based from top, |band|
|
||||
(s,res) = ( sortBy (flip compare `on` fst) b, s!!m ) -- sorted decreasing, result<
|
||||
|
|
@ -5,15 +5,15 @@ val One = BigInteger.ONE
|
|||
val Three = BigInteger.valueOf(3)
|
||||
val Five = BigInteger.valueOf(5)
|
||||
|
||||
fun PriorityQueue<BigInteger>.update(x: BigInteger) {
|
||||
add(x shiftLeft(1))
|
||||
add(x multiply(Three))
|
||||
add(x multiply(Five))
|
||||
fun PriorityQueue<BigInteger>.update(x: BigInteger) : PriorityQueue<BigInteger> {
|
||||
add(x.shiftLeft(1))
|
||||
add(x.multiply(Three))
|
||||
add(x.multiply(Five))
|
||||
return this
|
||||
}
|
||||
|
||||
fun hamming(n: Int): BigInteger {
|
||||
val frontier = PriorityQueue<BigInteger>()
|
||||
frontier.update(One)
|
||||
val frontier = PriorityQueue<BigInteger>().update(One)
|
||||
var lowest = One
|
||||
repeat(n - 1) {
|
||||
lowest = frontier.poll() ?: lowest
|
||||
|
|
@ -29,5 +29,5 @@ fun hamming(i : Iterable<Int>) : Iterable<BigInteger> = i.map { hamming(it) }
|
|||
fun main(args: Array<String>) {
|
||||
val r = 1..20
|
||||
println("Hamming($r) = " + hamming(r))
|
||||
arrayOf(1691, 1000000).forEach { println("Hamming(${it}) = " + hamming(it)) }
|
||||
arrayOf(1691, 1000000).forEach { println("Hamming($it) = " + hamming(it)) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@ val One = BigInteger.ONE
|
|||
val Three = BigInteger.valueOf(3)
|
||||
val Five = BigInteger.valueOf(5)
|
||||
|
||||
fun PriorityQueue<BigInteger>.update(x: BigInteger) {
|
||||
add(x shiftLeft 1)
|
||||
add(x multiply Three)
|
||||
add(x multiply Five)
|
||||
infix fun PriorityQueue<BigInteger>.update(x: BigInteger) : PriorityQueue<BigInteger> {
|
||||
add(x.shiftLeft(1))
|
||||
add(x.multiply(Three))
|
||||
add(x.multiply(Five))
|
||||
return this
|
||||
}
|
||||
|
||||
fun hamming(a: Any?): Any = when (a) {
|
||||
is Number -> {
|
||||
val pq = PriorityQueue<BigInteger>()
|
||||
pq update One
|
||||
val pq = PriorityQueue<BigInteger>() update One
|
||||
var lowest = One
|
||||
repeat(a.toInt() - 1) {
|
||||
lowest = pq.poll() ?: lowest
|
||||
|
|
|
|||
48
Task/Hamming-numbers/Kotlin/hamming-numbers-4.kotlin
Normal file
48
Task/Hamming-numbers/Kotlin/hamming-numbers-4.kotlin
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import java.math.BigInteger as BI
|
||||
|
||||
data class LazyList<T>(val head: T, val lztail: Lazy<LazyList<T>?>) {
|
||||
fun toSequence() = generateSequence(this) { it.lztail.value }
|
||||
.map { it.head }
|
||||
}
|
||||
|
||||
fun hamming(): LazyList<BI> {
|
||||
fun merge(s1: LazyList<BI>, s2: LazyList<BI>): LazyList<BI> {
|
||||
val s1v = s1.head; val s2v = s2.head
|
||||
if (s1v < s2v) {
|
||||
return LazyList(s1v, lazy({->merge(s1.lztail.value!!, s2)}))
|
||||
} else {
|
||||
return LazyList(s2v, lazy({->merge(s1, s2.lztail.value!!)}))
|
||||
}
|
||||
}
|
||||
fun llmult(m: BI, s: LazyList<BI>): LazyList<BI> {
|
||||
fun llmlt(ss: LazyList<BI>): LazyList<BI> {
|
||||
return LazyList(m * ss.head, lazy({->llmlt(ss.lztail.value!!)}))
|
||||
}
|
||||
return llmlt(s)
|
||||
}
|
||||
fun u(s: LazyList<BI>?, n: Long): LazyList<BI> {
|
||||
var r: LazyList<BI>? = null // mutable nullable so can do the below
|
||||
if (s == null) { // recursively referenced variables are ugly!!!
|
||||
r = llmult(BI.valueOf(n), LazyList(BI.valueOf(1), lazy{ -> r }))
|
||||
} else { // recursively referenced variables only work with lazy
|
||||
r = merge(s, llmult(BI.valueOf(n), // or a loop race limit
|
||||
LazyList(BI.valueOf(1), lazy{ -> r })))
|
||||
}
|
||||
return r
|
||||
}
|
||||
val prms = arrayOf(5L, 3L, 2L)
|
||||
val thunk = {->prms.fold<Long,LazyList<BI>?>(null, {s, n -> u(s,n)})!!}
|
||||
return LazyList(BI.valueOf(1), lazy(thunk))
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
tailrec fun nth(n: Int, h: LazyList<BI>): BI =
|
||||
if (n > 1) { nth(n - 1, h.lztail.value!!) }
|
||||
else { h.head } // non-generic faster: boxing optimized away
|
||||
println(hamming().toSequence().take(20).toList())
|
||||
println(nth(1691, hamming()))
|
||||
val strt = System.currentTimeMillis()
|
||||
println(nth(1000000, hamming()))
|
||||
val stop = System.currentTimeMillis()
|
||||
println("Took ${stop - strt} milliseconds for the last.")
|
||||
}
|
||||
24
Task/Hamming-numbers/OCaml/hamming-numbers-1.ocaml
Normal file
24
Task/Hamming-numbers/OCaml/hamming-numbers-1.ocaml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
module ISet = Set.Make(struct type t = int let compare=compare end)
|
||||
|
||||
let pq = ref (ISet.singleton 1)
|
||||
|
||||
let next () =
|
||||
let m = ISet.min_elt !pq in
|
||||
pq := ISet.(remove m !pq |> add (2*m) |> add (3*m) |> add (5*m));
|
||||
m
|
||||
|
||||
let () =
|
||||
|
||||
print_string "The first 20 are: ";
|
||||
|
||||
for i = 1 to 20
|
||||
do
|
||||
Printf.printf "%d " (next ())
|
||||
done;
|
||||
|
||||
for i = 21 to 1690
|
||||
do
|
||||
ignore (next ())
|
||||
done;
|
||||
|
||||
Printf.printf "\nThe 1691st is %d\n" (next ());
|
||||
25
Task/Hamming-numbers/OCaml/hamming-numbers-2.ocaml
Normal file
25
Task/Hamming-numbers/OCaml/hamming-numbers-2.ocaml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
open Big_int
|
||||
|
||||
module APSet = Set.Make(
|
||||
struct
|
||||
type t = big_int
|
||||
let compare = compare_big_int
|
||||
end)
|
||||
|
||||
let pq = ref (APSet.singleton (big_int_of_int 1))
|
||||
|
||||
let next () =
|
||||
let m = APSet.min_elt !pq in
|
||||
let ( * ) = mult_int_big_int in
|
||||
pq := APSet.(remove m !pq |> add (2*m) |> add (3*m) |> add (5*m));
|
||||
m
|
||||
|
||||
let () =
|
||||
let n = 1_000_000 in
|
||||
|
||||
for i = 1 to (n-1)
|
||||
do
|
||||
ignore (next ())
|
||||
done;
|
||||
|
||||
Printf.printf "\nThe %dth is %s\n" n (string_of_big_int (next ()));
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
/*REXX program computes Hamming numbers: 1 ──► 20, # 1691, the one millionth.*/
|
||||
numeric digits 100 /*ensure enough decimal digits. */
|
||||
call hamming 1, 20 /*show the 1st ──► twentieth Hamming #s*/
|
||||
call hamming 1691 /*show the 1,691st Hamming number. */
|
||||
call hamming 1000000 /*show the 1 millionth Hamming number.*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
/*REXX program computes Hamming numbers: 1 ──► 20, # 1691, and the one millionth. */
|
||||
numeric digits 100 /*ensure enough decimal digits. */
|
||||
call hamming 1, 20 /*show the 1st ──► twentieth Hamming #s*/
|
||||
call hamming 1691 /*show the 1,691st Hamming number. */
|
||||
call hamming 1000000 /*show the 1 millionth Hamming number.*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
hamming: procedure; parse arg x,y; if y=='' then y=x; w=length(y)
|
||||
#2=1; #3=1; #5=1; @.=0; @.1=1
|
||||
do n=2 for y-1
|
||||
@.n = min(2*@.#2, 3*@.#3, 5*@.#5) /*pick the minimum of 3 Hamming numbers*/
|
||||
if 2*@.#2 == @.n then #2 = #2+1 /*number already defined? Use next #. */
|
||||
if 3*@.#3 == @.n then #3 = #3+1 /* " " " " " " */
|
||||
if 5*@.#5 == @.n then #5 = #5+1 /* " " " " " " */
|
||||
end /*n*/ /* [↑] maybe assign next 3 Hamming #s.*/
|
||||
do j=x to y /*W is used to align the (output) index*/
|
||||
say 'Hamming('right(j,w)") =" @.j /*display 'em, Dano.*/
|
||||
end /*j*/
|
||||
#2=1; #3=1; #5=1; @.=0; @.1=1
|
||||
do n=2 for y-1
|
||||
@.n = min(2*@.#2, 3*@.#3, 5*@.#5) /*pick the minimum of 3 (Hamming) #s.*/
|
||||
if 2*@.#2 == @.n then #2 = #2+1 /*number already defined? Use next #*/
|
||||
if 3*@.#3 == @.n then #3 = #3+1 /* " " " " " "*/
|
||||
if 5*@.#5 == @.n then #5 = #5+1 /* " " " " " "*/
|
||||
end /*n*/ /* [↑] maybe assign next 3 Hamming#s*/
|
||||
do j=x to y
|
||||
say 'Hamming('right(j,w)") =" @.j
|
||||
end /*j*/
|
||||
|
||||
say right( 'length of last Hamming number =' length(@.y), 70); say
|
||||
return
|
||||
say right( 'length of last Hamming number =' length(@.y), 70); say
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
/*REXX program computes Hamming numbers: 1 ──► 20, # 1691, the one millionth.*/
|
||||
numeric digits 100 /*ensure enough decimal digits. */
|
||||
call hamming 1, 20 /*show the 1st ──► twentieth Hamming #s*/
|
||||
call hamming 1691 /*show the 1,691st Hamming number. */
|
||||
call hamming 1000000 /*show the 1 millionth Hamming number.*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
hamming: procedure; parse arg x,y; if y=='' then y=x; w=length(y)
|
||||
#2=1; #3=1; #5=1; @.=0; @.1=1
|
||||
do n=2 for y-1
|
||||
_2 = @.#2 + @.#2 /*this is faster than: 2 * @.#2 */
|
||||
_3 = 3 * @.#3
|
||||
_5 = 5 * @.#5
|
||||
m =_2 /*assume a minimum of the 3 Hamming #s.*/
|
||||
if _3 < m then m =_3 /*is this number less than the minimum?*/
|
||||
if _5 < m then m =_5 /* " " " " " " " */
|
||||
@.n = m /*now, assign the next Hamming number. */
|
||||
if _2 == m then #2 = #2 + 1 /*number already defined? Use next #. */
|
||||
if _3 == m then #3 = #3 + 1 /* " " " " " " */
|
||||
if _5 == m then #5 = #5 + 1 /* " " " " " " */
|
||||
end /*n*/ /* [↑] maybe assign next 3 Hamming #s.*/
|
||||
do j=x to y /*W is used to align the (output) index*/
|
||||
say 'Hamming('right(j,w)") =" @.j /*display 'em, Dano.*/
|
||||
end /*j*/
|
||||
/*REXX program computes Hamming numbers: 1 ──► 20, # 1691, and the one millionth.*/
|
||||
numeric digits 100 /*ensure enough decimal digits. */
|
||||
call hamming 1, 20 /*show the 1st ──► twentieth Hamming #s*/
|
||||
call hamming 1691 /*show the 1,691st Hamming number. */
|
||||
call hamming 1000000 /*show the 1 millionth Hamming number.*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
hamming: procedure; parse arg x,y; if y=='' then y=x; w=length(y)
|
||||
#2=1; #3=1; #5=1; @.=0; @.1=1
|
||||
do n=2 for y-1
|
||||
_2 = @.#2 + @.#2 /*this is faster than: @.#2 * 2 */
|
||||
_3 = @.#3 * 3
|
||||
_5 = @.#5 * 5
|
||||
m = _2 /*assume a minimum (of the 3 Hammings).*/
|
||||
if _3 < m then m = _3 /*is this number less than the minimum?*/
|
||||
if _5 < m then m = _5 /* " " " " " " " */
|
||||
@.n = m /*now, assign the next Hamming number.*/
|
||||
if _2 == m then #2 = #2 + 1 /*number already defined? Use next #.*/
|
||||
if _3 == m then #3 = #3 + 1 /* " " " " " " */
|
||||
if _5 == m then #5 = #5 + 1 /* " " " " " " */
|
||||
end /*n*/ /* [↑] maybe assign next Hamming #'s. */
|
||||
do j=x to y
|
||||
say 'Hamming('right(j, w)") =" @.j
|
||||
end /*j*/
|
||||
|
||||
say right( 'length of last Hamming number =' length(@.y), 70); say
|
||||
return
|
||||
say right( 'length of last Hamming number =' length(@.y), 70); say
|
||||
return
|
||||
|
|
|
|||
27
Task/Hamming-numbers/Racket/hamming-numbers-2.rkt
Normal file
27
Task/Hamming-numbers/Racket/hamming-numbers-2.rkt
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#lang racket
|
||||
(require racket/stream)
|
||||
(define first stream-first)
|
||||
(define rest stream-rest)
|
||||
|
||||
(define (hamming)
|
||||
(define (merge s1 s2)
|
||||
(let ([x1 (first s1)]
|
||||
[x2 (first s2)])
|
||||
(if (< x1 x2) ; don't have to handle duplicate case
|
||||
(stream-cons x1 (merge (rest s1) s2))
|
||||
(stream-cons x2 (merge s1 (rest s2))))))
|
||||
(define (smult m s) ; faster than using map (* m)
|
||||
(define (smlt ss)
|
||||
(stream-cons (* m (first ss)) (smlt (rest ss))))
|
||||
(smlt s))
|
||||
(define (u s n)
|
||||
(if (stream-empty? s) ; checking here more efficient than in merge
|
||||
(letrec ([r (smult n (stream-cons 1 r))])
|
||||
r)
|
||||
(letrec ([r (merge s (smult n (stream-cons 1 r)))])
|
||||
r)))
|
||||
(stream-cons 1 (stream-fold u empty-stream '(5 3 2))))
|
||||
|
||||
(for/list ([i 20] [x (hamming)]) x) (newline)
|
||||
(stream-ref (hamming) 1690) (newline)
|
||||
(stream-ref (hamming) 999999) (newline)
|
||||
70
Task/Hamming-numbers/Rust/hamming-numbers-1.rust
Normal file
70
Task/Hamming-numbers/Rust/hamming-numbers-1.rust
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
extern crate num;
|
||||
num::bigint::BigUint;
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
fn basic_hamming(n: usize) -> BigUint {
|
||||
let two = BigUint::from(2u8);
|
||||
let three = BigUint::from(3u8);
|
||||
let five = BigUint::from(5u8);
|
||||
let mut h = vec![BigUint::from(0u8); n];
|
||||
h[0] = BigUint::from(1u8);
|
||||
let mut x2 = BigUint::from(2u8);
|
||||
let mut x3 = BigUint::from(3u8);
|
||||
let mut x5 = BigUint::from(5u8);
|
||||
let mut i = 0usize; let mut j = 0usize; let mut k = 0usize;
|
||||
|
||||
// BigUint comparisons are expensive, so do it only as necessary...
|
||||
fn min3(x: &BigUint, y: &BigUint, z: &BigUint) -> (usize, BigUint) {
|
||||
let (cs, r1) = if y == z { (0x6, y) }
|
||||
else if y < z { (2, y) } else { (4, z) };
|
||||
if x == r1 { (cs | 1, x.clone()) }
|
||||
else if x < r1 { (1, x.clone()) } else { (cs, r1.clone()) }
|
||||
}
|
||||
|
||||
let mut c = 1;
|
||||
while c < n { // satisfy borrow checker with extra blocks: { }
|
||||
let (cs, e1) = { min3(&x2, &x3, &x5) };
|
||||
h[c] = e1; // vector now owns the generated value
|
||||
if (cs & 1) != 0 { i += 1; x2 = &two * &h[i] }
|
||||
if (cs & 2) != 0 { j += 1; x3 = &three * &h[j] }
|
||||
if (cs & 4) != 0 { k += 1; x5 = &five * &h[k] }
|
||||
c += 1;
|
||||
}
|
||||
|
||||
match h.pop() {
|
||||
Some(v) => v,
|
||||
_ => panic!("basic_hamming: arg is zero; no elements")
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print!("[");
|
||||
for (i, h) in (1..21).map(basic_hamming).enumerate() {
|
||||
if i != 0 { print!(",") }
|
||||
print!(" {}", h)
|
||||
}
|
||||
println!(" ]");
|
||||
println!("{}", basic_hamming(1691));
|
||||
|
||||
let strt = Instant::now();
|
||||
|
||||
let rslt = basic_hamming(1000000);
|
||||
|
||||
let elpsd = strt.elapsed();
|
||||
let secs = elpsd.as_secs();
|
||||
let millis = (elpsd.subsec_nanos() / 1000000)as u64;
|
||||
let dur = secs * 1000 + millis;
|
||||
|
||||
let rs = rslt.to_str_radix(10);
|
||||
let mut s = rs.as_str();
|
||||
println!("{} digits:", s.len());
|
||||
while s.len() > 100 {
|
||||
let (f, r) = s.split_at(100);
|
||||
s = r;
|
||||
println!("{}", f);
|
||||
}
|
||||
println!("{}", s);
|
||||
|
||||
println!("This last took {} milliseconds", dur);
|
||||
}
|
||||
32
Task/Hamming-numbers/Rust/hamming-numbers-2.rust
Normal file
32
Task/Hamming-numbers/Rust/hamming-numbers-2.rust
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
fn nodups_hamming(n: usize) -> BigUint {
|
||||
let two = BigUint::from(2u8);
|
||||
let three = BigUint::from(3u8);
|
||||
let five = BigUint::from(5u8);
|
||||
let mut m = vec![BigUint::from(0u8); 1];
|
||||
m[0] = BigUint::from(1u8);
|
||||
let mut h = vec![BigUint::from(0u8); n];
|
||||
h[0] = BigUint::from(1u8);
|
||||
if n > 1 {
|
||||
m.push(BigUint::from(3u8)); // for initial x53 advance
|
||||
h[1] = BigUint::from(2u8); // for initial x532 advance
|
||||
}
|
||||
let mut x5 = BigUint::from(5u8);
|
||||
let mut x53 = BigUint::from(9u8); // 3 times 3 because already merged one step
|
||||
let mut mrg = BigUint::from(3u8);
|
||||
let mut x532 = BigUint::from(2u8);
|
||||
|
||||
let mut i = 0usize; let mut j = 1usize;
|
||||
let mut c = 1usize;
|
||||
while c < n { // satisfy borrow checker with extra blocks: { }
|
||||
if &x532 < &mrg { h[c] = x532; i += 1; x532 = &two * &h[i]; }
|
||||
else { h[c] = mrg;
|
||||
if &x53 < &x5 { mrg = x53; j += 1; x53 = &three * &m[j]; }
|
||||
else { mrg = x5.clone(); x5 = &five * &x5; };
|
||||
m.push(mrg.clone()); };
|
||||
c += 1;
|
||||
}
|
||||
match h.pop() {
|
||||
Some(v) => v,
|
||||
_ => panic!("nodups_hamming: arg is zero; no elements")
|
||||
}
|
||||
}
|
||||
83
Task/Hamming-numbers/Rust/hamming-numbers-3.rust
Normal file
83
Task/Hamming-numbers/Rust/hamming-numbers-3.rust
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
fn log_nodups_hamming(n: u64) -> BigUint {
|
||||
if n <= 0 { panic!("nodups_hamming: arg is zero; no elements") }
|
||||
if n < 2 { return BigUint::from(1u8) } // trivial case for n == 1
|
||||
if n > 1.2e13 as u64 { panic!("log_nodups_hamming: argument too large to guarantee results!") }
|
||||
|
||||
// constants as expanded integers to minimize round-off errors, and
|
||||
// reduce execution time using integer operations not float...
|
||||
const LAA2: u64 = 35184372088832; // 2.0f64.powi(45)).round() as u64;
|
||||
const LBA2: u64 = 55765910372219; // 3.0f64.log2() * 2.0f64.powi(45)).round() as u64;
|
||||
const LCA2: u64 = 81695582054030; // 5.0f64.log2() * 2.0f64.powi(45)).round() as u64;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Logelm { // log representation of an element with only allowable powers
|
||||
exp2: u16,
|
||||
exp3: u16,
|
||||
exp5: u16,
|
||||
logr: u64 // log representation used for comparison only - not exact
|
||||
}
|
||||
|
||||
impl Logelm {
|
||||
fn lte(&self, othr: &Logelm) -> bool {
|
||||
if self.logr <= othr.logr { true } else { false }
|
||||
}
|
||||
fn mul2(&self) -> Logelm {
|
||||
Logelm { exp2: self.exp2 + 1, logr: self.logr + LAA2, .. *self }
|
||||
}
|
||||
fn mul3(&self) -> Logelm {
|
||||
Logelm { exp3: self.exp3 + 1, logr: self.logr + LBA2, .. *self }
|
||||
}
|
||||
fn mul5(&self) -> Logelm {
|
||||
Logelm { exp5: self.exp5 + 1, logr: self.logr + LCA2, .. *self }
|
||||
}
|
||||
}
|
||||
|
||||
let one = Logelm { exp2: 0, exp3: 0, exp5: 0, logr: 0 };
|
||||
let mut x532 = one.mul2();
|
||||
let mut mrg = one.mul3();
|
||||
let mut x53 = one.mul3().mul3(); // advance as mrg has the former value...
|
||||
let mut x5 = one.mul5();
|
||||
|
||||
let mut h = Vec::with_capacity(65536); // vec!(one.clone(); 0);
|
||||
let mut m = Vec::<Logelm>::with_capacity(65536); // vec!(one.clone(); 0);
|
||||
|
||||
let mut i = 0usize; let mut j = 0usize;
|
||||
for _ in 1 .. n {
|
||||
let cph = h.capacity();
|
||||
if i > cph / 2 { // drain extra unneeded values...
|
||||
h.drain(0 .. i);
|
||||
i = 0;
|
||||
}
|
||||
if x532.lte(&mrg) {
|
||||
h.push(x532);
|
||||
x532 = h[i].mul2();
|
||||
i += 1;
|
||||
} else {
|
||||
h.push(mrg);
|
||||
if x53.lte(&x5) {
|
||||
mrg = x53;
|
||||
x53 = m[j].mul3();
|
||||
j += 1;
|
||||
} else {
|
||||
mrg = x5;
|
||||
x5 = x5.mul5();
|
||||
}
|
||||
let cpm = m.capacity();
|
||||
if j > cpm / 2 { // drain extra unneeded values...
|
||||
m.drain(0 .. j);
|
||||
j = 0;
|
||||
}
|
||||
m.push(mrg);
|
||||
}
|
||||
}
|
||||
|
||||
let o = &h[&h.len() - 1];
|
||||
let two = BigUint::from(2u8);
|
||||
let three = BigUint::from(3u8);
|
||||
let five = BigUint::from(5u8);
|
||||
let mut ob = BigUint::from(1u8); // convert to BigUint at the end
|
||||
for _ in 0 .. o.exp2 { ob = ob * &two }
|
||||
for _ in 0 .. o.exp3 { ob = ob * &three }
|
||||
for _ in 0 .. o.exp5 { ob = ob * &five }
|
||||
ob
|
||||
}
|
||||
131
Task/Hamming-numbers/Rust/hamming-numbers-4.rust
Normal file
131
Task/Hamming-numbers/Rust/hamming-numbers-4.rust
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
extern crate num; // requires dependency on the num library
|
||||
use num::bigint::BigUint;
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
fn log_nodups_hamming_iter() -> Box<Iterator<Item = (u16, u16, u16)>> {
|
||||
// constants as expanded integers to minimize round-off errors, and
|
||||
// reduce execution time using integer operations not float...
|
||||
const LAA2: u64 = 35184372088832; // 2.0f64.powi(45)).round() as u64;
|
||||
const LBA2: u64 = 55765910372219; // 3.0f64.log2() * 2.0f64.powi(45)).round() as u64;
|
||||
const LCA2: u64 = 81695582054030; // 5.0f64.log2() * 2.0f64.powi(45)).round() as u64;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Logelm { // log representation of an element with only allowable powers
|
||||
exp2: u16,
|
||||
exp3: u16,
|
||||
exp5: u16,
|
||||
logr: u64 // log representation used for comparison only - not exact
|
||||
}
|
||||
impl Logelm {
|
||||
fn lte(&self, othr: &Logelm) -> bool {
|
||||
if self.logr <= othr.logr { true } else { false }
|
||||
}
|
||||
fn mul2(&self) -> Logelm {
|
||||
Logelm { exp2: self.exp2 + 1, logr: self.logr + LAA2, .. *self }
|
||||
}
|
||||
fn mul3(&self) -> Logelm {
|
||||
Logelm { exp3: self.exp3 + 1, logr: self.logr + LBA2, .. *self }
|
||||
}
|
||||
fn mul5(&self) -> Logelm {
|
||||
Logelm { exp5: self.exp5 + 1, logr: self.logr + LCA2, .. *self }
|
||||
}
|
||||
}
|
||||
|
||||
let one = Logelm { exp2: 0, exp3: 0, exp5: 0, logr: 0 };
|
||||
let mut x532 = one.mul2();
|
||||
let mut mrg = one.mul3();
|
||||
let mut x53 = one.mul3().mul3(); // advance as mrg has the former value...
|
||||
let mut x5 = one.mul5();
|
||||
|
||||
let mut h = Vec::with_capacity(65536);
|
||||
let mut m = Vec::<Logelm>::with_capacity(65536);
|
||||
|
||||
let mut i = 0usize; let mut j = 0usize;
|
||||
Box::new((0u64 .. ).map(move |it| if it < 1 { (0, 0, 0) } else {
|
||||
let cph = h.capacity();
|
||||
if i > cph / 2 {
|
||||
h.drain(0 .. i);
|
||||
i = 0;
|
||||
}
|
||||
if x532.lte(&mrg) {
|
||||
h.push(x532);
|
||||
x532 = h[i].mul2();
|
||||
i += 1;
|
||||
} else {
|
||||
h.push(mrg);
|
||||
if x53.lte(&x5) {
|
||||
mrg = x53;
|
||||
x53 = m[j].mul3();
|
||||
j += 1;
|
||||
} else {
|
||||
mrg = x5;
|
||||
x5 = x5.mul5();
|
||||
}
|
||||
let cpm = m.capacity();
|
||||
if j > cpm / 2 {
|
||||
m.drain(0 .. j);
|
||||
j = 0;
|
||||
}
|
||||
m.push(mrg);
|
||||
}
|
||||
let o = &h[&h.len() - 1];
|
||||
(o.exp2, o.exp3, o.exp5)
|
||||
}))
|
||||
}
|
||||
|
||||
fn convert_log2big(o: (u16, u16, u16)) -> BigUint {
|
||||
let two = BigUint::from(2u8);
|
||||
let three = BigUint::from(3u8);
|
||||
let five = BigUint::from(5u8);
|
||||
let (x2, x3, x5) = o;
|
||||
let mut ob = BigUint::from(1u8); // convert to BigUint at the end
|
||||
for _ in 0 .. x2 { ob = ob * &two }
|
||||
for _ in 0 .. x3 { ob = ob * &three }
|
||||
for _ in 0 .. x5 { ob = ob * &five }
|
||||
ob
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print!("[");
|
||||
for (i, h) in log_nodups_hamming_iter().take(20).map(convert_log2big).enumerate() {
|
||||
if i != 0 { print!(",") }
|
||||
print!(" {}", h)
|
||||
}
|
||||
println!(" ]");
|
||||
println!("{}", convert_log2big(log_nodups_hamming_iter().take(1691).last().unwrap()));
|
||||
|
||||
let strt = Instant::now();
|
||||
|
||||
// let rslt = convert_log2big(log_nodups_hamming_iter().take(1000000000).last().unwrap());
|
||||
let mut it = log_nodups_hamming_iter().into_iter();
|
||||
for _ in 0 .. 100-1 { // a little faster; less one level of iteration
|
||||
let _ = it.next();
|
||||
}
|
||||
let rslt = convert_log2big(it.next().unwrap());
|
||||
|
||||
let elpsd = strt.elapsed();
|
||||
let secs = elpsd.as_secs();
|
||||
let millis = (elpsd.subsec_nanos() / 1000000)as u64;
|
||||
let dur = secs * 1000 + millis;
|
||||
|
||||
println!("2^{} times 3^{} times 5^{}", rslt.0, rslt.1, rslt.2);
|
||||
let rs = convert_log2big(rslt).to_str_radix(10);
|
||||
let mut s = rs.as_str();
|
||||
println!("{} digits:", s.len());
|
||||
let lg3 = 3.0f64.log2();
|
||||
let lg5 = 5.0f64.log2();
|
||||
let lg = (rslt.0 as f64 + rslt.1 as f64 * lg3
|
||||
+ rslt.2 as f64 * lg5) * 2.0f64.log10();
|
||||
println!("Approximately {}E+{}", 10.0f64.powf(lg.fract()), lg.trunc());
|
||||
if s.len() <= 10000 {
|
||||
while s.len() > 100 {
|
||||
let (f, r) = s.split_at(100);
|
||||
s = r;
|
||||
println!("{}", f);
|
||||
}
|
||||
println!("{}", s);
|
||||
}
|
||||
|
||||
println!("This last took {} milliseconds.", dur);
|
||||
}
|
||||
255
Task/Hamming-numbers/Rust/hamming-numbers-5.rust
Normal file
255
Task/Hamming-numbers/Rust/hamming-numbers-5.rust
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
extern crate num;
|
||||
use num::bigint::BigUint;
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::iter::FromIterator;
|
||||
use std::cell::{UnsafeCell, RefCell};
|
||||
use std::mem;
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
// since Box<FnOnce() -> T + 'a> doesn't currently work and
|
||||
// FnBox, which does work, (version 1.13) is UnStable;
|
||||
// use the boilerplate Invoke trait and Thunk
|
||||
// from the old removed thunk standard library...
|
||||
|
||||
pub trait Invoke<R = ()> {
|
||||
fn invoke(self: Box<Self>) -> R;
|
||||
}
|
||||
|
||||
impl<R, F: FnOnce() -> R> Invoke<R> for F {
|
||||
#[inline(always)]
|
||||
fn invoke(self: Box<F>) -> R { (*self)() }
|
||||
}
|
||||
|
||||
pub struct Thunk<'a, R>(Box<Invoke<R> + 'a>);
|
||||
|
||||
impl<'a, R: 'a> Thunk<'a, R> {
|
||||
#[inline(always)]
|
||||
fn new<F: 'a + FnOnce() -> R>(func: F) -> Thunk<'a, R> {
|
||||
Thunk(Box::new(func))
|
||||
}
|
||||
#[inline(always)]
|
||||
fn invoke(self) -> R { self.0.invoke() }
|
||||
}
|
||||
|
||||
// actual Lazy implementation starts here...
|
||||
|
||||
use self::LazyState::*;
|
||||
|
||||
pub struct Lazy<'a, T: 'a>(UnsafeCell<LazyState<'a, T>>);
|
||||
|
||||
enum LazyState<'a, T: 'a> {
|
||||
Unevaluated(Thunk<'a, T>),
|
||||
EvaluationInProgress,
|
||||
Evaluated(T)
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> Lazy<'a, T>{
|
||||
#[inline]
|
||||
pub fn new<'b, F>(thunk: F) -> Lazy<'b, T>
|
||||
where F: 'b + FnOnce() -> T {
|
||||
Lazy(UnsafeCell::new(Unevaluated(Thunk::new(thunk))))
|
||||
}
|
||||
#[inline]
|
||||
pub fn evaluated(val: T) -> Lazy<'a, T> {
|
||||
Lazy(UnsafeCell::new(Evaluated(val)))
|
||||
}
|
||||
#[inline]
|
||||
fn force<'b>(&'b self) { // not thread-safe
|
||||
unsafe {
|
||||
match *self.0.get() {
|
||||
Evaluated(_) => return, // nothing required; already Evaluated
|
||||
EvaluationInProgress => panic!("Lazy::force called recursively!!!"),
|
||||
_ => () // need to do following something else if Unevaluated...
|
||||
} // following eliminates recursive race; drops neither on replace...
|
||||
match mem::replace(&mut *self.0.get(), EvaluationInProgress) {
|
||||
Unevaluated(thnk) => { // thnk can't call force on the same Lazy
|
||||
*self.0.get() = Evaluated(thnk.invoke());
|
||||
},
|
||||
_ => unreachable!() // already took care of other cases in above match.
|
||||
}
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn value<'b>(&'b self) -> &'b T {
|
||||
self.force(); // evaluatate if not evealutated
|
||||
match unsafe { &*self.0.get() } {
|
||||
&Evaluated(ref v) => v, // return value
|
||||
_ => { unreachable!() } // previous force guarantees never not Evaluated
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn unwrap<'b>(self) -> T where T: 'b { // consumes the object to produce the value
|
||||
self.force(); // evaluatate if not evealutated
|
||||
match unsafe { self.0.into_inner() } {
|
||||
Evaluated(v) => v,
|
||||
_ => unreachable!() // previous code guarantees never not Evaluated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now for immutable persistent (memoized) LazyList via Lazy above
|
||||
|
||||
type RcLazyListNode<'a, T: 'a> = Rc<Lazy<'a, LazyList<'a, T>>>;
|
||||
|
||||
use self::LazyList::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
enum LazyList<'a, T: 'a + Clone> {
|
||||
/// The Empty List
|
||||
Empty,
|
||||
/// A list with one member and possibly another list.
|
||||
Cons(T, RcLazyListNode<'a, T>)
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + Clone> LazyList<'a, T> {
|
||||
#[inline]
|
||||
pub fn cons<F>(v: T, cntf: F) -> LazyList<'a, T>
|
||||
where F: 'a + FnOnce() -> LazyList<'a, T> {
|
||||
Cons(v, Rc::new(Lazy::new(cntf)))
|
||||
}
|
||||
#[inline]
|
||||
pub fn head<'b>(&'b self) -> &'b T {
|
||||
if let Cons(ref hd, _) = *self { return hd }
|
||||
panic!("LazyList::head called on an Empty LazyList!!!")
|
||||
}
|
||||
#[inline]
|
||||
pub fn tail<'b>(&'b self) -> &'b Lazy<'a, LazyList<'a, T>> {
|
||||
if let Cons(_, ref rlln) = *self { return &*rlln }
|
||||
panic!("LazyList::tail called on an Empty LazyList!!!")
|
||||
}
|
||||
#[inline]
|
||||
pub fn unwrap(self) -> (T, RcLazyListNode<'a, T>) { // consumes the object
|
||||
if let Cons(hd, rlln) = self {
|
||||
return (hd, rlln) }
|
||||
panic!("LazyList::unwrap called on an Empty LazyList!!!")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + Clone> Iterator for LazyList<'a, T> {
|
||||
type Item = T;
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Empty = *self { return None }
|
||||
let oldll = mem::replace(self, Empty);
|
||||
let (hd, rlln) = oldll.unwrap();
|
||||
let mut newll = rlln.value().clone();
|
||||
mem::swap(self, &mut newll); // self now contains tail, newll contains the Empty
|
||||
Some(hd)
|
||||
}
|
||||
}
|
||||
|
||||
// implements worker wrapper recursion closures using shared RcMFn variable...
|
||||
|
||||
type RcMFn<'a, T: 'a> = Rc<UnsafeCell<Box<FnMut(T) -> T + 'a>>>;
|
||||
|
||||
//#[derive(Clone)]
|
||||
//struct RcMFn<'a, T: 'a>(Rc<UnsafeCell<Box<FnMut() -> T + 'a>>>);
|
||||
|
||||
trait RcMFnMethods<'a, T> {
|
||||
fn create<F: FnMut(T) -> T + 'a>(v: F) -> RcMFn<'a, T>;
|
||||
fn invoke(&self, v: T) -> T;
|
||||
fn set<F: FnMut(T) -> T + 'a>(&self, v: F);
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> RcMFnMethods<'a, T> for RcMFn<'a, T> {
|
||||
fn create<F: FnMut(T) -> T + 'a>(v: F) -> RcMFn<'a, T> { // creates new value wrapper
|
||||
Rc::new(UnsafeCell::new(Box::new(v)))
|
||||
}
|
||||
#[inline(always)] // needs to be faster to be worth it
|
||||
fn invoke(&self, v: T) -> T {
|
||||
unsafe { (*(*(*self).get()))(v) }
|
||||
}
|
||||
fn set<F: FnMut(T) -> T + 'a>(&self, v: F) {
|
||||
unsafe { *self.get() = Box::new(v); }
|
||||
}
|
||||
}
|
||||
|
||||
// implementation for a reference-counted, interior-mutable variable
|
||||
// necessary for such things as sharing data and recursive variables
|
||||
|
||||
type RcMVar<T> = Rc<RefCell<T>>;
|
||||
|
||||
//#[derive(Clone)]
|
||||
//struct RcMVar<T>(Rc<RefCell<T>>);
|
||||
|
||||
trait RcMVarMethods<T> {
|
||||
fn create(v: T) -> Self;
|
||||
fn get(self: &Self) -> T;
|
||||
fn set(self: &Self, v: T);
|
||||
}
|
||||
|
||||
impl<T: Clone> RcMVarMethods<T> for RcMVar<T> {
|
||||
fn create(v: T) -> RcMVar<T> { // creates new value wrapped in RcMVar
|
||||
Rc::new(RefCell::new(v))
|
||||
}
|
||||
#[inline]
|
||||
fn get(&self) -> T {
|
||||
self.borrow().clone()
|
||||
}
|
||||
fn set(&self, v: T) {
|
||||
*self.borrow_mut() = v;
|
||||
}
|
||||
}
|
||||
|
||||
fn hammings() -> Box<Iterator<Item = Rc<BigUint>>> {
|
||||
type LL<'a> = LazyList<'a, Rc<BigUint>>;
|
||||
fn merge<'a>(x: LL<'a>, y: LL<'a>) -> LL<'a> {
|
||||
let lte = { x.head() <= y.head() }; // private context for borrow
|
||||
if lte {
|
||||
let (hdx, tlx) = x.unwrap();
|
||||
LL::cons(hdx, move || merge(tlx.value().clone(), y))
|
||||
} else {
|
||||
let (hdy, tly) = y.unwrap();
|
||||
LL::cons(hdy, move || merge(x, tly.value().clone()))
|
||||
}
|
||||
}
|
||||
fn smult<'a>(m: BigUint, s: LL<'a>) -> LL<'a> { // like map m * but faster...
|
||||
let smlt = RcMFn::create(move |ss: LL<'a>| ss);
|
||||
let csmlt = smlt.clone();
|
||||
smlt.set(move |ss: LL<'a>| {
|
||||
let (hd, tl) = ss.unwrap();
|
||||
let ccsmlt = csmlt.clone();
|
||||
LL::cons(Rc::new(&m * &*hd), move || ccsmlt.invoke(tl.value().clone()))
|
||||
});
|
||||
smlt.invoke(s)
|
||||
}
|
||||
fn u<'a>(s: LL<'a>, n: usize) -> LL<'a> {
|
||||
let nb = BigUint::from(n);
|
||||
let rslt = RcMVar::create(Empty);
|
||||
let crslt = rslt.clone(); // same interior data...
|
||||
let cll = LL::cons(Rc::new(BigUint::from(1u8)), move || crslt.get()); // gets future value
|
||||
// below sets future value for above closure...
|
||||
rslt.set(if let Empty = s { smult(nb, cll) } else { merge(s, smult(nb, cll)) });
|
||||
rslt.get()
|
||||
}
|
||||
fn rll<'a>() -> LL<'a> { [5, 3, 2].into_iter()
|
||||
.fold(Empty, |ll, n| u(ll, *n) ) }
|
||||
let hmng = LL::cons(Rc::new(BigUint::from(1u8)), move || rll());
|
||||
Box::new(hmng.into_iter())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print!("[");
|
||||
for (i, h) in hammings().take(20).enumerate() {
|
||||
if i != 0 { print!(",") }
|
||||
print!(" {}", h)
|
||||
}
|
||||
println!(" ]");
|
||||
|
||||
println!("{}", hammings().take(1691).last().unwrap());
|
||||
|
||||
let strt = Instant::now();
|
||||
|
||||
let rslt = hammings().take(1000000).last().unwrap();
|
||||
|
||||
let elpsd = strt.elapsed();
|
||||
let secs = elpsd.as_secs();
|
||||
let millis = (elpsd.subsec_nanos() / 1000000)as u64;
|
||||
let dur = secs * 1000 + millis;
|
||||
|
||||
println!("{}", rslt);
|
||||
|
||||
println!("This last took {} milliseconds.", dur);
|
||||
}
|
||||
95
Task/Hamming-numbers/Rust/hamming-numbers-6.rust
Normal file
95
Task/Hamming-numbers/Rust/hamming-numbers-6.rust
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
extern crate num; // requires dependency on the num library
|
||||
use num::bigint::BigUint;
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
fn nth_hamming(n: u64) -> (u32, u32, u32) {
|
||||
if n < 2 {
|
||||
if n <= 0 { panic!("nth_hamming: argument is zero; no elements") }
|
||||
return (0, 0, 0) // trivial case for n == 1
|
||||
}
|
||||
|
||||
let lg3 = 3.0f64.ln() / 2.0f64.ln(); // log base 2 of 3
|
||||
let lg5 = 5.0f64.ln() / 2.0f64.ln(); // log base 2 of 5
|
||||
let fctr = 6.0f64 * lg3 * lg5;
|
||||
let crctn = 30.0f64.sqrt().ln() / 2.0f64.ln(); // log base 2 of sqrt 30
|
||||
let lgest = (fctr * n as f64).powf(1.0f64/3.0f64)
|
||||
- crctn; // from WP formula
|
||||
let frctn = if n < 1000000000 { 0.509f64 } else { 0.105f64 };
|
||||
let lghi = (fctr * (n as f64 + frctn * lgest)).powf(1.0f64/3.0f64)
|
||||
- crctn; // calculate hi log limit based on log(N) - WP article
|
||||
let lglo = 2.0f64 * lgest - lghi; // and a lower limit of the upper "band"
|
||||
let mut count = 0; // need to use extended precision, might go over
|
||||
let mut bnd = Vec::with_capacity(0);
|
||||
let klmt = (lghi / lg5) as u32 + 1;
|
||||
for k in 0 .. klmt { // i, j, k values can be just u32 values
|
||||
let p = k as f64 * lg5;
|
||||
let jlmt = ((lghi - p) / lg3) as u32 + 1;
|
||||
for j in 0 .. jlmt {
|
||||
let q = p + j as f64 * lg3;
|
||||
let ir = lghi - q;
|
||||
let lg = q + (ir as u32) as f64; // current log value (estimated)
|
||||
count += ir as u64 + 1;
|
||||
if lg >= lglo {
|
||||
bnd.push((lg, (ir as u32, j, k)))
|
||||
}
|
||||
}
|
||||
}
|
||||
if n > count { panic!("nth_hamming: band high estimate is too low!") };
|
||||
let ndx = (count - n) as usize;
|
||||
if ndx >= bnd.len() { panic!("nth_hamming: band low estimate is too high!") };
|
||||
bnd.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap()); // sort decreasing order
|
||||
|
||||
bnd[ndx].1
|
||||
}
|
||||
|
||||
fn convert_log2big(o: (u32, u32, u32)) -> BigUint {
|
||||
let two = BigUint::from(2u8);
|
||||
let three = BigUint::from(3u8);
|
||||
let five = BigUint::from(5u8);
|
||||
let (x2, x3, x5) = o;
|
||||
let mut ob = BigUint::from(1u8); // convert to BigUint at the end
|
||||
for _ in 0 .. x2 { ob = ob * &two }
|
||||
for _ in 0 .. x3 { ob = ob * &three }
|
||||
for _ in 0 .. x5 { ob = ob * &five }
|
||||
ob
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print!("[");
|
||||
for (i, h) in (1 .. 21).map(nth_hamming).enumerate() {
|
||||
if i != 0 { print!(",") }
|
||||
print!(" {}", convert_log2big(h))
|
||||
}
|
||||
println!(" ]");
|
||||
println!("{}", convert_log2big(nth_hamming(1691)));
|
||||
|
||||
let strt = Instant::now();
|
||||
|
||||
let rslt = nth_hamming(1000000);
|
||||
|
||||
let elpsd = strt.elapsed();
|
||||
let secs = elpsd.as_secs();
|
||||
let millis = (elpsd.subsec_nanos() / 1000000)as u64;
|
||||
let dur = secs * 1000 + millis;
|
||||
|
||||
println!("2^{} times 3^{} times 5^{}", rslt.0, rslt.1, rslt.2);
|
||||
let rs = convert_log2big(rslt).to_str_radix(10);
|
||||
let mut s = rs.as_str();
|
||||
println!("{} digits:", s.len());
|
||||
let lg3 = 3.0f64.log2();
|
||||
let lg5 = 5.0f64.log2();
|
||||
let lg = (rslt.0 as f64 + rslt.1 as f64 * lg3
|
||||
+ rslt.2 as f64 * lg5) * 2.0f64.log10();
|
||||
println!("Approximately {}E+{}", 10.0f64.powf(lg.fract()), lg.trunc());
|
||||
if s.len() <= 10000 {
|
||||
while s.len() > 100 {
|
||||
let (f, r) = s.split_at(100);
|
||||
s = r;
|
||||
println!("{}", f);
|
||||
}
|
||||
println!("{}", s);
|
||||
}
|
||||
|
||||
println!("This last took {} milliseconds.", dur);
|
||||
}
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
def hamming(): Stream[BigInt] = {
|
||||
def merge(a: Stream[BigInt], b: Stream[BigInt]): Stream[BigInt] = {
|
||||
val av = a.head; val bv = b.head
|
||||
if (av < bv) av #:: merge(a.tail, b)
|
||||
else bv #:: merge(a, b.tail)
|
||||
}
|
||||
def smult(m:BigInt, s: Stream[BigInt]): Stream[BigInt] =
|
||||
(m * s.head) #:: smult(m, s.tail) // equiv to map (m *) s - faster
|
||||
lazy val s5: Stream[BigInt] = 5 #:: smult(5, s5)
|
||||
lazy val s35: Stream[BigInt] = 3 #:: merge(s5, smult(3, s35))
|
||||
lazy val s235: Stream[BigInt] = 2 #:: merge(s35, smult(2, s235))
|
||||
1 #:: s235
|
||||
}
|
||||
if (a.isEmpty) b else {
|
||||
val av = a.head; val bv = b.head
|
||||
if (av < bv) av #:: merge(a.tail, b)
|
||||
else bv #:: merge(a, b.tail) } }
|
||||
def smult(m:Int, s: Stream[BigInt]): Stream[BigInt] =
|
||||
(m * s.head) #:: smult(m, s.tail) // equiv to map (m *) s; faster
|
||||
def u(s: Stream[BigInt], n: Int): Stream[BigInt] = {
|
||||
lazy val r: Stream[BigInt] = merge(s, smult(n, 1 #:: r))
|
||||
r }
|
||||
1 #:: List(5, 3, 2).foldLeft(Stream.empty[BigInt]) { u } }
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
(define (hamming)
|
||||
(define (foldl f z l)
|
||||
(define (foldls zs ls)
|
||||
(if (null? ls) zs (foldls (f zs (car ls)) (cdr ls))))
|
||||
(foldls z l))
|
||||
(define (merge a b)
|
||||
(let ((x (car a)) (y (car b)))
|
||||
(if (< x y) (cons x (delay (merge (force (cdr a)) b)))
|
||||
(cons y (delay (merge a (force (cdr b))))))))
|
||||
(define (smult m s) (cons (* m (car s))
|
||||
(delay (smult m (force (cdr s)))))) ;; equiv to map (* m) s
|
||||
(define s5 (cons 5 (delay (smult 5 s5))))
|
||||
(define s35 (cons 3 (delay (merge s5 (smult 3 s35)))))
|
||||
(define s235 (cons 2 (delay (merge s35 (smult 2 s235)))))
|
||||
(cons 1 (delay s235)))
|
||||
(if (null? a) b
|
||||
(let ((x (car a)) (y (car b)))
|
||||
(if (< x y) (cons x (delay (merge (force (cdr a)) b)))
|
||||
(cons y (delay (merge a (force (cdr b)))))))))
|
||||
(define (smult m s) (cons (* m (car s)) ;; equiv to map (* m) s; faster
|
||||
(delay (smult m (force (cdr s))))))
|
||||
(define (u s n) (letrec ((a (merge s (smult n (cons 1 (delay a)))))) a))
|
||||
(cons 1 (delay (foldl u '() '(5 3 2)))))
|
||||
|
||||
;;; test...
|
||||
(define (stream-take->list n strm)
|
||||
|
|
|
|||
17
Task/Hamming-numbers/ZX-Spectrum-Basic/hamming-numbers.zx
Normal file
17
Task/Hamming-numbers/ZX-Spectrum-Basic/hamming-numbers.zx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
10 FOR h=1 TO 20: GO SUB 1000: NEXT h
|
||||
20 LET h=1691: GO SUB 1000
|
||||
30 STOP
|
||||
1000 REM Hamming
|
||||
1010 DIM a(h)
|
||||
1030 LET a(1)=1: LET x2=2: LET x3=3: LET x5=5: LET i=1: LET j=1: LET k=1
|
||||
1040 FOR n=2 TO h
|
||||
1050 LET m=x2
|
||||
1060 IF m>x3 THEN LET m=x3
|
||||
1070 IF m>x5 THEN LET m=x5
|
||||
1080 LET a(n)=m
|
||||
1090 IF m=x2 THEN LET i=i+1: LET x2=2*a(i)
|
||||
1100 IF m=x3 THEN LET j=j+1: LET x3=3*a(j)
|
||||
1110 IF m=x5 THEN LET k=k+1: LET x5=5*a(k)
|
||||
1120 NEXT n
|
||||
1130 PRINT "H(";h;")= ";a(h)
|
||||
1140 RETURN
|
||||
Loading…
Add table
Add a link
Reference in a new issue