squarefree_almost_primes_in_range.pl 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 10 March 2021
  4. # https://github.com/trizen
  5. # Generate squarefree 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 squarefree_almost_primes ($A, $B, $k, $callback) {
  15. $A = vecmax($A, pn_primorial($k));
  16. sub ($m, $lo, $k) {
  17. my $hi = rootint(divint($B, $m), $k);
  18. if ($lo > $hi) {
  19. return;
  20. }
  21. if ($k == 1) {
  22. $lo = vecmax($lo, divceil($A, $m));
  23. if ($lo > $hi) {
  24. return;
  25. }
  26. forprimes {
  27. $callback->(mulint($m, $_));
  28. } $lo, $hi;
  29. return;
  30. }
  31. foreach my $p (@{primes($lo, $hi)}) {
  32. __SUB__->(mulint($m, $p), $p+1, $k-1);
  33. }
  34. }->(1, 2, $k);
  35. }
  36. # Generate squarefree 5-almost primes in the range [3000, 10000]
  37. my $k = 5;
  38. my $from = 3000;
  39. my $upto = 10000;
  40. my @arr; squarefree_almost_primes($from, $upto, $k, sub ($n) { push @arr, $n });
  41. my @test = grep { is_almost_prime($k, $_) && is_square_free($_) } $from..$upto; # just for testing
  42. join(' ', sort { $a <=> $b } @arr) eq join(' ', @test) or die "Error: not equal!";
  43. say join(', ', @arr);