lucas-carmichael_numbers_in_range.jl 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. #!/usr/bin/julia
  2. # Daniel "Trizen" Șuteu
  3. # Date: 06 September 2022
  4. # https://github.com/trizen
  5. # Generate all the Lucas-Carmichael numbers with n prime factors in a given range [a,b]. (not in sorted order)
  6. # See also:
  7. # https://en.wikipedia.org/wiki/Almost_prime
  8. # https://trizenx.blogspot.com/2020/08/pseudoprimes-construction-methods-and.html
  9. # PARI/GP program (in range [A,B]):
  10. # lucas_carmichael(A, B, k) = A=max(A, vecprod(primes(k+1))\2); (f(m, l, p, k, u=0, v=0) = my(list=List()); if(k==1, forprime(p=u, v, my(t=m*p); if((t+1)%l == 0 && (t+1)%(p+1) == 0, listput(list, t))), forprime(q = p, sqrtnint(B\m, k), my(t = m*q); my(L=lcm(l, q+1)); if(gcd(L, t) == 1, my(u=ceil(A/t), v=B\t); if(u <= v, my(r=nextprime(q+1)); if(k==2 && r>u, u=r); list=concat(list, f(t, L, r, k-1, u, v)))))); list); vecsort(Vec(f(1, 1, 3, k)));
  11. using Primes
  12. const BIG = false # true to use big integers
  13. function big_prod(arr)
  14. BIG || return prod(arr)
  15. r = big(1)
  16. for n in (arr)
  17. r *= n
  18. end
  19. return r
  20. end
  21. function lucas_carmichael_numbers_in_range(A, B, k)
  22. A = max(A, fld(big_prod(primes(prime(k+1))), 2))
  23. # Largest possible factor of Lucas-Carmichael numbers <= B
  24. # Proof: By the Chinese Remainder Theorem, if n is a Lucas-Carmichael number, then
  25. # n == p (mod p*(p+1)), where p is a prime factor of n,
  26. # therefore `n = p + j*p*(p+1)` for some `j >= 1`,
  27. # where for `j=1` we have `p^2 + 2*p <= n`, hence `p <= sqrt(n+1)-1`.
  28. max_p = isqrt(B)
  29. terms = []
  30. F = function(m, L, lo, k)
  31. hi = round(Int64, fld(B, m)^(1/k))
  32. if (lo > hi)
  33. return nothing
  34. end
  35. if (k == 1)
  36. hi = min(hi, max_p)
  37. lo = round(Int64, max(lo, cld(A, m)))
  38. lo > hi && return nothing
  39. t = L - invmod(m, L)
  40. t > hi && return nothing
  41. if (t < lo)
  42. t += L*cld(lo - t, L)
  43. end
  44. t > hi && return nothing
  45. for p in t:L:hi
  46. if ((m*p + 1) % (p+1) == 0 && isprime(p))
  47. push!(terms, m*p)
  48. end
  49. end
  50. return nothing
  51. end
  52. for p in primes(lo, hi)
  53. if (gcd(m, p+1) == 1)
  54. F(m*p, lcm(L, p+1), p+1, k-1)
  55. end
  56. end
  57. end
  58. F((BIG ? big(1) : 1), (BIG ? big(1) : 1), 3, k)
  59. return sort(terms)
  60. end
  61. # Generate all the Carmichael numbers in range [A,B]
  62. function lucas_carmichael(A, B)
  63. k = 3
  64. terms = []
  65. while true
  66. # Stop when the lower-bound (`primorial(prime(k+1))/2`) is greater than the upper-limit
  67. if (big_prod(primes(prime(k+1)))/2 > B)
  68. break
  69. end
  70. append!(terms, lucas_carmichael_numbers_in_range(A, B, k))
  71. k += 1
  72. end
  73. return sort(terms)
  74. end
  75. println("=> Lucas-Carmichael numbers <= 10^6:")
  76. println(lucas_carmichael(1, 10^6));
  77. # Generate all the 6-Lucas-Carmichael numbers in the range [100, 10^10]
  78. k = 6
  79. from = 100
  80. upto = 10^10
  81. arr = lucas_carmichael_numbers_in_range(from, upto, k)
  82. println("\n=> Lucas-Carmichael numbers with $k prime factors in range [$from, $upto]:")
  83. println(arr)