1 = 1 2 = 010 3 = 011 4 = 00100and so on. The bits sequence of a positive integer can be obtained like this:}
proc int2bits int {
set res ""
while {$int>0} {
set res [expr {$int%2}]$res ;# prepend - we have no [string insert]
set int [expr {$int/2}]
}
set res
}# and so the Elias gamma function is just proc Elias'gamma int {
set bits [int2bits $int]
return [string repeat 0 [expr {[string length $bits]-1}]]$bits
}# and for a list of integers, which is the most useful application: proc Elias'gammas ints {
set res ""
foreach int $ints {append res [Elias'gamma $int]}
set res
}# Now to decode such a bit string: proc Elias'decode'gammas bits {
set res {}
while {$bits ne ""} {
regexp ^(0*) $bits -> zeroes
set length [expr {[string length $zeroes]*2}]
lappend res [bits2int [string range $bits 0 $length]]
set bits [string range $bits [incr length] end]
}
set res
}# with this little helper, which doesn't bother for the leading zeroes: proc bits2int bits {
set res 0
foreach bit [split $bits ""] {
set res [expr {$res*2+$bit}]
}
set res
}if 0 {Testing: % Elias'gammas {1 2 3 4 5}
10100110010000101
% Elias'decode'gammas [Elias'gammas {1 2 3 4 5}]
1 2 3 4 5So we managed to cram 5 integers into 17 bits, and extract them correctly, too. This code works very well for lists of small integers, like runlengths - the worst case there, the 010101... checkerboard, just takes up one bit per 1-length run. For bigger integers, the Elias delta encoding [2] may be more compact. In the delta encoding the length information for the integer we are encoding is encoded with the Elias gamma code.}
proc Elias'delta int {
set bits [int2bits $int]
return [Elias'gamma [string length $bits]][string range $bits 1 end]
}
proc Elias'deltas ints {
set res ""
foreach int $ints {append res [Elias'delta $int]}
set res
}
proc Elias'decode'deltas bits {
set res {}
while {$bits ne ""} {
regexp ^(0*) $bits -> zeroes
set length [expr {[string length $zeroes]*2}]
set l2 [bits2int [string range $bits 0 $length]]
set l3 [expr {$length+$l2-1}]
lappend res [bits2int 1[string range $bits [expr {$length+1}] $l3]]
set bits [string range $bits [incr l3] end]
}
set res
}if 0 {Testing again: % Elias'decode'deltas [Elias'deltas {1 10 100 1000}]
1 10 100 1000The delta encoding is more compact if many numbers are bigger than 32 - here's an experimental table: % foreach i {1 2 4 8 16 32 64 128 256 512 1024 2048 4096} {
puts $i:[string length [Elias'gamma $i]],[string length [Elias'delta $i]]}
1:1,1
2:3,4
4:5,5
8:7,8
16:9,9
32:11,10
64:13,11
128:15,14
256:17,15
512:19,16
1024:21,17
2048:23,18
4096:25,19if 0 {Another Elias code is omega coding, also called recursive Elias coding [3]. It generalizes on the gamma and delta codes by putting a series of length prefixes in front of the encoded number, each prefix telling the length of the next in the sequence. The process stops when encountering a '0' bit after a prefix (Each length prefix starts with an '1' bit).}[ Arts and crafts of Tcl-Tk programming | Category Compression ]

