Prime Test.swift 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. //
  2. // Prime Test.swift
  3. // CS.BigInt
  4. //
  5. // Created by Károly Lőrentey on 2016-01-04.
  6. // Copyright © 2016-2017 Károly Lőrentey.
  7. //
  8. /// The first several [prime numbers][primes].
  9. ///
  10. /// [primes]: https://oeis.org/A000040
  11. let primes: [CS.BigUInt.Word] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
  12. /// The ith element in this sequence is the smallest composite number that passes the strong probable prime test
  13. /// for all of the first (i+1) primes.
  14. ///
  15. /// This is sequence [A014233](http://oeis.org/A014233) on the [Online Encyclopaedia of Integer Sequences](http://oeis.org).
  16. let pseudoPrimes: [CS.BigUInt] = [
  17. /* 2 */ 2_047,
  18. /* 3 */ 1_373_653,
  19. /* 5 */ 25_326_001,
  20. /* 7 */ 3_215_031_751,
  21. /* 11 */ 2_152_302_898_747,
  22. /* 13 */ 3_474_749_660_383,
  23. /* 17 */ 341_550_071_728_321,
  24. /* 19 */ 341_550_071_728_321,
  25. /* 23 */ 3_825_123_056_546_413_051,
  26. /* 29 */ 3_825_123_056_546_413_051,
  27. /* 31 */ 3_825_123_056_546_413_051,
  28. /* 37 */ "318665857834031151167461",
  29. /* 41 */ "3317044064679887385961981",
  30. ]
  31. extension CS.BigUInt {
  32. //MARK: Primality Testing
  33. /// Returns true iff this integer passes the [strong probable prime test][sppt] for the specified base.
  34. ///
  35. /// [sppt]: https://en.wikipedia.org/wiki/Probable_prime
  36. public func isStrongProbablePrime(_ base: CS.BigUInt) -> Bool {
  37. precondition(base > (1 as CS.BigUInt))
  38. precondition(self > (0 as CS.BigUInt))
  39. let dec = self - 1
  40. let r = dec.trailingZeroBitCount
  41. let d = dec >> r
  42. var test = base.power(d, modulus: self)
  43. if test == 1 || test == dec { return true }
  44. if r > 0 {
  45. let shift = self.leadingZeroBitCount
  46. let normalized = self << shift
  47. for _ in 1 ..< r {
  48. test *= test
  49. test.formRemainder(dividingBy: normalized, normalizedBy: shift)
  50. if test == 1 {
  51. return false
  52. }
  53. if test == dec { return true }
  54. }
  55. }
  56. return false
  57. }
  58. /// Returns true if this integer is probably prime. Returns false if this integer is definitely not prime.
  59. ///
  60. /// This function performs a probabilistic [Miller-Rabin Primality Test][mrpt], consisting of `rounds` iterations,
  61. /// each calculating the strong probable prime test for a random base. The number of rounds is 10 by default,
  62. /// but you may specify your own choice.
  63. ///
  64. /// To speed things up, the function checks if `self` is divisible by the first few prime numbers before
  65. /// diving into (slower) Miller-Rabin testing.
  66. ///
  67. /// Also, when `self` is less than 82 bits wide, `isPrime` does a deterministic test that is guaranteed to
  68. /// return a correct result.
  69. ///
  70. /// [mrpt]: https://en.wikipedia.org/wiki/Miller–Rabin_primality_test
  71. public func isPrime(rounds: Int = 10) -> Bool {
  72. if count <= 1 && self[0] < 2 { return false }
  73. if count == 1 && self[0] < 4 { return true }
  74. // Even numbers above 2 aren't prime.
  75. if self[0] & 1 == 0 { return false }
  76. // Quickly check for small primes.
  77. for i in 1 ..< primes.count {
  78. let p = primes[i]
  79. if self.count == 1 && self[0] == p {
  80. return true
  81. }
  82. if self.quotientAndRemainder(dividingByWord: p).remainder == 0 {
  83. return false
  84. }
  85. }
  86. /// Give an exact answer when we can.
  87. if self < pseudoPrimes.last! {
  88. for i in 0 ..< pseudoPrimes.count {
  89. guard isStrongProbablePrime(CS.BigUInt(primes[i])) else {
  90. break
  91. }
  92. if self < pseudoPrimes[i] {
  93. // `self` is below the lowest pseudoprime corresponding to the prime bases we tested. It's a prime!
  94. return true
  95. }
  96. }
  97. return false
  98. }
  99. /// Otherwise do as many rounds of random SPPT as required.
  100. for _ in 0 ..< rounds {
  101. let random = CS.BigUInt.randomInteger(lessThan: self - 2) + 2
  102. guard isStrongProbablePrime(random) else {
  103. return false
  104. }
  105. }
  106. // Well, it smells primey to me.
  107. return true
  108. }
  109. }
  110. extension CS.BigInt {
  111. //MARK: Primality Testing
  112. /// Returns true iff this integer passes the [strong probable prime test][sppt] for the specified base.
  113. ///
  114. /// [sppt]: https://en.wikipedia.org/wiki/Probable_prime
  115. public func isStrongProbablePrime(_ base: CS.BigInt) -> Bool {
  116. precondition(base.sign == .plus)
  117. if self.sign == .minus { return false }
  118. return self.magnitude.isStrongProbablePrime(base.magnitude)
  119. }
  120. /// Returns true if this integer is probably prime. Returns false if this integer is definitely not prime.
  121. ///
  122. /// This function performs a probabilistic [Miller-Rabin Primality Test][mrpt], consisting of `rounds` iterations,
  123. /// each calculating the strong probable prime test for a random base. The number of rounds is 10 by default,
  124. /// but you may specify your own choice.
  125. ///
  126. /// To speed things up, the function checks if `self` is divisible by the first few prime numbers before
  127. /// diving into (slower) Miller-Rabin testing.
  128. ///
  129. /// Also, when `self` is less than 82 bits wide, `isPrime` does a deterministic test that is guaranteed to
  130. /// return a correct result.
  131. ///
  132. /// [mrpt]: https://en.wikipedia.org/wiki/Miller–Rabin_primality_test
  133. public func isPrime(rounds: Int = 10) -> Bool {
  134. if self.sign == .minus { return false }
  135. return self.magnitude.isPrime(rounds: rounds)
  136. }
  137. }