lucas-carmichael_numbers_in_range.pl 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 27 August 2022
  4. # https://github.com/trizen
  5. # Generate all the Lucas-Carmichael numbers with n prime factors in a given 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. my $q = divint($x, $y);
  13. ($q * $y == $x) ? $q : ($q + 1);
  14. }
  15. sub lucas_carmichael_numbers_in_range ($A, $B, $k, $callback) {
  16. $A = vecmax($A, pn_primorial($k));
  17. sub ($m, $lambda, $p, $k, $u = undef, $v = undef) {
  18. if ($k == 1) {
  19. printf("# $m -> ($u, $v) -> 10^%.3f\n", log($v - $u) / log(10)) if ($v - $u > 2e6);
  20. if ($v - $u > 1e10) {
  21. die "Range too large!\n";
  22. }
  23. foreach my $p (@{primes($u, $v)}) {
  24. my $t = $m * $p;
  25. if (($t + 1) % $lambda == 0 and ($t + 1) % ($p + 1) == 0) {
  26. $callback->($t);
  27. }
  28. }
  29. return;
  30. }
  31. my $s = rootint(divint($B, $m), $k);
  32. for (my $r ; $p <= $s ; $p = $r) {
  33. $r = next_prime($p);
  34. my $L = lcm($lambda, $p + 1);
  35. gcd($L, $m) == 1 or next;
  36. my $t = $m * $p;
  37. my $u = divceil($A, $t);
  38. my $v = divint($B, $t);
  39. if ($u <= $v) {
  40. __SUB__->($t, $L, $r, $k - 1, (($k == 2 && $r > $u) ? $r : $u), $v);
  41. }
  42. }
  43. }
  44. ->(1, 1, 3, $k);
  45. }
  46. my $min_k = 10; # mininum number of prime factors
  47. my $max_k = 1e4; # maxinum number of prime factors
  48. #my $from = 1; # generate terms >= this
  49. #my $upto = 196467189590024639; # generate terms <= this
  50. # Generate terms in this range
  51. my $from = 3614740529402519;
  52. my $upto = 20576473996736735;
  53. foreach my $k ($min_k .. $max_k) {
  54. last if pn_primorial($k) > $upto;
  55. say "# Generating with k = $k";
  56. lucas_carmichael_numbers_in_range($from, $upto, $k, sub ($n) { say $n });
  57. }