elias_gamma_encoding.pl 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #!/usr/bin/perl
  2. # Author: Trizen
  3. # Date: 13 June 2023
  4. # https://github.com/trizen
  5. # Implementation of the Elias gamma encoding scheme.
  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. my $t = sprintf('%b', $k + 1);
  20. $bitstring .= ('1' x (length($t) - 1)) . '0' . substr($t, 1);
  21. }
  22. pack('B*', $bitstring);
  23. }
  24. sub elias_decoding ($str) {
  25. open my $fh, '<:raw', \$str;
  26. my @ints;
  27. my $len = 0;
  28. my $buffer = '';
  29. for (my $k = 0 ; $k <= $len ; ++$k) {
  30. my $bl = 0;
  31. ++$bl while (read_bit($fh, \$buffer) eq '1');
  32. push @ints, oct('0b' . '1' . join('', map { read_bit($fh, \$buffer) } 1 .. $bl)) - 1;
  33. if ($k == 0) {
  34. $len = pop(@ints);
  35. }
  36. }
  37. return \@ints;
  38. }
  39. my @integers = map { int(rand($_)) } 1 .. 1000;
  40. my $str = elias_encoding([@integers]);
  41. say "Encoded length: ", length($str);
  42. say "Rawdata length: ", length(join(' ', @integers));
  43. my $decoded = elias_decoding($str);
  44. join(' ', @integers) eq join(' ', @$decoded) or die "Decoding error";
  45. __END__
  46. Encoded length: 1777
  47. Rawdata length: 3594