binary_prime_encoder.pl 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 22 September 2016
  5. # https://github.com/trizen
  6. # Encode prime numbers below a certain limit into a large number.
  7. # Example for primes below 7:
  8. #
  9. # x = 110101
  10. #
  11. # where each (k+1)-th bit in x is 1 when (k+1) is prime.
  12. #
  13. # This can be illustrated as:
  14. # [1, 1, 0, 1, 0, 1]
  15. # [2, 3, 4, 5, 6, 7]
  16. #
  17. # The binary number 110101 is represented by 53 in base 10.
  18. # See also: https://oeis.org/A072762
  19. # https://en.wikipedia.org/wiki/Prime_constant
  20. use 5.010;
  21. use strict;
  22. use warnings;
  23. no warnings 'recursion';
  24. use Memoize qw(memoize);
  25. use Math::AnyNum qw(:overload);
  26. use ntheory qw(is_prime prev_prime);
  27. memoize('_encode');
  28. sub _encode {
  29. my ($n) = @_;
  30. $n < 2 ? 0 : 2 * _encode($n - 1) + (is_prime($n) ? 1 : 0);
  31. }
  32. sub encode_primes {
  33. my ($limit) = @_;
  34. _encode(prev_prime($limit + 1));
  35. }
  36. sub decode_primes {
  37. my ($n) = @_;
  38. my $pow = $n >> 1;
  39. my $shift = 1;
  40. while (($pow + 1) & $pow) {
  41. $pow |= $pow >> $shift;
  42. $shift <<= 1;
  43. }
  44. $pow += 1;
  45. my @primes;
  46. my $p = 2;
  47. while ($pow) {
  48. if ($n & $pow) {
  49. push @primes, $p;
  50. }
  51. ++$p;
  52. $pow >>= 1;
  53. }
  54. @primes;
  55. }
  56. say "Encoded primes below 100: ", encode_primes(100);
  57. say "Decoded primes below 100: ", join(' ', decode_primes(encode_primes(100)));
  58. __END__
  59. Encoded primes below 100: 65709066564613793476872782081
  60. Decoded primes below 100: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97