smallest_lucas-carmichael_divisible_by_n_faster.sf 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. #!/usr/bin/ruby
  2. # Method for finding the smallest Lucas-Carmichael number divisible by n.
  3. # See also:
  4. # https://oeis.org/A253597
  5. # https://oeis.org/A253598
  6. func lucas_carmichael_numbers_from_multiple(A, B, m, L, lo, k, callback) {
  7. var hi = min(idiv(B,m).iroot(k), B.isqrt)
  8. return nil if (lo > hi)
  9. if (k == 1) {
  10. lo = max(lo, idiv_ceil(A, m))
  11. lo > hi && return nil
  12. var t = mulmod(m.invmod(L), -1, L)
  13. t > hi && return nil
  14. t += L*idiv_ceil(lo - t, L) if (t < lo)
  15. t > hi && return nil
  16. for p in (range(t, hi, L)) {
  17. p.is_prime || next
  18. p.divides(m) && next
  19. with (m*p) {|n|
  20. if (p.inc `divides` n.inc) {
  21. callback(n)
  22. }
  23. }
  24. }
  25. return nil
  26. }
  27. each_prime(lo, hi, {|p|
  28. p.divides(m) && next
  29. m.is_coprime(p+1) || next
  30. __FUNC__(A, B, m*p, lcm(L, p+1), p+1, k-1, callback)
  31. })
  32. }
  33. func lucas_carmichael_divisible_by(m) {
  34. m >= 1 || return nil
  35. m.is_even && return nil
  36. gcd(m, psi(m)) == 1 || return nil
  37. var a = max(399, m)
  38. var b = 2*a
  39. var L = m.factor.lcm{.inc}
  40. var found = []
  41. loop {
  42. for k in ((m.is_prime ? 2 : 1)..1000) {
  43. var P = k.by {|p|
  44. p.is_odd && p.is_prime && !p.divides(m) && !p.divides(L)
  45. }
  46. break if (P.prod*m > b)
  47. var callback = {|n|
  48. found << n
  49. b = min(b, n)
  50. }
  51. lucas_carmichael_numbers_from_multiple(a, b, m, L, P[0], k, callback)
  52. }
  53. a = b+1
  54. b = 2*a
  55. break if found
  56. }
  57. found.min
  58. }
  59. assert_eq(lucas_carmichael_divisible_by(3), 399)
  60. assert_eq(lucas_carmichael_divisible_by(3*7), 399)
  61. assert_eq(lucas_carmichael_divisible_by(7*19), 399)
  62. say lucas_carmichael_divisible_by.map(primes(3..50))
  63. say 40.of(lucas_carmichael_divisible_by).grep
  64. __END__
  65. [399, 935, 399, 935, 2015, 935, 399, 4991, 51359, 2015, 1584599, 20705, 5719, 18095]
  66. [399, 399, 935, 399, 935, 2015, 935, 399, 399, 4991, 51359, 2015, 8855, 1584599, 9486399]