A simple prime-number bot, in python. WIP
mastodon
python
fediverse
bot
mathematics
prime-numbers

lucas.py 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. # Finding lucas pseudoprimes
  2. from math import sqrt, gcd, floor, log
  3. from time import process_time
  4. def isqrt(n):
  5. """ Find the integer square root of n via newton's method, code via
  6. stackoverflow:
  7. (https://stackoverflow.com/questions/15390807/integer-square-root-in-python)
  8. """
  9. x = n
  10. y = (x + 1) // 2
  11. while y < x:
  12. x = y
  13. y = (x + n // x) // 2
  14. return x
  15. def hasIntSQRT(n):
  16. """Detect whether the square root of n is an integer,
  17. i.e. whether the isqrt(n) is the true square root.
  18. """
  19. isq = isqrt(n)
  20. return isq * isq == n
  21. def Dsequence():
  22. """Generate sequence 5, -7, 9, -11, 13, -15...
  23. """
  24. val = 5
  25. while True:
  26. if val % 4 == 1:
  27. yield val
  28. else:
  29. yield -val
  30. val = val + 2
  31. def Legendre(a, p):
  32. """Function for calculating Legendre symbol.
  33. Note that this is only supposed to be defined if p is an odd prime, but we
  34. don't know in advance if that is true - will therefore only throw and error
  35. if p is even.
  36. Uses original power definition from
  37. <https://en.wikipedia.org/wiki/Legendre_symbol>
  38. """
  39. if (p % 2 == 0):
  40. raise ValueError("p must be odd, is {}".format(p))
  41. lv = pow(a, (p-1)//2, p)
  42. if lv == p - 1:
  43. lv = -1
  44. return lv
  45. def Jacobi(a, n):
  46. """Function for calculating Jacobi symbol.
  47. Note that this is only defined for positive odd integers n.
  48. Uses algorithm from
  49. <https://en.wikipedia.org/wiki/Jacobi_symbol#Calculating_the_Jacobi_symbol>
  50. """
  51. if n < 1:
  52. raise ValueError("n must be positive")
  53. if (n % 2 == 0):
  54. raise ValueError("n must be odd")
  55. if a % n != a:
  56. return Jacobi(a%n, n)
  57. if a != 0 and a % 2 == 0:
  58. nm8 = n % 8
  59. if (nm8 == 3 or nm8 == 5):
  60. return -1 * Jacobi(a//2, n)
  61. else:
  62. return Jacobi(a//2, n)
  63. if a == 1:
  64. return 1
  65. if gcd(a, n) != 1:
  66. return 0
  67. if a == 0 and n == 1:
  68. return 1
  69. if n % 4 == 3 and a % 4 == 3:
  70. return -1 * Jacobi(n, a)
  71. return Jacobi(n, a)
  72. def FirstD(n):
  73. """Return first D in the sequence 5, -7, 9, -11, 13, -15... for which the
  74. Jacobi symbol (D/n) is -1
  75. """
  76. if n < 1 or n % 2 == 0:
  77. raise ValueError("n must be a positive odd number")
  78. # Flag to see if it's been checked whether or not n is
  79. # square
  80. haschecked = False
  81. for D in Dsequence():
  82. if Jacobi(D, n) == -1:
  83. return D
  84. # This is supposed to be faster
  85. if D > 30 and not haschecked:
  86. if hasIntSQRT(n):
  87. raise ValueError("n must not be a square")
  88. # Shouldn't fire
  89. return 0
  90. def Lucas(n, p, q):
  91. """Function for generating values of a lucas sequence with parameters p, q.
  92. Via formula at <https://en.wikipedia.org/wiki/Lucas_sequence>
  93. """
  94. if n < 0:
  95. raise ValueError("n must be a non-negative integer")
  96. Uc = 0
  97. Vc = 2
  98. for i in range(n):
  99. Un = (p * Uc + Vc) // 2
  100. Vn = ((p * p - 4 * q) * Uc + p * Vc) // 2
  101. Uc = Un
  102. Vc = Vn
  103. return Uc, Vc
  104. def LucasUn(n, p, q):
  105. """Return only the U numbers from a lucas sequence Un(P, Q). For example if
  106. P = 1, and Q = -1 this will return the Fibonacci numbers; if P = 3 and Q =
  107. 2 then it returns the Mersenne numbers etc.
  108. """
  109. return Lucas(n, p, q)[0]
  110. def LucasVn(n, p, q):
  111. """Return only V numbers from a local sequence Vn(P, Q).
  112. """
  113. return Lucas(n, p, q)[1]
  114. def LucasFast(k, p, q, n):
  115. if k < 0:
  116. raise ValueError("k must be a non-negative integer")
  117. if n < 1:
  118. raise ValueError("n must be a postive integer")
  119. if n % 2 == 0:
  120. raise ValueError("n must be odd")
  121. uc, vc = Lucas(0, p, q)
  122. dk = floor(log(k, 2))
  123. tp = 2**dk
  124. krunn = k
  125. ks = 0
  126. for i in range(dk + 1):
  127. un = (uc * vc)
  128. vn = (pow(vc, 2, n) - 2 * pow(q, ks, n))
  129. uc = un % n
  130. vc = vn % n
  131. ks = ks * 2
  132. if krunn >= tp:
  133. krunn = krunn - tp
  134. ks = ks + 1
  135. un = p * uc + vc
  136. if un % 2 != 0:
  137. un = un + n
  138. vn = (p * p - 4 * q) * uc + p * vc
  139. if vn % 2 != 0:
  140. vn = vn + n
  141. uc = (un // 2) % n
  142. vc = (vn // 2) % n
  143. tp = tp // 2
  144. return(uc, vc)
  145. for i in range(1, 20, 2):
  146. if hasIntSQRT(i):
  147. continue
  148. d = FirstD(i)
  149. q = (1 - d) // 4
  150. fu, fv = LucasFast(i + 1, 1, q, i)
  151. su, sv = Lucas(i + 1, 1, q)
  152. su = su % i
  153. sv = sv % i
  154. if (fu != su) or (fv != sv):
  155. print("{}: {}, {}; {} {}".format(i, fu, fv, su, sv))
  156. print("Done!")
  157. i = 19999999999999999999999999999999999999999999999999999999999
  158. t1 = process_time()
  159. hasIntSQRT(i)
  160. te = process_time() - t1
  161. print(te)
  162. t1 = process_time()
  163. d = FirstD(i)
  164. te = process_time() - t1
  165. print(te)
  166. q = (1 - d) // 4
  167. t1 = process_time()
  168. LucasFast(i + 1, 1, q, i)
  169. te = process_time() - t1
  170. print(te)
  171. t1 = process_time()