calculate_legendre.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. def is_prime(a):
  4. """
  5. Check if `a` is a prime number.
  6. Parameters
  7. ----------
  8. a : int, a >= 2
  9. """
  10. return all(a % i for i in xrange(2, a))
  11. # http://stackoverflow.com/a/14793082/562769
  12. def factorize(n):
  13. factors = []
  14. p = 2
  15. while True:
  16. # while we can divide by smaller number, do so
  17. while(n % p == 0 and n > 0):
  18. factors.append(p)
  19. n = n / p
  20. p += 1 # p is not necessary prime, but n%p == 0 only for prime numbers
  21. if p > n / p:
  22. break
  23. if n > 1:
  24. factors.append(n)
  25. return factors
  26. def calculate_legendre(a, p):
  27. """
  28. Calculate the legendre symbol (a, p) with p is prime.
  29. The result is either -1, 0 or 1
  30. >>> calculate_legendre(3, 29)
  31. -1
  32. >>> calculate_legendre(111, 41) # Beispiel aus dem Skript, S. 114
  33. -1
  34. >>> calculate_legendre(113, 41) # Beispiel aus dem Skript, S. 114
  35. 1
  36. >>> calculate_legendre(2, 31)
  37. 1
  38. >>> calculate_legendre(5, 31)
  39. 1
  40. # http://math.stackexchange.com/q/221223/6876
  41. >>> calculate_legendre(150, 1009)
  42. 1
  43. # http://math.stackexchange.com/q/221223/6876
  44. >>> calculate_legendre(25, 1009)
  45. 1
  46. # http://math.stackexchange.com/q/221223/6876
  47. >>> calculate_legendre(2, 1009)
  48. 1
  49. # http://math.stackexchange.com/q/221223/6876
  50. >>> calculate_legendre(3, 1009)
  51. 1
  52. """
  53. if a >= p or a < 0:
  54. return calculate_legendre(a % p, p)
  55. elif a == 0 or a == 1:
  56. return a
  57. elif a == 2:
  58. if p % 8 == 1 or p % 8 == 7:
  59. return 1
  60. else:
  61. return -1
  62. elif a == p-1:
  63. if p % 4 == 1:
  64. return 1
  65. else:
  66. return -1
  67. elif not is_prime(a):
  68. factors = factorize(a)
  69. product = 1
  70. for pi in factors:
  71. product *= calculate_legendre(pi, p)
  72. return product
  73. else:
  74. if ((p-1)/2) % 2 == 0 or ((a-1)/2) % 2 == 0:
  75. return calculate_legendre(p, a)
  76. else:
  77. return (-1)*calculate_legendre(p, a)
  78. if __name__ == "__main__":
  79. import doctest
  80. doctest.testmod()