squarefree_almost_primes_in_range_mpz.pl 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 10 March 2021
  4. # Edit: 04 April 2024
  5. # https://github.com/trizen
  6. # Generate all the squarefree k-almost prime numbers in range [A,B].
  7. # See also:
  8. # https://en.wikipedia.org/wiki/Almost_prime
  9. use 5.036;
  10. use ntheory qw(:all);
  11. use Math::GMPz;
  12. sub squarefree_almost_primes ($A, $B, $k) {
  13. $A = vecmax($A, pn_primorial($k));
  14. $A = Math::GMPz->new("$A");
  15. $B = Math::GMPz->new("$B");
  16. my $u = Math::GMPz::Rmpz_init();
  17. my @values = sub ($m, $lo, $k) {
  18. Math::GMPz::Rmpz_tdiv_q($u, $B, $m);
  19. Math::GMPz::Rmpz_root($u, $u, $k);
  20. my $hi = Math::GMPz::Rmpz_get_ui($u);
  21. if ($lo > $hi) {
  22. return;
  23. }
  24. my @lst;
  25. if ($k == 1) {
  26. Math::GMPz::Rmpz_cdiv_q($u, $A, $m);
  27. if (Math::GMPz::Rmpz_fits_ulong_p($u)) {
  28. $lo = vecmax($lo, Math::GMPz::Rmpz_get_ui($u));
  29. }
  30. elsif (Math::GMPz::Rmpz_cmp_ui($u, $lo) > 0) {
  31. if (Math::GMPz::Rmpz_cmp_ui($u, $hi) > 0) {
  32. return;
  33. }
  34. $lo = Math::GMPz::Rmpz_get_ui($u);
  35. }
  36. if ($lo > $hi) {
  37. return;
  38. }
  39. foreach my $p (@{primes($lo, $hi)}) {
  40. my $v = Math::GMPz::Rmpz_init();
  41. Math::GMPz::Rmpz_mul_ui($v, $m, $p);
  42. push @lst, $v;
  43. }
  44. return @lst;
  45. }
  46. my $z = Math::GMPz::Rmpz_init();
  47. foreach my $p (@{primes($lo, $hi)}) {
  48. Math::GMPz::Rmpz_mul_ui($z, $m, $p);
  49. push @lst, __SUB__->($z, $p + 1, $k - 1);
  50. }
  51. return @lst;
  52. }
  53. ->(Math::GMPz->new(1), 2, $k);
  54. sort { Math::GMPz::Rmpz_cmp($a, $b) } @values;
  55. }
  56. # Generate squarefree 5-almost primes in the range [3000, 10000]
  57. my $k = 5;
  58. my $from = 3000;
  59. my $upto = 10000;
  60. my @arr = squarefree_almost_primes($from, $upto, $k);
  61. my @test = grep { is_almost_prime($k, $_) && is_square_free($_) } $from .. $upto; # just for testing
  62. join(' ', @arr) eq join(' ', @test) or die "Error: not equal!";
  63. say join(', ', @arr);