new_sieve.jl 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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::UInt128, 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 |> UInt128, p, n), 0:p-1)
  22. end
  23. function mulmod(a::UInt128, b::UInt128, m::Integer)
  24. # https://discourse.julialang.org/t/modular-multiplication-without-overflow/90421/4
  25. magic1 = (UInt128(0xFFFFFFFF) << 32)
  26. magic2 = UInt128(0x8000000000000000)
  27. if iszero(((a | b) & magic1))
  28. return (a * b) % m
  29. end
  30. d = zero(UInt128)
  31. mp2 = m >> 1
  32. if a >= m; a %= m; end
  33. if b >= m; b %= m; end
  34. for _ in 1:64
  35. (d > mp2) ? d = ((d << 1) - m) : d = (d << 1)
  36. if !iszero(a & magic2)
  37. d += b
  38. end
  39. if d >= m
  40. d -= m
  41. end
  42. a <<= 1
  43. end
  44. return d
  45. end
  46. function mulmod(a::Integer, b::Integer, m::Integer)
  47. sa, sb = UInt128.(unsigned.((a,b)))
  48. return mulmod(sa, sb, m)
  49. end
  50. function chinese(a1, m1, a2, m2)
  51. M = lcm(m1, m2)
  52. return [
  53. (mulmod(mulmod(a1, invmod(div(M, m1), m1), M), div(M, m1), M) +
  54. mulmod(mulmod(a2, invmod(div(M, m2), m2), M), div(M, m2), M)) % M, M
  55. ]
  56. end
  57. function remainders_for_primes(n, primes)
  58. res = [[0, 1]]
  59. for p in primes
  60. rems = remaindersmodp(p, n)
  61. nres = []
  62. for r in res
  63. a = r[1]
  64. m = r[2]
  65. for rem in rems
  66. push!(nres, chinese(a, m, rem, p))
  67. end
  68. end
  69. res = nres
  70. end
  71. res = map(x -> x[1], res)
  72. sort!(res)
  73. return res
  74. end
  75. function is(m::UInt128, n)
  76. isprime( 6 * m + 1) || return false
  77. isprime(12 * m + 1) || return false
  78. isprime(18 * m + 1) || return false
  79. for k in 2:n-2
  80. isprime((9 * m << k) + 1) || return false
  81. end
  82. return true
  83. end
  84. function deltas(arr)
  85. prev = 0
  86. D = []
  87. for k in arr
  88. push!(D, k - prev)
  89. prev = k
  90. end
  91. return D
  92. end
  93. function chernick_carmichael_with_n_factors(n)
  94. maxp = 11
  95. n >= 8 && (maxp = 17)
  96. n >= 10 && (maxp = 29)
  97. n >= 12 && (maxp = 31)
  98. P = primes(maxp)
  99. R = remainders_for_primes(n, P)
  100. D = deltas(R)
  101. s = prod(P)
  102. while (D[1] == 0)
  103. popfirst!(D)
  104. end
  105. push!(D, R[1] + s - R[length(R)])
  106. m = R[1] |> UInt128
  107. D_len = length(D)
  108. two_power = max(1 << (n - 4), 1)
  109. for j in 0:10^18
  110. if (m > 8000000000000000 && m % two_power == 0 && is(m, n))
  111. return m |> Int128
  112. end
  113. if (j % 10^8 == 0 && j > 0)
  114. println("Searching for a($n) with m = $m")
  115. end
  116. m += D[(j % D_len) + 1]
  117. end
  118. end
  119. for n in 12:12
  120. println([n, chernick_carmichael_with_n_factors(n)])
  121. end