double-elias_gamma_encoding.pl 1.8 KB

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