chernick-carmichael_with_n_factors_sieve.jl 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #!/usr/bin/julia
  2. # Sieve for Chernick's "universal form" Carmichael number with n prime factors.
  3. # Inspired by the PARI program by David A. Corneth from OEIS A372238.
  4. # Finding A318646(10) takes ~3 minutes.
  5. # See also:
  6. # https://oeis.org/A318646
  7. # https://oeis.org/A372238/a372238.gp.txt
  8. using Primes
  9. function isrem(m, p, n)
  10. (( 6 * m + 1) % p == 0) && return false
  11. ((12 * m + 1) % p == 0) && return false
  12. ((18 * m + 1) % p == 0) && return false
  13. for k in 2 : n-2
  14. if (((9 * m << k) + 1) % p == 0)
  15. return false
  16. end
  17. end
  18. return true
  19. end
  20. function remaindersmodp(p, n)
  21. filter(m -> isrem(m, p, n), 0:p-1)
  22. end
  23. function mulmod(a::Integer, b::Integer, m::Integer)
  24. (a*b) % m # XXX: can overflow
  25. end
  26. function chinese(a1, m1, a2, m2)
  27. M = lcm(m1, m2)
  28. return [
  29. (mulmod(mulmod(a1, invmod(div(M, m1), m1), M), div(M, m1), M) +
  30. mulmod(mulmod(a2, invmod(div(M, m2), m2), M), div(M, m2), M)) % M, M
  31. ]
  32. end
  33. function remainders_for_primes(n, primes)
  34. res = [[0, 1]]
  35. for p in primes
  36. rems = remaindersmodp(p, n)
  37. if (length(rems) == 0)
  38. rems = [0]
  39. end
  40. nres = []
  41. for r in res
  42. a = r[1]
  43. m = r[2]
  44. for rem in rems
  45. push!(nres, chinese(a, m, rem, p))
  46. end
  47. end
  48. res = nres
  49. end
  50. res = map(x -> x[1], res)
  51. sort!(res)
  52. return res
  53. end
  54. function is(m, n)
  55. isprime( 6 * m + 1) || return false
  56. isprime(12 * m + 1) || return false
  57. isprime(18 * m + 1) || return false
  58. for k in 2:n-2
  59. isprime((9 * m << k) + 1) || return false
  60. end
  61. return true
  62. end
  63. function deltas(arr)
  64. prev = 0
  65. D = []
  66. for k in arr
  67. push!(D, k - prev)
  68. prev = k
  69. end
  70. return D
  71. end
  72. function chernick_carmichael_with_n_factors(n)
  73. maxp = 11
  74. n >= 8 && (maxp = 17)
  75. n >= 10 && (maxp = 29)
  76. n >= 12 && (maxp = 31)
  77. P = primes(maxp)
  78. R = remainders_for_primes(n, P)
  79. D = deltas(R)
  80. s = prod(P)
  81. while (D[1] == 0)
  82. popfirst!(D)
  83. end
  84. push!(D, R[1] + s - R[length(R)])
  85. m = R[1]
  86. D_len = length(D)
  87. two_power = max(1 << (n - 4), 1)
  88. for j in 0:10^18
  89. if (m % two_power == 0 && is(m, n))
  90. return m
  91. end
  92. if (j % 10^8 == 0 && j > 0)
  93. println("Searching for a($n) with m = $m")
  94. end
  95. m += D[(j % D_len) + 1]
  96. end
  97. end
  98. for n in 3:9
  99. println([n, chernick_carmichael_with_n_factors(n)])
  100. end