This commit is contained in:
Ingy döt Net 2013-04-10 21:29:02 -07:00
parent 764da6cbbb
commit db842d013d
19005 changed files with 197040 additions and 7 deletions

View file

@ -0,0 +1,12 @@
[[wp:Hamming_numbers#Algorithms|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'' &nbsp; (numbers whose prime divisors are less or equal to 5).
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]]
# [[wp: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]).

View file

@ -0,0 +1,37 @@
PR precision=100 PR
MODE SERIES = FLEX [1 : 0] UNT, # Initially, no elements #
UNT = LONG LONG INT; # A 100-digit unsigned integer #
PROC hamming number = (INT n) UNT: # The n-th Hamming number #
CASE n
IN 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 # First 10 in a table #
OUT # Additional operators #
OP MIN = (INT i, j) INT: (i < j | i | j), MIN = (UNT i, j) UNT: (i < j | i | j);
PRIO MIN = 9;
OP LAST = (SERIES h) UNT: h[UPB h]; # Last element of a series #
OP +:= = (REF SERIES s, UNT elem) VOID:
# Extend a series by one element, only keep the elements you need #
(INT lwb = (i MIN j) MIN k, upb = UPB s;
REF SERIES new s = HEAP FLEX [lwb : upb + 1] UNT;
(new s[lwb : upb] := s[lwb : upb], new s[upb + 1] := elem);
s := new s
);
# Determine the n-th hamming number iteratively #
SERIES h := 1, # Series, initially one element #
UNT m2 := 2, m3 := 3, m5 := 5, # Multipliers #
INT i := 1, j := 1, k := 1; # Counters #
TO n - 1
DO h +:= (m2 MIN m3) MIN m5;
(LAST h = m2 | m2 := 2 * h[i +:= 1]);
(LAST h = m3 | m3 := 3 * h[j +:= 1]);
(LAST h = m5 | m5 := 5 * h[k +:= 1])
OD;
LAST h
ESAC;
FOR k TO 20
DO print ((whole (hamming number (k), 0), blank))
OD;
print ((newline, whole (hamming number (1 691), 0)));
print ((newline, whole (hamming number (1 000 000), 0)))

View file

