smallest_carmichael_divisible_by_n_faster.sf 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #!/usr/bin/ruby
  2. # Method for finding the smallest Carmichael number divisible by n.
  3. # See also:
  4. # https://oeis.org/A135721
  5. # https://oeis.org/A253595
  6. func carmichael_numbers_from_multiple(A, B, m, L, lo, k, callback) {
  7. # Largest possisble prime factor for Carmichael numbers <= b
  8. var max_p = ((1 + isqrt(8*B + 1))>>2)
  9. var hi = min(max_p, idiv(B,m).iroot(k))
  10. return nil if (lo > hi)
  11. if (k == 1) {
  12. lo = max(lo, idiv_ceil(A, m))
  13. lo > hi && return nil
  14. var t = m.invmod(L)
  15. t > hi && return nil
  16. t += L*idiv_ceil(lo - t, L) if (t < lo)
  17. t > hi && return nil
  18. for p in (range(t, hi, L)) {
  19. p.is_prime || next
  20. p.divides(m) && next
  21. with (m*p) {|n|
  22. if (p.dec `divides` n.dec) {
  23. callback(n)
  24. }
  25. }
  26. }
  27. return nil
  28. }
  29. each_prime(lo, hi, {|p|
  30. p.divides(m) && next
  31. var t = lcm(L, p-1)
  32. m.is_coprime(t) || next
  33. __FUNC__(A, B, m*p, t, p+1, k-1, callback)
  34. })
  35. }
  36. func carmichael_divisible_by(m) {
  37. m >= 1 || return nil
  38. m.is_even && return nil
  39. gcd(m, phi(m)) == 1 || return nil
  40. var a = max(561, m)
  41. var b = 2*a
  42. var L = m.factor.lcm{.dec}
  43. var found = []
  44. loop {
  45. for k in ((m.is_prime ? 2 : 1)..1000) {
  46. var P = k.by {|p|
  47. p.is_odd && p.is_prime && !p.divides(m) && !p.divides(L)
  48. }
  49. break if (P.prod*m > b)
  50. var callback = {|n|
  51. found << n
  52. b = min(b, n)
  53. }
  54. carmichael_numbers_from_multiple(a, b, m, L, P[0], k, callback)
  55. }
  56. a = b+1
  57. b = 2*a
  58. break if found
  59. }
  60. found.min
  61. }
  62. assert_eq(carmichael_divisible_by(3), 561)
  63. assert_eq(carmichael_divisible_by(3*5), 62745)
  64. assert_eq(carmichael_divisible_by(7*19), 1729)
  65. assert_eq(carmichael_divisible_by(47*89), 62745)
  66. assert_eq(carmichael_divisible_by(5*47*89), 62745)
  67. assert_eq(carmichael_divisible_by(3*47*89), 62745)
  68. assert_eq(carmichael_divisible_by(3*89), 62745)
  69. say carmichael_divisible_by.map(primes(3..50))
  70. say 40.of(carmichael_divisible_by).grep
  71. __END__
  72. [561, 1105, 1729, 561, 1105, 561, 1729, 6601, 2465, 2821, 29341, 6601, 334153, 62745]
  73. [561, 561, 1105, 1729, 561, 1105, 62745, 561, 1729, 6601, 2465, 2821, 561, 825265, 29341]