prog.pl 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #!/usr/bin/perl
  2. # Least Carmichael number that is divisible by the n-th cyclic number A003277(n), or 0 if no such number exists
  3. # https://oeis.org/A253595
  4. use 5.020;
  5. use warnings;
  6. use ntheory qw(:all);
  7. use experimental qw(signatures);
  8. sub divceil ($x, $y) { # ceil(x/y)
  9. my $q = divint($x, $y);
  10. ($q * $y == $x) ? $q : ($q + 1);
  11. }
  12. sub carmichael_from_multiple ($A, $B, $m, $L, $lo, $k, $callback) {
  13. my $hi = rootint(divint($B, $m), $k);
  14. if ($lo > $hi) {
  15. return;
  16. }
  17. if ($k == 1) {
  18. $lo = vecmax($lo, divceil($A, $m));
  19. $lo > $hi && return;
  20. my $t = invmod($m, $L) // return;
  21. $t > $hi && return;
  22. $t += $L while ($t < $lo);
  23. for (my $p = $t ; $p <= $hi ; $p += $L) {
  24. if ($m % $p != 0 and is_prime($p)) {
  25. my $n = $m * $p;
  26. if (($n - 1) % ($p - 1) == 0) {
  27. $callback->($n);
  28. }
  29. }
  30. }
  31. return;
  32. }
  33. foreach my $p (@{primes($lo, $hi)}) {
  34. $m % $p == 0 and next;
  35. gcd($m, $p - 1) == 1 or next;
  36. __SUB__->($A, $B, $m * $p, lcm($L, $p - 1), $p + 1, $k - 1, $callback);
  37. }
  38. }
  39. sub carmichael_divisible_by ($m) {
  40. $m >= 1 or return;
  41. $m % 2 == 0 and return;
  42. is_square_free($m) || return;
  43. gcd($m, euler_phi($m)) == 1 or return;
  44. my $A = vecmax(561, $m);
  45. my $B = 2 * $A;
  46. my $L = vecmax(1, lcm(map { $_ - 1 } factor($m)));
  47. my @found;
  48. for (; ;) {
  49. for my $k ((is_prime($m) ? 2 : 1) .. 1000) {
  50. my @P;
  51. for (my $p = 3 ; scalar(@P) < $k ; $p = next_prime($p)) {
  52. if ($m % $p != 0 and $L % $p != 0) {
  53. push @P, $p;
  54. }
  55. }
  56. last if (vecprod(@P, $m) > $B);
  57. my $callback = sub ($n) {
  58. push @found, $n;
  59. $B = vecmin($B, $n);
  60. };
  61. carmichael_from_multiple($A, $B, $m, $L, $P[0], $k, $callback);
  62. }
  63. last if @found;
  64. $A = $B + 1;
  65. $B = 2 * $A;
  66. }
  67. vecmin(@found);
  68. }
  69. carmichael_divisible_by(3) == 561 or die;
  70. carmichael_divisible_by(3 * 5) == 62745 or die;
  71. carmichael_divisible_by(7 * 19) == 1729 or die;
  72. carmichael_divisible_by(47 * 89) == 62745 or die;
  73. carmichael_divisible_by(5 * 47 * 89) == 62745 or die;
  74. carmichael_divisible_by(3 * 47 * 89) == 62745 or die;
  75. carmichael_divisible_by(3 * 89) == 62745 or die;
  76. my $count = 1;
  77. foreach my $n (1..1e6) {
  78. my $r = carmichael_divisible_by($n);
  79. if (defined($r)) {
  80. ++$count;
  81. say "$count $r";
  82. }
  83. }
  84. #say join(', ', map { carmichael_divisible_by($_) } @{primes(3, 50)});
  85. #say join(', ', map { carmichael_divisible_by($_) } 1 .. 60);
  86. __END__
  87. 561, 1105, 1729, 561, 1105, 561, 1729, 6601, 2465, 2821, 29341, 6601, 334153, 62745
  88. 561, 561, 1105, 1729, 561, 1105, 62745, 561, 1729, 6601, 2465, 2821, 561, 825265, 29341, 6601, 334153, 62745, 561, 2433601, 74165065