@ -0,0 +1,70 @@
with Ada.Text_IO;
procedure Hamming is
generic
type Int_Type is private;
Zero : Int_Type;
One : Int_Type;
Two : Int_Type;
Three : Int_Type;
Five : Int_Type;
with function "mod" (Left, Right : Int_Type) return Int_Type is <>;
with function "/" (Left, Right : Int_Type) return Int_Type is <>;
with function "+" (Left, Right : Int_Type) return Int_Type is <>;
function Get_Hamming (Position : Positive) return Int_Type;
function Get_Hamming (Position : Positive) return Int_Type is
function Is_Hamming (Number : Int_Type) return Boolean is
Temporary : Int_Type := Number;
begin
while Temporary mod Two = Zero loop
Temporary := Temporary / Two;
end loop;
while Temporary mod Three = Zero loop
Temporary := Temporary / Three;
end loop;
while Temporary mod Five = Zero loop
Temporary := Temporary / Five;
end loop;
return Temporary = One;
end Is_Hamming;
Result : Int_Type := One;
Previous : Positive := 1;
begin
while Previous /= Position loop
Result := Result + One;
if Is_Hamming (Result) then
Previous := Previous + 1;
end if;
end loop;
return Result;
end Get_Hamming;
-- up to 2**32 - 1
function Integer_Get_Hamming is new Get_Hamming
(Int_Type => Integer,
Zero => 0,
One => 1,
Two => 2,
Three => 3,
Five => 5);
-- up to 2**64 - 1
function Long_Long_Integer_Get_Hamming is new Get_Hamming
(Int_Type => Long_Long_Integer,
Zero => 0,
One => 1,
Two => 2,
Three => 3,
Five => 5);
begin
Ada.Text_IO.Put ("1) First 20 Hamming numbers: ");
for I in 1 .. 20 loop
Ada.Text_IO.Put (Integer'Image (Integer_Get_Hamming (I)));
end loop;
Ada.Text_IO.New_Line;
Ada.Text_IO.Put_Line ("2) 1_691st Hamming number: " &
Integer'Image (Integer_Get_Hamming (1_691)));
-- even Long_Long_Integer overflows here
Ada.Text_IO.Put_Line ("3) 1_000_000st Hamming number: " &
Long_Long_Integer'Image (Long_Long_Integer_Get_Hamming (1_000_000)));
end Hamming;

View file

@ -0,0 +1,14 @@
type My_Index is mod 2**8;
package My_Big_Numbers is new Big_Number (Index_type => My_Index, Nb_Item => 64);
function Int2Big is new My_Big_Numbers.Generic_Conversion.Int_Number2Big_Unsigned (Integer);
function Big_Get_Hamming is new Get_Hamming
(Int_Type => My_Big_Numbers.Big_Unsigned,
Zero => My_Big_Numbers.Big_Unsigned_Zero,
One => My_Big_Numbers.Big_Unsigned_One,
Two => My_Big_Numbers.Big_Unsigned_Two,
Three => Int2Big(3),
Five => Int2Big(5),
"mod" => My_Big_Numbers.Unsigned_Number."mod",
"+" => My_Big_Numbers.Unsigned_Number."+",
"/" => My_Big_Numbers.Unsigned_Number."/");

View file

@ -0,0 +1,2 @@
Ada.Text_IO.Put_Line ("3) 1_000_000st Hamming number: " &
Ada.Strings.Unbounded.To_String (My_Big_Numbers.String_Conversion.Big_Unsigned2UString (Big_Get_Hamming (1_000_000))));

View file

@ -0,0 +1,51 @@
SetBatchLines, -1
Msgbox % hamming(1,20)
Msgbox % hamming(1690)
return
hamming(first,last=0)
{
if (first < 1)
ans=ERROR
if (last = 0)
last := first
i:=0, j:=0, k:=0
num1 := ceil((last * 20)**(1/3))
num2 := ceil(num1 * ln(2)/ln(3))
num3 := ceil(num1 * ln(2)/ln(5))
loop
{
H := (2**i) * (3**j) * (5**k)
if (H > 0)
ans = %H%`n%ans%
i++
if (i > num1)
{
i=0
j++
if (j > num2)
{
j=0
k++
}
}
if (k > num3)
break
}
Sort ans, N
Loop, parse, ans, `n, `r
{
if (A_index > last)
break
if (A_index < first)
continue
Output = %Output%`n%A_LoopField%
}
return Output
}

View file

@ -0,0 +1,21 @@
@% = &1010
FOR h% = 1 TO 20
PRINT "H("; h% ") = "; FNhamming(h%)
NEXT
PRINT "H(1691) = "; FNhamming(1691)
END
DEF FNhamming(l%)
LOCAL i%, j%, k%, n%, m, x2, x3, x5, h%()
DIM h%(l%) : h%(0) = 1
x2 = 2 : x3 = 3 : x5 = 5
FOR n% = 1 TO l%-1
m = x2
IF m > x3 m = x3
IF m > x5 m = x5
h%(n%) = m
IF m = x2 i% += 1 : x2 = 2 * h%(i%)
IF m = x3 j% += 1 : x3 = 3 * h%(j%)
IF m = x5 k% += 1 : x5 = 5 * h%(k%)
NEXT
= h%(l%-1)

View file

@ -0,0 +1,22 @@
#include <iostream>
#include <vector>
// Hamming like sequences Generator
//
// Nigel Galloway. August 13th., 2012
//
class Ham {
private:
std::vector<unsigned int> _H, _hp, _hv, _x;
public:
bool operator!=(const Ham& other) const {return true;}
Ham begin() const {return *this;}
Ham end() const {return *this;}
unsigned int operator*() const {return _x.back();}
Ham(const std::vector<unsigned int> &pfs):_H(pfs),_hp(pfs.size(),0),_hv({pfs}),_x({1}){}
const Ham& operator++() {
for (int i=0; i<_H.size(); i++) for (;_hv[i]<=_x.back();_hv[i]=_x[++_hp[i]]*_H[i]);
_x.push_back(_hv[0]);
for (int i=1; i<_H.size(); i++) if (_hv[i]<_x.back()) _x.back()=_hv[i];
return *this;
}
};

View file

@ -0,0 +1,11 @@
int main() {
int count = 1;
for (unsigned int i : Ham({2,3,5})) {
if (count <= 62) std::cout << i << ' ';
if (count++ == 1691) {
std::cout << "\nThe one thousand six hundred and ninety first Hamming Number is " << i << std::endl;
break;
}
}
return 0;
}

View file

@ -0,0 +1,9 @@
int main() {
int count = 1;
for (unsigned int i : Ham({2,3,5,7})) {
std::cout << i << ' ';
if (count++ == 64) break;
}
std::cout << std::endl;
return 0;
}

View file

@ -0,0 +1,56 @@
#include <stdio.h>
#include <stdlib.h>
typedef unsigned long long ham;
size_t alloc = 0, n = 1;
ham *q = 0;
void qpush(ham h)
{
int i, j;
if (alloc <= n) {
alloc = alloc ? alloc * 2 : 16;
q = realloc(q, sizeof(ham) * alloc);
}
for (i = n++; (j = i/2) && q[j] > h; q[i] = q[j], i = j);
q[i] = h;
}
ham qpop()
{
int i, j;
ham r, t;
/* outer loop for skipping duplicates */
for (r = q[1]; n > 1 && r == q[1]; q[i] = t) {
/* inner loop is the normal down heap routine */
for (i = 1, t = q[--n]; (j = i * 2) < n;) {
if (j + 1 < n && q[j] > q[j+1]) j++;
if (t <= q[j]) break;
q[i] = q[j], i = j;
}
}
return r;
}
int main()
{
int i;
ham h;
for (qpush(i = 1); i <= 1691; i++) {
/* takes smallest value, and queue its multiples */
h = qpop();
qpush(h * 2);
qpush(h * 3);
qpush(h * 5);
if (i <= 20 || i == 1691)
printf("%6d: %llu\n", i, h);
}
/* free(q); */
return 0;
}

View file

@ -0,0 +1,96 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <gmp.h>
/* number of factors. best be mutually prime -- duh. */
#define NK 3
#define MAX_HAM (1 << 24)
#define MAX_POW 1024
int n_hams = 0, idx[NK] = {0}, fac[] = { 2, 3, 5, 7, 11};
/* k-smooth numbers are stored as their exponents of each factor;
v is the log of the number, for convenience. */
typedef struct {
int e[NK];
double v;
} ham_t, *ham;
ham_t *hams, values[NK] = {{{0}, 0}};
double inc[NK][MAX_POW];
/* most of the time v can be just incremented, but eventually
* floating point precision will bite us, so better recalculate */
inline
void _setv(ham x) {
int i;
for (x->v = 0, i = 0; i < NK; i++)
x->v += inc[i][x->e[i]];
}
inline
int _eq(ham a, ham b) {
int i;
for (i = 0; i < NK && a->e[i] == b->e[i]; i++);
return i == NK;
}
ham get_ham(int n)
{
int i, ni;
ham h;
n--;
while (n_hams < n) {
for (ni = 0, i = 1; i < NK; i++)
if (values[i].v < values[ni].v)
ni = i;
*(h = hams + ++n_hams) = values[ni];
for (ni = 0; ni < NK; ni++) {
if (! _eq(values + ni, h)) continue;
values[ni] = hams[++idx[ni]];
values[ni].e[ni]++;
_setv(values + ni);
}
}
return hams + n;
}
void show_ham(ham h)
{
static mpz_t das_ham, tmp;
int i;
mpz_init_set_ui(das_ham, 1);
mpz_init_set_ui(tmp, 1);
for (i = 0; i < NK; i++) {
mpz_ui_pow_ui(tmp, fac[i], h->e[i]);
mpz_mul(das_ham, das_ham, tmp);
}
gmp_printf("%Zu\n", das_ham);
}
int main()
{
int i, j;
hams = malloc(sizeof(ham_t) * MAX_HAM);
for (i = 0; i < NK; i++) {
values[i].e[i] = 1;
inc[i][1] = log(fac[i]);
_setv(values + i);
for (j = 2; j < MAX_POW; j++)
inc[i][j] = j * inc[i][1];
}
printf(" 1,691: "); show_ham(get_ham(1691));
printf(" 1,000,000: "); show_ham(get_ham(1e6));
printf("10,000,000: "); show_ham(get_ham(1e7));
return 0;
}

View file

@ -0,0 +1,19 @@
(defn smerge [xs ys]
(lazy-seq
(let [x (first xs),
y (first ys),
[z xs* ys*]
(cond
(< x y) [x (rest xs) ys]
(> x y) [y xs (rest ys)]
:else [x (rest xs) (rest ys)])]
(cons z (smerge xs* ys*)))))
(defn smerge3 [xs ys zs]
(smerge xs (smerge ys zs)))
(defn map*n [n ks] (map #(* n %) ks))
(def hamming
(lazy-seq
(cons 1 (smerge3 (map*n 2 hamming) (map*n 3 hamming) (map*n 5 hamming)))))

View file

@ -0,0 +1,82 @@
# Generate hamming numbers in order. Hamming numbers have the
# property that they don't evenly divide any prime numbers outside
# a given set, such as [2, 3, 5].
generate_hamming_sequence = (primes, max_n) ->
# We use a lazy algorithm, only ever keeping N candidates
# in play, one for each of our seed primes. Let's say
# primes is [2,3,5]. Our virtual streams are these:
#
# hammings: 1,2,3,4,5,6,8,10,12,15,16,18,20,...
# hammings*2: 2,4,6,9.10,12,16,20,24,30,32,36,40...
# hammings*3: 3,6,9,12,15,18,24,30,36,45,...
# hammings*5: 5,10,15,20,25,30,40,50,...
#
# After encountering 40 for the last time, our candidates
# will be
# 50 = 2 * 25
# 45 = 3 * 15
# 50 = 5 * 10
# Then, after 45
# 50 = 2 * 25
# 48 = 3 * 16 <= new
# 50 = 5 * 10
hamming_numbers = [1]
candidates = ([p, p, 1] for p in primes)
last_number = 1
while hamming_numbers.length < max_n
# Get the next candidate Hamming Number tuple.
i = min_idx(candidates)
candidate = candidates[i]
[n, p, seq_idx] = candidate
# Add to sequence unless it's a duplicate.
if n > last_number
hamming_numbers.push n
last_number = n
# Replace the candidate with its successor (based on
# p = 2, 3, or 5).
#
# This is the heart of the algorithm. Let's say, over the
# primes [2,3,5], we encounter the hamming number 32 based on it being
# 2 * 16, where 16 is the 12th number in the sequence.
# We'll be passed in [32, 2, 12] as candidate, and
# hamming_numbers will be [1,2,3,4,5,6,8,9,10,12,16,18,...]
# by now. The next candidate we need to enqueue is
# [36, 2, 13], where the numbers mean this:
#
# 36 - next multiple of 2 of a Hamming number
# 2 - prime number
# 13 - 1-based index of 18 in the sequence
#
# When we encounter [36, 2, 13], we will then enqueue
# [40, 2, 14], based on 20 being the 14th hamming number.
q = hamming_numbers[seq_idx]
candidates[i] = [p*q, p, seq_idx+1]
hamming_numbers
min_idx = (arr) ->
# Don't waste your time reading this--it just returns
# the index of the smallest tuple in an array, respecting that
# the tuples may contain integers. (CS compiles to JS, which is
# kind of stupid about sorting. There are libraries to work around
# the limitation, but I wanted this code to be standalone.)
less_than = (tup1, tup2) ->
i = 0
while i < tup2.length
return true if tup1[i] <= tup2[i]
return false if tup1[i] > tup2[i]
i += 1
min_i = 0
for i in [1...arr.length]
if less_than arr[i], arr[min_i]
min_i = i
return min_i
primes = [2, 3, 5]
numbers = generate_hamming_sequence(primes, 10000)
console.log numbers[1690]
console.log numbers[9999]

View file

@ -0,0 +1,20 @@
(defun next-hamm (factors seqs)
(let ((x (apply #'min (map 'list #'first seqs))))
(loop for s in seqs
for f in factors
for i from 0
with add = t do
(if (= x (first s)) (pop s))
;; prevent a value from being added to multiple lists
(when add
(setf (elt seqs i) (nconc s (list (* x f))))
(if (zerop (mod x f)) (setf add nil)))
finally (return x))))
(loop with factors = '(2 3 5)
with seqs = (loop for i in factors collect '(1))
for n from 1 to 1000001 do
(let ((x (next-hamm factors seqs)))
(if (or (< n 21)
(= n 1691)
(= n 1000000)) (format t "~d: ~d~%" n x))))

View file

@ -0,0 +1,20 @@
(defun hamming (n)
(let ((fac '(2 3 5))
(idx (make-array 3 :initial-element 0))
(h (make-array (1+ n)
:initial-element 1
:element-type 'integer)))
(loop for i from 1 to n
with e with x = '(1 1 1) do
(setf e (setf (aref h i) (apply #'min x))
x (loop for y in x
for f in fac
for j from 0
collect (if (= e y) (* f (aref h (incf (aref idx j)))) y))))
(aref h n)))
(loop for i from 1 to 20 do
(format t "~2d: ~d~%" i (hamming i)))
(loop for i in '(1691 1000000) do
(format t "~d: ~d~%" i (hamming i)))

View file

@ -0,0 +1,23 @@
import std.stdio, std.bigint, std.algorithm, std.range;
auto hamming(in int n) {
BigInt two = 2, three = 3, five = 5;
auto h = new BigInt[n];
h[0] = 1;
BigInt x2 = 2, x3 = 3, x5 = 5;
int i, j, k;
foreach (ref el; h[1 .. $]) {
el = min(x2, x3, x5);
if (el == x2) x2 = two * h[++i];
if (el == x3) x3 = three * h[++j];
if (el == x5) x5 = five * h[++k];
}
return h.back;
}
void main() {
iota(1, 21).map!hamming.writeln;
1_691.hamming.writeln;
1_000_000.hamming.writeln;
}

View file

@ -0,0 +1,23 @@
import std.stdio,std.bigint,std.container,std.algorithm,std.range;
BigInt hamming(int n)
in {
assert(n > 0);
} body {
auto frontier = redBlackTree(BigInt(2), BigInt(3), BigInt(5));
auto lowest = BigInt(1);
foreach (_; 1 .. n) {
lowest = frontier.front();
frontier.removeFront();
frontier.insert(lowest * 2);
frontier.insert(lowest * 3);
frontier.insert(lowest * 5);
}
return lowest;
}
void main() {
writeln("First 20 Hamming numbers: ", map!hamming(iota(1, 21)));
writeln("hamming(1691) = ", hamming(1691));
writeln("hamming(1_000_000) = ", hamming(1_000_000));
}

View file

@ -0,0 +1,107 @@
import std.stdio: writefln;
import std.bigint: BigInt, toDecimalString;
import std.numeric: gcd;
import std.algorithm: copy, map;
import std.math; // log, ^^
// Number of factors.
enum NK = 3;
enum MAX_HAM = 10_000_000;
static assert(gcd(NK, MAX_HAM) == 1);
enum int[NK] fac = [2, 3, 5];
/// k-smooth numbers (stored as their exponents of each factor).
struct Hamming {
double v; // log of the number, for convenience.
ushort[NK] e; // exponents of each factor.
// Compile-time constant, map!log(fac)
// log can't be used in CTFE yet
public static __gshared const double[fac.length] inc;
nothrow pure static this() {
//map!log(fac[]).copy(inc[]); // Not nothrow, not const.
foreach (i, f; fac)
inc[i] = log(f);
}
bool opEquals(in ref Hamming y) const pure nothrow {
//return this.e == y.e; // too much slow
foreach (size_t i; 0 .. this.e.length)
if (this.e[i] != y.e[i])
return false;
return true;
}
void update() pure nothrow {
//this.v = dotProduct(inc, this.e); // too much slow
this.v = 0.0;
foreach (size_t i; 0 .. this.e.length)
this.v += inc[i] * this.e[i];
}
string toString() const {
BigInt result = 1;
foreach (size_t i, f; fac)
result *= BigInt(f) ^^ this.e[i];
return toDecimalString(result);
}
}
// Global variables.
__gshared Hamming[] hams;
__gshared Hamming[NK] values;
nothrow static this() {
// Slower than malloc if you don't use all the MAX_HAM items.
hams = new Hamming[MAX_HAM];
foreach (i, ref v; values) {
v.e[i] = 1;
v.v = Hamming.inc[i];
}
}
ref Hamming getHam(in size_t n) nothrow
in {
assert(n <= MAX_HAM);
} body {
// Most of the time v can be just incremented, but eventually
// floating point precision will bite us, so better recalculate.
__gshared static size_t[NK] idx;
__gshared static int n_hams;
for (; n_hams < n; n_hams++) {
{
// Find the index of the minimum v.
size_t ni = 0;
foreach (size_t i; 1 .. NK)
if (values[i].v < values[ni].v)
ni = i;
hams[n_hams] = values[ni];
hams[n_hams].update();
}
foreach (size_t i; 0 .. NK)
if (values[i] == hams[n_hams]) {
values[i] = hams[idx[i]];
idx[i]++;
values[i].e[i]++;
values[i].update();
}
}
return hams[n - 2];
}
void main() {
foreach (n; [1691, 10 ^^ 6, MAX_HAM])
writefln("%8d: %s", n, getHam(n));
}

View file

@ -0,0 +1,77 @@
note
description : "Initial part, in order, of the sequence of Hamming numbers"
math : "[
Hamming numbers, also known as regular numbers and 5-smooth numbers, are natural integers
that have 2, 3 and 5 as their only prime factors.
]"
computer_arithmetic :
"[
This version avoids integer overflow and stops at the last representable number in the sequence.
]"
output : "[
Per requirements of the RosettaCode example, execution will produce items of indexes 1 to 20 and 1691.
The algorithm (procedure `hamming') is more general and will produce the first `n' Hamming numbers
for any `n'.
]"
source : "This problem was posed in Edsger W. Dijkstra, A Discipline of Programming, Prentice Hall, 1978"
date : "8 August 2012"
authors : "Bertrand Meyer", "Emmanuel Stapf"
revision : "1.0"
libraries : "Relies on SORTED_TWO_WAY_LIST from EiffelBase"
implementation : "[
Using SORTED_TWO_WAY_LIST provides an elegant illustration of how to implement
a lazy scheme in Eiffel through the use of object-oriented data structures.
]"
warning : "[
The formatting (<lang>) specifications for Eiffel in RosettaCode are slightly obsolete:
`note' and other newer keywords not supported, red color for manifest strings.
This should be fixed soon.
]"
class
APPLICATION
create
make
feature {NONE} -- Initialization
make
-- Print first 20 Hamming numbers, in order, and the 1691-st one.
local
Hammings: like hamming
-- List of Hamming numbers, up to 1691-st one.
do
Hammings := hamming (1691)
across 1 |..| 20 as i loop
io.put_natural (Hammings.i_th (i.item)); io.put_string (" ")
end
io.put_new_line; io.put_natural (Hammings.i_th (1691)); io.put_new_line
end
feature -- Basic operations
hamming (n: INTEGER): ARRAYED_LIST [NATURAL]
-- First `n' elements (in order) of the Hamming sequence,
-- or as many of them as will not produce overflow.
local
sl: SORTED_TWO_WAY_LIST [NATURAL]
overflow: BOOLEAN
first, next: NATURAL
do
create Result.make (n); create sl.make
sl.extend (1); sl.start
across 1 |..| n as i invariant
-- "The numbers output so far are the first `i' - 1 Hamming numbers, in order".
-- "Result.first is the `i'-th Hamming number."
until sl.is_empty loop
first := sl.first; sl.start
Result.extend (first); sl.remove
across << 2, 3, 5 >> as multiplier loop
next := multiplier.item * first
overflow := overflow or next <= first
if not overflow and then not sl.has (next) then sl.extend (next) end
end
end
end
end

View file

@ -0,0 +1,32 @@
USING: accessors deques dlists fry kernel make math math.order
;
IN: rosetta.hamming
TUPLE: hamming-iterator 2s 3s 5s ;
: <hamming-iterator> ( -- hamming-iterator )
hamming-iterator new
1 1dlist >>2s
1 1dlist >>3s
1 1dlist >>5s ;
: enqueue ( n hamming-iterator -- )
[ [ 2 * ] [ 2s>> ] bi* push-back ]
[ [ 3 * ] [ 3s>> ] bi* push-back ]
[ [ 5 * ] [ 5s>> ] bi* push-back ] 2tri ;
: next ( hamming-iterator -- n )
dup [ 2s>> ] [ 3s>> ] [ 5s>> ] tri
3dup [ peek-front ] tri@ min min
[
'[
dup peek-front _ =
[ pop-front* ] [ drop ] if
] tri@
] [ swap enqueue ] [ ] tri ;
: next-n ( hamming-iterator n -- seq )
swap '[ _ [ _ next , ] times ] { } make ;
: nth-from-now ( hamming-iterator n -- m )
1 - over '[ _ next drop ] times next ;

View file

@ -0,0 +1,18 @@
USING: combinators fry kernel lists lists.lazy locals math ;
IN: rosetta.hamming-lazy
:: sort-merge ( xs ys -- result )
xs car :> x
ys car :> y
{
{ [ x y < ] [ [ x ] [ xs cdr ys sort-merge ] lazy-cons ] }
{ [ x y > ] [ [ y ] [ ys cdr xs sort-merge ] lazy-cons ] }
[ [ x ] [ xs cdr ys cdr sort-merge ] lazy-cons ]
} cond ;
:: hamming ( -- hamming )
f :> h!
[ 1 ] [
h 2 3 5 [ '[ _ * ] lazy-map ] tri-curry@ tri
sort-merge sort-merge
] lazy-cons h! h ;

View file

@ -0,0 +1,92 @@
\ manipulating and computing with Hamming numbers:
: extract2 ( h -- l )
40 rshift ;
: extract3 ( h -- m )
20 rshift $fffff and ;
: extract5 ( h -- n )
$fffff and ;
' + alias h* ( h1 h2 -- h )
: h. { h -- }
." 2^" h extract2 0 .r
." *3^" h extract3 0 .r
." *5^" h extract5 . ;
\ the following numbers have been produced with bc -l as follows
1 62 lshift constant ldscale2
7309349404307464679 constant ldscale3 \ 2^62*l(3)/l(2) (rounded up)
10708003330985790206 constant ldscale5 \ 2^62*l(5)/l(2) (rounded down)
: hld { h -- ud }
\ ud is a scaled fixed-point representation of the logarithm dualis of h
h extract2 ldscale2 um*
h extract3 ldscale3 um* d+
h extract5 ldscale5 um* d+ ;
: h<= ( h1 h2 -- f )
2dup = if
2drop true exit
then
hld rot hld assert( 2over 2over d<> )
du>= ;
: hmin ( h1 h2 -- h )
2dup h<= if
drop
else
nip
then ;
\ actual algorithm
0 value seq
variable seqlast 0 seqlast !
: lastseq ( -- u )
\ last stored number in the sequence
seq seqlast @ th @ ;
: genseq ( h1 "name" -- )
\ h1 is the factor for the sequence
create , 0 , \ factor and index of element used for last return
does> ( -- u2 )
\ u2 is the next number resulting from multiplying h1 with numbers
\ in the sequence that is larger than the last number in the
\ sequence
dup @ lastseq { h1 l } cell+ dup @ begin ( index-addr index )
seq over th @ h1 h* dup l h<= while
drop 1+ repeat
>r swap ! r> ;
$10000000000 genseq s2
$00000100000 genseq s3
$00000000001 genseq s5
: nextseq ( -- )
s2 s3 hmin s5 hmin , 1 seqlast +! ;
: nthseq ( u1 -- h )
\ the u1 th element in the sequence
dup seqlast @ u+do
nextseq
loop
1- 0 max cells seq + @ ;
: .nseq ( u1 -- )
dup seqlast @ u+do
nextseq
loop
0 u+do
seq i th @ h.
loop ;
here to seq
0 , \ that's 1
20 .nseq
cr 1691 nthseq h.
cr 1000000 nthseq h.

View file

@ -0,0 +1,72 @@
program Hamming_Test
use big_integer_module
implicit none
call Hamming(1,20)
write(*,*)
call Hamming(1691)
write(*,*)
call Hamming(1000000)
contains
subroutine Hamming(first, last)
integer, intent(in) :: first
integer, intent(in), optional :: last
integer :: i, n, i2, i3, i5, lim
type(big_integer), allocatable :: hnums(:)
if(present(last)) then
lim = last
else
lim = first
end if
if(first < 1 .or. lim > 2500000 ) then
write(*,*) "Invalid input"
return
end if
allocate(hnums(lim))
i2 = 1 ; i3 = 1 ; i5 = 1
hnums(1) = 1
n = 1
do while(n < lim)
n = n + 1
hnums(n) = mini(2*hnums(i2), 3*hnums(i3), 5*hnums(i5))
if(2*hnums(i2) == hnums(n)) i2 = i2 + 1
if(3*hnums(i3) == hnums(n)) i3 = i3 + 1
if(5*hnums(i5) == hnums(n)) i5 = i5 + 1
end do
if(present(last)) then
do i = first, last
call print_big(hnums(i))
write(*, "(a)", advance="no") " "
end do
else
call print_big(hnums(first))
end if
deallocate(hnums)
end subroutine
function mini(a, b, c)
type(big_integer) :: mini
type(big_integer), intent(in) :: a, b, c
if(a < b ) then
if(a < c) then
mini = a
else
mini = c
end if
else if(b < c) then
mini = b
else
mini = c
end if
end function mini
end program

View file

@ -0,0 +1,35 @@
package main
import (
"fmt"
"math/big"
)
func min(a, b *big.Int) *big.Int {
if a.Cmp(b) < 0 {
return a
}
return b
}
func hamming(n int) []*big.Int {
h := make([]*big.Int, n)
h[0] = big.NewInt(1)
two, three, five := big.NewInt(2), big.NewInt(3), big.NewInt(5)
next2, next3, next5 := big.NewInt(2), big.NewInt(3), big.NewInt(5)
i, j, k := 0, 0, 0
for m := 1; m < len(h); m++ {
h[m] = new(big.Int).Set(min(next2, min(next3, next5)))
if h[m].Cmp(next2) == 0 { i++; next2.Mul( two, h[i]) }
if h[m].Cmp(next3) == 0 { j++; next3.Mul(three, h[j]) }
if h[m].Cmp(next5) == 0 { k++; next5.Mul( five, h[k]) }
}
return h
}
func main() {
h := hamming(1e6)
fmt.Println(h[:20])
fmt.Println(h[1691-1])
fmt.Println(h[len(h)-1])
}

View file

@ -0,0 +1,99 @@
package main
import (
"flag"
"fmt"
"math"
"math/big"
"os"
)
var ordinal int // ordinal of last sequence element to compute
var sequenceMode bool // print the whole sequence or just one element?
var lg3, lg5 float64 // precomputed base-2 logarithms for 3 and 5
var table [][3]int16 // table for dynamic-programming stored results
var front [3]cursor // state of the three multiplied sequences
type cursor struct {
f int // index (0, 1, 2) corresponding to factor (2, 3, 5)
i int // index into table for the entry being multiplied
lg float64 // base-2 logarithm of the multiple (for ordering)
}
func (c *cursor) value() [3]int16 {
x := table[c.i]
x[c.f]++ // multiply by incrementing the exponent
return x
}
func (c *cursor) advance() {
c.i++
// skip entries that would produce duplicates
for (c.f < 2 && table[c.i][2] > 0) || (c.f < 1 && table[c.i][1] > 0) {
c.i++
}
x := c.value()
c.lg = float64(x[0]) + lg3*float64(x[1]) + lg5*float64(x[2])
}
func step() {
table = append(table, front[0].value())
front[0].advance()
// re-establish sorted order
if front[0].lg > front[1].lg {
front[0], front[1] = front[1], front[0]
if front[1].lg > front[2].lg {
front[1], front[2] = front[2], front[1]
}
}
}
func show(elem [3]int16) {
z := big.NewInt(1)
for i, base := range []int64{2, 3, 5} {
b := big.NewInt(base)
x := big.NewInt(int64(elem[i]))
z.Mul(z, b.Exp(b, x, nil))
}
fmt.Println(z)
}
func fail(msg string) {
fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], msg)
os.Exit(1)
}
func parse() {
flag.Parse()
if flag.NArg() != 1 {
fail("need one argument")
}
_, err := fmt.Sscan(flag.Arg(0), &ordinal)
if err != nil || ordinal <= 0 {
fail("argument must be a positive integer")
}
}
func init() {
flag.BoolVar(&sequenceMode, "s", false, "sequence mode")
lg3 = math.Log2(3)
lg5 = math.Log2(5)
front = [3]cursor{
{0, 0, 1}, // 2
{1, 0, lg3}, // 3
{2, 0, lg5}, // 5
}
}
func main() {
parse()
table = make([][3]int16, 1, ordinal)
for i, n := 1, ordinal; i < n; i++ {
if sequenceMode {
show(table[i-1])
}
step()
}
show(table[ordinal-1])
}

View file

@ -0,0 +1,16 @@
hamming = 1 : map (2*) hamming `union` map (3*) hamming `union` map (5*) hamming
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
print $ take 20 hamming
print (hamming !! (1691-1), hamming !! (1692-1))
print $ hamming !! (1000000-1)
-- Output:
-- [1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36]
-- (2125764000,2147483648)
-- 519312780448388736089589843750000000000000000000000000000000000000000000000000000000

View file

@ -0,0 +1,12 @@
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
main = do
print $ take 20 hamming
print $ hamming !! 1690
print $ hamming !! (1000000-1)

View file

@ -0,0 +1 @@
hamm n = drop n $ iterate (\(_,(a:t))-> (a,union t [2*a,3*a,5*a])) (0,[1])

View file

@ -0,0 +1,20 @@
*Main> map fst $ take 20 $ hamm 1
[1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36]
*Main> map fst $ take 2 $ hamm 1691
[2125764000,2147483648]
*Main> mapM_ print $ take 10 $ hamm 1
(1,[2,3,5])
(2,[3,4,5,6,10])
(3,[4,5,6,9,10,15])
(4,[5,6,8,9,10,12,15,20])
(5,[6,8,9,10,12,15,20,25])
(6,[8,9,10,12,15,18,20,25,30])
(8,[9,10,12,15,16,18,20,24,25,30,40])
(9,[10,12,15,16,18,20,24,25,27,30,40,45])
(10,[12,15,16,18,20,24,25,27,30,40,45,50])
(12,[15,16,18,20,24,25,27,30,36,40,45,50,60])
*Main> map (length.snd.head.hamm) [2000,4000,8000,16000]
[402,638,1007,1596]

View file

@ -0,0 +1,44 @@
-- 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
{-# OPTIONS -O2 -XBangPatterns #-}
import Data.List (sortBy)
import Data.Function (on)
main = do { let (r,t) = nthHam 1000000
; sequence_ [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
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
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 = res
where
(d,w) = rngval n -- correction dist, width
hi = estval n - d -- hi > logval > hi-w
(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
(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) }

View file

@ -0,0 +1,53 @@
# Lazily generate the three Hamming numbers that can be derived directly
# from a known Hamming number h
class Triplet : Class (cv, ce)
method nextVal()
suspend cv := @ce
end
initially (baseNum)
cv := 2*baseNum
ce := create (3|5)*baseNum
end
# Generate Hamming numbers, in order. Default is first 30
# But an optional argument can be used to generate more (or less)
# e.g. hamming 5000 generates the first 5000.
procedure main(args)
limit := integer(args[1]) | 30
every write("\t", generateHamming() \ limit)
end
# Do the work. Start with known Hamming number 1 and maintain
# a set of triplet Hamming numbers as they get derived from that
# one. Most of the code here is to figure out which Hamming
# number is next in sequence (while removing duplicates)
procedure generateHamming()
triplers := set()
insert(triplers, Triplet(1))
suspend 1
repeat {
# Pick a Hamming triplet that *may* have the next smallest number
t1 := !triplers # any will do to start
every t1 ~=== (t2 := !triplers) do {
if t1.cv > t2.cv then {
# oops we were wrong, switch assumption
t1 := t2
}
else if t1.cv = t2.cv then {
# t2's value is a duplicate, so
# advance triplet t2, if none left in t2, remove it
t2.nextVal() | delete(triplers, t2)
}
}
# Ok, t1 has the next Hamming number, grab it
suspend t1.cv
insert(triplers, Triplet(t1.cv))
# Advance triplet t1, if none left in t1, remove it
t1.nextVal() | delete(triplers, t1)
}
end

View file

@ -0,0 +1 @@
hamming=: {. (/:~@~.@], 2 3 5 * {)/ @ (1x,~i.@-)

View file

@ -0,0 +1,5 @@
hamming 20
1 2 3 4 5 6 8 9 10 12 15 16 18 20 24 25 27 30 32 36
{: hamming 1691
2125764000

View file

@ -0,0 +1 @@
/:~@~.@]

View file

@ -0,0 +1 @@
2 3 5 * {

View file

@ -0,0 +1 @@
2 3 5 * LHA { RHA

View file

@ -0,0 +1 @@
(1x,~i.@-)

View file

@ -0,0 +1,2 @@
({. (/:~@~.@], 2 3 5 * {)/ @ (1x,~i.@-)) 7
1 2 3 4 5 6 8

View file

@ -0,0 +1,2 @@
(1x,~i.@-) 7
6 5 4 3 2 1 0 1

View file

@ -0,0 +1,2 @@
6(/:~@~.@], 2 3 5 * {) 5(/:~@~.@], 2 3 5 * {) 4(/:~@~.@], 2 3 5 * {) 3(/:~@~.@], 2 3 5 * {) 2(/:~@~.@], 2 3 5 * {) 1(/:~@~.@], 2 3 5 * {) 0(/:~@~.@], 2 3 5 * {) 1
1 2 3 4 5 6 8 9 10 12 15 18 20 25 30 16 24 40

View file

@ -0,0 +1,37 @@
import java.math.BigInteger;
import java.util.PriorityQueue;
final class Hamming {
private static BigInteger THREE = BigInteger.valueOf(3);
private static BigInteger FIVE = BigInteger.valueOf(5);
private static void updateFrontier(BigInteger x,
PriorityQueue<BigInteger> pq) {
pq.offer(x.shiftLeft(1));
pq.offer(x.multiply(THREE));
pq.offer(x.multiply(FIVE));
}
public static BigInteger hamming(int n) {
if (n <= 0)
throw new IllegalArgumentException("Invalid parameter");
PriorityQueue<BigInteger> frontier = new PriorityQueue<BigInteger>();
updateFrontier(BigInteger.ONE, frontier);
BigInteger lowest = BigInteger.ONE;
for (int i = 1; i < n; i++) {
lowest = frontier.poll();
while (frontier.peek().equals(lowest))
frontier.poll();
updateFrontier(lowest, frontier);
}
return lowest;
}
public static void main(String[] args) {
System.out.print("Hamming(1 .. 20) =");
for (int i = 1; i < 21; i++)
System.out.print(" " + hamming(i));
System.out.println("\nHamming(1691) = " + hamming(1691));
System.out.println("Hamming(1000000) = " + hamming(1000000));
}
}

View file

@ -0,0 +1,27 @@
function hamming() {
var queues = {2: [], 3: [], 5: []};
var base;
var next_ham = 1;
while (true) {
yield next_ham;
for (base in queues) {queues[base].push(next_ham * base)}
next_ham = [ queue[0] for each (queue in queues) ].reduce(function(min, val) {
return Math.min(min,val)
});
for (base in queues) {if (queues[base][0] == next_ham) queues[base].shift()}
}
}
var ham = hamming();
var first20=[], i=1;
for (; i <= 20; i++)
first20.push(ham.next());
print(first20.join(', '));
print('...');
for (; i <= 1690; i++)
ham.next();
print(i + " => " + ham.next());

View file

@ -0,0 +1,98 @@
<html>
<head></head>
<body>
<div id="main"></div>
</body>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script src="http://peterolson.github.com/BigInteger.js/BigInteger.min.js"></script>
<script type="text/javascript">
var _primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37];
function log(text) {
$('#main').append(text + "\n");
}
function big(exponents) {
var i, e, val = bigInt.one;
for (i = 0; i < exponents.length; i++)
for (e = 0; e < exponents[i]; e++)
val = val.times(_primes[i]);
return val.toString();
}
function hamming(n, nprimes) {
var i, iter, p, q, min, equal, x;
var hammings = new Array(n); // array of hamming #s we generate
hammings[0] = new Array(nprimes);
for (p = 0; p < nprimes; p++) {
hammings[0][p] = 0;
}
var hammlogs = new Array(n); // log values for above
hammlogs[0] = 0;
var primelogs = new Array(nprimes); // pre-calculated prime log values
var listlogs = new Array(nprimes); // log values of list heads
for (p = 0; p < nprimes; p++) {
primelogs[p] = listlogs[p] = Math.log(_primes[p]);
}
var indexes = new Array(nprimes); // intermediate hamming values as indexes into hammings
for (p = 0; p < nprimes; p++) {
indexes[p] = 0;
}
var listheads = new Array(nprimes); // intermediate hamming list heads
for (p = 0; p < nprimes; p++) {
listheads[p] = new Array(nprimes);
for (q = 0; q < nprimes; q++) {
listheads[p][q] = 0;
}
listheads[p][p] = 1;
}
for (iter = 1; iter < n; iter++) {
min = 0;
for (p = 1; p < nprimes; p++)
if (listlogs[p] < listlogs[min])
min = p;
hammlogs[iter] = listlogs[min]; // that's the next hamming number
hammings[iter] = listheads[min].slice();
for (p = 0; p < nprimes; p++) { // update each list head if it matches new value
equal = true; // test each exponent to see if number matches
for (i = 0; i < nprimes; i++) {
if (hammings[iter][i] != listheads[p][i]) {
equal = false;
break;
}
}
if (equal) { // if it matches...
x = ++indexes[p]; // set index to next hamming number
listheads[p] = hammings[x].slice(); // copy hamming number
listheads[p][p] += 1; // increment exponent = mult by prime
listlogs[p] = hammlogs[x] + primelogs[p]; // add log(prime) to log(value) = mult by prime
}
}
}
return hammings[n - 1];
}
$(document).ready(function() {
var i, nprimes;
var t = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,1691,1000000];
for (nprimes = 3; nprimes <= 4; nprimes++) {
var start = new Date();
log('<h1>' + _primes[nprimes - 1] + '-Smooth:' + '</h1>');
log('<table>');
for (i = 0; i < t.length; i++)
log('<tr>' + '<td>' + t[i] + ':' + '</td><td>' + big(hamming(t[i], nprimes)) + '</td>');
var end = new Date();
log('<tr>' + '<td>' + 'Elapsed time:' + '</td><td>' + (end-start)/1000 + ' seconds' + '</td>');
log('</table>');
}
});
</script>
</html>

View file

@ -0,0 +1,24 @@
dim h( 1000000)
for i =1 to 20
print hamming( i); " ";
next i
print
print "H( 1691)", hamming( 1691)
print "H( 1000000)", hamming( 1000000)
end
function hamming( limit)
h( 0) =1
x2 =2: x3 =3: x5 =5
i =0: j =0: k =0
for n =1 to limit
h( n) = min( x2, min( x3, x5))
if x2 = h( n) then i = i +1: x2 =2 *h( i)
if x3 = h( n) then j = j +1: x3 =3 *h( j)
if x5 = h( n) then k = k +1: x5 =5 *h( k)
next n
hamming =h( limit -1)
end function

View file

@ -0,0 +1,26 @@
to init.ham
; queues
make "twos [1]
make "threes [1]
make "fives [1]
end
to next.ham
localmake "ham first :twos
if less? first :threes :ham [make "ham first :threes]
if less? first :fives :ham [make "ham first :fives]
if equal? :ham first :twos [ignore dequeue "twos]
if equal? :ham first :threes [ignore dequeue "threes]
if equal? :ham first :fives [ignore dequeue "fives]
queue "twos :ham * 2
queue "threes :ham * 3
queue "fives :ham * 5
output :ham
end
init.ham
repeat 20 [print next.ham]
repeat 1690-20 [ignore next.ham]
print next.ham

View file

@ -0,0 +1,24 @@
function hiter()
hammings = {1}
prev, vals = {1, 1, 1}
index = 1
local function nextv()
local n, v = 1, hammings[prev[1]]*2
if hammings[prev[2]]*3 < v then n, v = 2, hammings[prev[2]]*3 end
if hammings[prev[3]]*5 < v then n, v = 3, hammings[prev[3]]*5 end
prev[n] = prev[n] + 1
if hammings[index] == v then return nextv() end
index = index + 1
hammings[index] = v
return v
end
return nextv
end
j = hiter()
for i = 1, 20 do
print(j())
end
n, l = 0, 0
while n < 2^31 do n, l = j(), n end
print(l)

View file

@ -0,0 +1,34 @@
Hamming(n) New count,ok,next,number,which
For which=2,3,5 Set number=1
For count=1:1:n Do
. Set ok=0 Set:count<21 ok=1 Set:count=1691 ok=1 Set:count=n ok=1
. Write:ok !,$Justify(count,5),": ",number
. For which=2,3,5 Set next(number*which)=which
. Set number=$Order(next(""))
. Kill next(number)
. Quit
Quit
Do Hamming(2000)
1: 1
2: 2
3: 3
4: 4
5: 5
6: 6
7: 8
8: 9
9: 10
10: 12
11: 15
12: 16
13: 18
14: 20
15: 24
16: 25
17: 27
18: 30
19: 32
20: 36
1691: 2125764000
2000: 8062156800

View file

@ -0,0 +1,3 @@
HammingList[N_] := Module[{A, B, C}, {A, B, C} = (N^(1/3))*{2.8054745679851933, 1.7700573778298891, 1.2082521307023026} - {1, 1, 1};
Take[ Sort@Flatten@Table[ 2^x * 3^y * 5^z ,
{x, 0, A}, {y, 0, (-B/A)*x + B}, {z, 0, C - (C/A)*x - (C/B)*y}], N]];

View file

@ -0,0 +1,25 @@
use List::Util 'min';
sub ham_gen {
my @s = ([1], [1], [1]);
my @m = (2, 3, 5);
return sub {
# use bigint;
my $n = min($s[0][0], $s[1][0], $s[2][0]);
for (0 .. 2) {
shift @{$s[$_]} if $s[$_][0] == $n;
push @{$s[$_]}, $n * $m[$_]
}
return $n
}
}
my ($h, $i) = ham_gen;
++$i, print $h->(), " " until $i > 20;
print "...\n";
++$i, $h->() until $i == 1690;
print ++$i, "-th: ", $h->(), "\n";

View file

@ -0,0 +1,13 @@
(de hamming (N)
(let (L (1) H)
(do N
(for (X L X (cadr X)) # Find smallest result
(setq H (car X)) )
(idx 'L H NIL) # Remove it
(for I (2 3 5) # Generate next results
(idx 'L (* I H) T) ) )
H ) )
(println (make (for N 20 (link (hamming N)))))
(println (hamming 1691))
(println (hamming 1000000))

View file

@ -0,0 +1,21 @@
%% collect N elements produced by a generator in a row
take( 0, Next, Z-Z, Next).
take( N, Next, [A|B]-Z, NZ):- N>0, !, next(Next,A,Next1),
N1 is N-1,
take(N1,Next1,B-Z,NZ).
%% a generator provides specific {next} implementation
next( hamm( A2,B,C3,D,E5,F,[H|G] ), H, hamm(X,U,Y,V,Z,W,G) ):-
H is min(A2, min(C3,E5)),
( A2 =:= H -> B=[N2|U],X is N2*2 ; (X,U)=(A2,B) ),
( C3 =:= H -> D=[N3|V],Y is N3*3 ; (Y,V)=(C3,D) ),
( E5 =:= H -> F=[N5|W],Z is N5*5 ; (Z,W)=(E5,F) ).
mkHamm( hamm(1,X,1,X,1,X,X) ). % Hamming numbers generator init state
main(N) :-
mkHamm(G),take(20,G,A-[],_), write(A), nl,
take(1691-1,G,_,G2),take(2,G2,B-[],_), write(B), nl,
take( N -1,G,_,G3),take(2,G3,[C1|_]-_,_), write(C1), nl.

View file

@ -0,0 +1,74 @@
hamming(N) :-
% to stop cleanly
nb_setval(go, 1),
% display list
( N = 20 -> watch_20(20, L); watch(1,N,L)),
% go
L=[1|L235],
multlist(L,2,L2),
multlist(L,3,L3),
multlist(L,5,L5),
merge_(L2,L3,L23),
merge_(L5,L23,L235).
%% multlist(L,N,LN)
%% multiply each element of list L with N, resulting in list LN
%% here only do multiplication for 1st element, then use multlist recursively
multlist([X|L],N,XLN) :-
% the trick to stop
nb_getval(go, 1) ->
% laziness flavor
when(ground(X),
( XN is X*N,
XLN=[XN|LN],
multlist(L,N,LN)));
true.
merge_([X|In1],[Y|In2],XYOut) :-
% the trick to stop
nb_getval(go, 1) ->
% laziness flavor
( X < Y -> XYOut = [X|Out], In11 = In1, In12 = [Y|In2]
; X = Y -> XYOut = [X|Out], In11 = In1, In12 = In2
; XYOut = [Y|Out], In11 = [X | In1], In12 = In2),
freeze(In11,freeze(In12, merge_(In11,In12,Out)));
true.
%% display nth element
watch(Max, Max, [X|_]) :-
% laziness flavor
when(ground(X),
(format('~w~n', [X]),
% the trick to stop
nb_linkval(go, 0))).
watch(N, Max, [_X|L]):-
N1 is N + 1,
watch(N1, Max, L).
%% display nth element
watch_20(1, [X|_]) :-
% laziness flavor
when(ground(X),
(format('~w~n', [X]),
% the trick to stop
nb_linkval(go, 0))).
watch_20(N, [X|L]):-
% laziness flavor
when(ground(X),
(format('~w ', [X]),
N1 is N - 1,
watch_20(N1, L))).

View file

@ -0,0 +1,41 @@
from itertools import islice
def hamming2():
'''\
This version is based on a snippet from:
http://dobbscodetalk.com/index.php?option=com_content&task=view&id=913&Itemid=85
When expressed in some imaginary pseudo-C with automatic
unlimited storage allocation and BIGNUM arithmetics, it can be
expressed as:
hamming = h where
array h;
n=0; h[0]=1; i=0; j=0; k=0;
x2=2*h[ i ]; x3=3*h[j]; x5=5*h[k];
repeat:
h[++n] = min(x2,x3,x5);
if (x2==h[n]) { x2=2*h[++i]; }
if (x3==h[n]) { x3=3*h[++j]; }
if (x5==h[n]) { x5=5*h[++k]; }
'''
h = 1
_h=[h] # memoized
multipliers = (2, 3, 5)
multindeces = [0 for i in multipliers] # index into _h for multipliers
multvalues = [x * _h[i] for x,i in zip(multipliers, multindeces)]
yield h
while True:
h = min(multvalues)
_h.append(h)
for (n,(v,x,i)) in enumerate(zip(multvalues, multipliers, multindeces)):
if v == h:
i += 1
multindeces[n] = i
multvalues[n] = x * _h[i]
# cap the memoization
mini = min(multindeces)
if mini >= 1000:
del _h[:mini]
multindeces = [i - mini for i in multindeces]
#
yield h

View file

@ -0,0 +1,25 @@
import psyco
def hamming(limit):
h = [1] * limit
x2, x3, x5 = 2, 3, 5
i = j = k = 0
for n in xrange(1, limit):
h[n] = min(x2, x3, x5)
if x2 == h[n]:
i += 1
x2 = 2 * h[i]
if x3 == h[n]:
j += 1
x3 = 3 * h[j]
if x5 == h[n]:
k += 1
x5 = 5 * h[k]
return h[-1]
psyco.bind(hamming)
print [hamming(i) for i in xrange(1, 21)]
print hamming(1691)
print hamming(1000000)

View file

@ -0,0 +1,25 @@
from itertools import tee, chain, groupby, islice
from heapq import merge
def raymonds_hamming():
# Generate "5-smooth" numbers, also called "Hamming numbers"
# or "Regular numbers". See: http://en.wikipedia.org/wiki/Regular_number
# Finds solutions to 2**i * 3**j * 5**k for some integers i, j, and k.
def deferred_output():
for i in output:
yield i
result, p2, p3, p5 = tee(deferred_output(), 4)
m2 = (2*x for x in p2) # multiples of 2
m3 = (3*x for x in p3) # multiples of 3
m5 = (5*x for x in p5) # multiples of 5
merged = merge(m2, m3, m5)
combined = chain([1], merged) # prepend a starting point
output = (k for k,g in groupby(combined)) # eliminate duplicates
return result
print list(islice(raymonds_hamming(), 20))
print islice(raymonds_hamming(), 1689, 1690).next()
print islice(raymonds_hamming(), 999999, 1000000).next()

View file

@ -0,0 +1,13 @@
from heapq import merge
from itertools import tee
def hamming_numbers():
last = 1
yield last
a,b,c = tee(hamming_numbers(), 3)
for n in merge((2*i for i in a), (3*i for i in b), (5*i for i in c)):
if n != last:
yield n
last = n

View file

@ -0,0 +1,38 @@
from itertools import islice, chain, tee
def merge(r, s):
# This is faster than heapq.merge.
rr = r.next()
ss = s.next()
while True:
if rr < ss:
yield rr
rr = r.next()
else:
yield ss
ss = s.next()
def p(n):
def gen():
x = n
while True:
yield x
x *= n
return gen()
def pp(n, s):
def gen():
for x in (merge(s, chain([n], (n * y for y in fb)))):
yield x
r, fb = tee(gen())
return r
def hamming(a, b = None):
if not b:
b = a + 1
seq = (chain([1], pp(5, pp(3, p(2)))))
return list(islice(seq, a - 1, b - 1))
print hamming(1, 21)
print hamming(1691)[0]
print hamming(1000000)[0]

View file

@ -0,0 +1,12 @@
hamming=function(hamms,limit) {
tmp=hamms
for(h in c(2,3,5)) {
tmp=c(tmp,h*hamms)
}
tmp=unique(tmp[tmp<=limit])
if(length(tmp)>length(hamms)) {
hamms=hamming(tmp,limit)
}
hamms
}
sort(hamming(1,limit=2^31)[-1])

View file

@ -0,0 +1,23 @@
/*REXX program computes Hamming numbers: 1──►20, #1691, one millionth.*/
numeric digits 100 /*ensure we have enough precision*/
call hamming 1, 20 /*show the first ──► twentieth #s*/
call hamming 1691 /*show the 1,691st Hamming number*/
call hamming 1000000 /*show the one millionth number*/
call hamming 10000000 /*show the 10th millionth number*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────HAMMING subroutine──────────────────*/
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 three pigs.*/
if 2*@.#2 == @.n then #2 = #2+1 /*# already defined? Use next #.*/
if 3*@.#3 == @.n then #3 = #3+1 /*" " " " " " */
if 5*@.#5 == @.n then #5 = #5+1 /*" " " " " " */
end /*n*/
do j=x to y /*W is used to align the index. */
say 'Hamming('right(j,w)") =" @.j /*list 'em, Dano.*/
end /*j*/
say right( 'length of last Hamming number =' length(@.y), 70); say
return

View file

@ -0,0 +1,28 @@
/*REXX program computes Hamming numbers: 1──►20, #1691, one millionth.*/
numeric digits 100 /*ensure we have enough precision*/
call hamming 1, 20 /*show the first ──► twentieth #s*/
call hamming 1691 /*show the 1,691st Hamming number*/
call hamming 1000000 /*show the one millionth number*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────HAMMING subroutine──────────────────*/
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 three)*/
if _3 < m then m =_3 /*is this less than the minimum? */
if _5 < m then m =_5 /* " " " " " " */
@.n = m /*now, assign the next Hamming #.*/
if _2 == m then #2 =#2 + 1 /*# already defined? Use next #.*/
if _3 == m then #3 =#3 + 1 /*" " " " " " */
if _5 == m then #5 =#5 + 1 /*" " " " " " */
end /*n*/
do j=x to y /*W is used to align the index. */
say 'Hamming('right(j,w)") =" @.j /*list 'em, Dano.*/
end /*j*/
say right( 'length of last Hamming number =' length(@.y), 70); say
return

View file

@ -0,0 +1,23 @@
#lang racket
(require racket/stream)
(define first stream-first)
(define rest stream-rest)
(define (merge s1 s2)
(define x1 (first s1))
(define x2 (first s2))
(cond [(= x1 x2) (merge s1 (rest s2))]
[(< x1 x2) (stream-cons x1 (merge (rest s1) s2))]
[else (stream-cons x2 (merge s1 (rest s2)))]))
(define (mult k) (λ(x) (* x k)))
(define hamming
(stream-cons
1 (merge (stream-map (mult 2) hamming)
(merge (stream-map (mult 3) hamming)
(stream-map (mult 5) hamming)))))
(for/list ([i 20] [x hamming]) x)
(stream-ref hamming 1690)
(stream-ref hamming 999999)

View file

@ -0,0 +1,14 @@
require 'generator'
# the Hamming number generator
hamming = Generator.new do |generator|
next_ham = 1
queues = { 2 => [], 3 => [], 5 => [] }
loop do
generator.yield next_ham
[2,3,5].each {|m| queues[m] << (next_ham * m)}
next_ham = [2,3,5].collect {|m| queues[m][0]}.min
[2,3,5].each {|m| queues[m].shift if queues[m][0] == next_ham}
end
end

View file

@ -0,0 +1,12 @@
hamming = Enumerator.new do |yielder|
next_ham = 1
queues = { 2 => [], 3 => [], 5 => [] }
loop do
yielder << next_ham # or: yielder.yield(next_ham)
[2,3,5].each {|m| queues[m]<< (next_ham * m)}
next_ham = [2,3,5].collect {|m| queues[m][0]}.min
[2,3,5].each {|m| queues[m].shift if queues[m][0]== next_ham}
end
end

View file

@ -0,0 +1,15 @@
start = Time.now
idx = 1
hamming.each do |ham|
case idx
when (1..20), 1691
p [idx, ham]
when 1_000_000
p [idx, ham]
break
end
idx += 1
end
puts "elapsed: #{Time.now - start} seconds"

View file

@ -0,0 +1,13 @@
class Hamming extends Iterator[BigInt] {
import scala.collection.mutable.Queue
val qs = Seq.fill(3)(new Queue[BigInt])
def enqueue(n: BigInt) = qs zip Seq(2, 3, 5) foreach { case (q, m) => q enqueue n * m }
def next = {
val n = qs map (_.head) min;
qs foreach { q => if (q.head == n) q.dequeue }
enqueue(n)
n
}
def hasNext = true
qs foreach (_ enqueue 1)
}

View file

@ -0,0 +1,21 @@
class Hamming extends Iterator[BigInt] {
import scala.collection.mutable.Queue
val q2 = new Queue[BigInt]
val q3 = new Queue[BigInt]
val q5 = new Queue[BigInt]
def enqueue(n: BigInt) = {
q2 enqueue n * 2
q3 enqueue n * 3
q5 enqueue n * 5
}
def next = {
val n = q2.head min q3.head min q5.head
if (q2.head == n) q2.dequeue
if (q3.head == n) q3.dequeue
if (q5.head == n) q5.dequeue
enqueue(n)
n
}
def hasNext = true
List(q2, q3, q5) foreach (_ enqueue 1)
}

View file

@ -0,0 +1,9 @@
val hamming : Stream[BigInt] = {
def merge(inx : Stream[BigInt], iny : Stream[BigInt]) : Stream[BigInt] = {
if (inx.head < iny.head) inx.head #:: merge(inx.tail, iny) else
if (iny.head < inx.head) iny.head #:: merge(inx, iny.tail) else
merge(inx, iny.tail)
}
1 #:: merge(hamming map (_ * 2), merge(hamming map (_ * 3), hamming map (_ * 5)))
}

View file

@ -0,0 +1,48 @@
(define-syntax lons
(syntax-rules ()
((_ lar ldr) (delay (cons lar (delay ldr))))))
(define (lar lons)
(car (force lons)))
(define (ldr lons)
(force (cdr (force lons))))
(define (lap proc . llists)
(lons (apply proc (map lar llists)) (apply lap proc (map ldr llists))))
(define (take n llist)
(if (zero? n)
(list)
(cons (lar llist) (take (- n 1) (ldr llist)))))
(define (llist-ref n llist)
(if (= n 1)
(lar llist)
(llist-ref (- n 1) (ldr llist))))
(define (merge llist-1 . llists)
(define (merge-2 llist-1 llist-2)
(cond ((null? llist-1) llist-2)
((null? llist-2) llist-1)
((< (lar llist-1) (lar llist-2))
(lons (lar llist-1) (merge-2 (ldr llist-1) llist-2)))
((> (lar llist-1) (lar llist-2))
(lons (lar llist-2) (merge-2 llist-1 (ldr llist-2))))
(else (lons (lar llist-1) (merge-2 (ldr llist-1) (ldr llist-2))))))
(if (null? llists)
llist-1
(apply merge (cons (merge-2 llist-1 (car llists)) (cdr llists)))))
(define hamming
(lons 1
(merge (lap (lambda (x) (* x 2)) hamming)
(lap (lambda (x) (* x 3)) hamming)
(lap (lambda (x) (* x 5)) hamming))))
(display (take 20 hamming))
(newline)
(display (llist-ref 1691 hamming))
(newline)
(display (llist-ref 1000000 hamming))
(newline)

View file

@ -0,0 +1,21 @@
Object subclass: Hammer [
Hammer class >> hammingNumbers: howMany [
|h i j k x2 x3 x5|
h := OrderedCollection new.
i := 0. j := 0. k := 0.
h add: 1.
x2 := 2. x3 := 2. x5 := 5.
[ ( h size) < howMany ] whileTrue: [
|m|
m := { x2. x3. x5 } sort first.
(( h indexOf: m ) = 0) ifTrue: [ h add: m ].
( x2 = (h last) ) ifTrue: [ i := i + 1. x2 := 2 * (h at: i) ].
( x3 = (h last) ) ifTrue: [ j := j + 1. x3 := 3 * (h at: j) ].
( x5 = (h last) ) ifTrue: [ k := k + 1. x5 := 5 * (h at: k) ].
].
^ h sort
]
].
(Hammer hammingNumbers: 20) displayNl.
(Hammer hammingNumbers: 1690) last displayNl.

View file

@ -0,0 +1,58 @@
package require Tcl 8.6
# Simple helper: Tcl-style list "map"
proc map {varName list script} {
set l {}
upvar 1 $varName v
foreach v $list {lappend l [uplevel 1 $script]}
return $l
}
# The core of a coroutine to compute the product of a hamming sequence.
#
# Tricky bit: we don't automatically advance to the next value, and instead
# wait to be told that the value has been consumed (i.e., is the result of
# the [yield] operation).
proc ham {key multiplier} {
global hammingCache
set i 0
yield [info coroutine]
# Cannot use [foreach]; that would take a snapshot of the list in
# the hammingCache variable, so missing updates.
while 1 {
set n [expr {[lindex $hammingCache($key) $i] * $multiplier}]
# If the number selected was ours, we advance to compute the next
if {[yield $n] == $n} {
incr i
}
}
}
# This coroutine computes the hamming sequence given a list of multipliers.
# It uses the [ham] helper from above to generate indivdual multiplied
# sequences. The key into the cache is the list of multipliers.
#
# Note that it is advisable for the values to be all co-prime wrt each other.
proc hammingCore args {
global hammingCache
set hammingCache($args) 1
set hammers [map x $args {coroutine ham$x,$args ham $args $x}]
yield
while 1 {
set n [lindex $hammingCache($args) [incr i]-1]
lappend hammingCache($args) \
[tcl::mathfunc::min {*}[map h $hammers {$h $n}]]
yield $n
}
}
# Assemble the pieces so as to compute the classic hamming sequence.
coroutine hamming hammingCore 2 3 5
# Print the first 20 values of the sequence
for {set i 1} {$i <= 20} {incr i} {
puts [format "hamming\[%d\] = %d" $i [hamming]]
}
for {} {$i <= 1690} {incr i} {set h [hamming]}
puts "hamming{1690} = $h"
for {} {$i <= 1000000} {incr i} {set h [hamming]}
puts "hamming{1000000} = $h"

View file

@ -0,0 +1,34 @@
variable hamming 1 hi2 0 hi3 0 hi5 0
proc hamming {n} {
global hamming hi2 hi3 hi5
set h2 [expr {[lindex $hamming $hi2]*2}]
set h3 [expr {[lindex $hamming $hi3]*3}]
set h5 [expr {[lindex $hamming $hi5]*5}]
while {[llength $hamming] < $n} {
lappend hamming [set h [expr {
$h2<$h3
? $h2<$h5 ? $h2 : $h5
: $h3<$h5 ? $h3 : $h5
}]]
if {$h==$h2} {
set h2 [expr {[lindex $hamming [incr hi2]]*2}]
}
if {$h==$h3} {
set h3 [expr {[lindex $hamming [incr hi3]]*3}]
}
if {$h==$h5} {
set h5 [expr {[lindex $hamming [incr hi5]]*5}]
}
}
return [lindex $hamming [expr {$n - 1}]]
}
# Print the first 20 values of the sequence
for {set i 1} {$i <= 20} {incr i} {
puts [format "hamming\[%d\] = %d" $i [hamming $i]]
}
puts "hamming{1690} = [hamming 1690]"
puts "hamming{1691} = [hamming 1691]"
puts "hamming{1692} = [hamming 1692]"
puts "hamming{1693} = [hamming 1693]"
puts "hamming{1000000} = [hamming 1000000]"