almost_prime_numbers_in_range.pl 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 15 February 2021
  4. # https://github.com/trizen
  5. # Generate k-almost prime numbers in range [a,b]. (not in sorted order)
  6. # See also:
  7. # https://en.wikipedia.org/wiki/Almost_prime
  8. use 5.020;
  9. use ntheory qw(:all);
  10. use experimental qw(signatures);
  11. sub divceil ($x, $y) { # ceil(x/y)
  12. (($x % $y == 0) ? 0 : 1) + divint($x, $y);
  13. }
  14. sub almost_prime_numbers ($A, $B, $k, $callback) {
  15. $A = vecmax($A, powint(2, $k));
  16. sub ($m, $p, $k) {
  17. if ($k == 1) {
  18. forprimes {
  19. $callback->(mulint($m, $_));
  20. } vecmax($p, divceil($A, $m)), divint($B, $m);
  21. return;
  22. }
  23. my $s = rootint(divint($B, $m), $k);
  24. while ($p <= $s) {
  25. my $t = mulint($m, $p);
  26. if (divceil($A, $t) <= divint($B, $t)) {
  27. __SUB__->($t, $p, $k - 1);
  28. }
  29. $p = next_prime($p);
  30. }
  31. }->(1, 2, $k);
  32. }
  33. # Generate 5-almost primes in the range [50, 1000]
  34. my $k = 5;
  35. my $from = 50;
  36. my $upto = 1000;
  37. my @arr; almost_prime_numbers($from, $upto, $k, sub ($n) { push @arr, $n });
  38. my @test = grep { is_almost_prime($k, $_) } $from..$upto; # just for testing
  39. join(' ', sort { $a <=> $b } @arr) eq join(' ', @test) or die "Error: not equal!";
  40. say join(', ', @arr);