-
Notifications
You must be signed in to change notification settings - Fork 34
/
double-elias_gamma_encoding.pl
86 lines (61 loc) · 1.84 KB
/
double-elias_gamma_encoding.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/perl
# Author: Trizen
# Date: 14 June 2023
# https://github.com/trizen
# Implementation of the double-variant of the Elias gamma encoding scheme, optimized for large integers.
# Reference:
# COMP526 7-5 SS7.4 Run length encoding
# https://youtube.com/watch?v=3jKLjmV1bL8
use 5.036;
sub read_bit ($fh, $bitstring) {
if (($$bitstring // '') eq '') {
$$bitstring = unpack('b*', getc($fh) // return undef);
}
chop($$bitstring);
}
sub elias_encoding ($integers) {
my $bitstring = '';
foreach my $k (scalar(@$integers), @$integers) {
if ($k == 0) {
$bitstring .= '0';
}
else {
my $t = sprintf('%b', $k + 1);
my $l = length($t);
my $L = sprintf('%b', $l);
$bitstring .= ('1' x (length($L) - 1)) . '0' . substr($L, 1) . substr($t, 1);
}
}
pack('B*', $bitstring);
}
sub elias_decoding ($str) {
open my $fh, '<:raw', \$str;
my @ints;
my $len = 0;
my $buffer = '';
for (my $k = 0 ; $k <= $len ; ++$k) {
my $bl = 0;
++$bl while (read_bit($fh, \$buffer) eq '1');
if ($bl > 0) {
my $bl2 = oct('0b1' . join('', map { read_bit($fh, \$buffer) } 1 .. $bl));
my $int = oct('0b1' . join('', map { read_bit($fh, \$buffer) } 1 .. ($bl2 - 1)));
push @ints, $int - 1;
}
else {
push @ints, 0;
}
if ($k == 0) {
$len = pop(@ints);
}
}
return \@ints;
}
my @integers = map { int(rand($_)) } 1 .. 1000;
my $str = elias_encoding([@integers]);
say "Encoded length: ", length($str);
say "Rawdata length: ", length(join(' ', @integers));
my $decoded = elias_decoding($str);
join(' ', @integers) eq join(' ', @$decoded) or die "Decoding error";
__END__
Encoded length: 1631
Rawdata length: 3616