The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 lines
6.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_Primes.h"
  21. #include "../maths/juce_Random.h"
  22. //==============================================================================
  23. namespace PrimesHelpers
  24. {
  25. void createSmallSieve (const int numBits, BigInteger& result)
  26. {
  27. result.setBit (numBits);
  28. result.clearBit (numBits); // to enlarge the array
  29. result.setBit (0);
  30. int n = 2;
  31. do
  32. {
  33. for (int i = n + n; i < numBits; i += n)
  34. result.setBit (i);
  35. n = result.findNextClearBit (n + 1);
  36. }
  37. while (n <= (numBits >> 1));
  38. }
  39. void bigSieve (const BigInteger& base, const int numBits, BigInteger& result,
  40. const BigInteger& smallSieve, const int smallSieveSize)
  41. {
  42. jassert (! base[0]); // must be even!
  43. result.setBit (numBits);
  44. result.clearBit (numBits); // to enlarge the array
  45. int index = smallSieve.findNextClearBit (0);
  46. do
  47. {
  48. const int prime = (index << 1) + 1;
  49. BigInteger r (base), remainder;
  50. r.divideBy (prime, remainder);
  51. int i = prime - remainder.getBitRangeAsInt (0, 32);
  52. if (r.isZero())
  53. i += prime;
  54. if ((i & 1) == 0)
  55. i += prime;
  56. i = (i - 1) >> 1;
  57. while (i < numBits)
  58. {
  59. result.setBit (i);
  60. i += prime;
  61. }
  62. index = smallSieve.findNextClearBit (index + 1);
  63. }
  64. while (index < smallSieveSize);
  65. }
  66. bool findCandidate (const BigInteger& base, const BigInteger& sieve,
  67. const int numBits, BigInteger& result, const int certainty)
  68. {
  69. for (int i = 0; i < numBits; ++i)
  70. {
  71. if (! sieve[i])
  72. {
  73. result = base + (unsigned int) ((i << 1) + 1);
  74. if (Primes::isProbablyPrime (result, certainty))
  75. return true;
  76. }
  77. }
  78. return false;
  79. }
  80. bool passesMillerRabin (const BigInteger& n, int iterations)
  81. {
  82. const BigInteger one (1), two (2);
  83. const BigInteger nMinusOne (n - one);
  84. BigInteger d (nMinusOne);
  85. const int s = d.findNextSetBit (0);
  86. d >>= s;
  87. BigInteger smallPrimes;
  88. int numBitsInSmallPrimes = 0;
  89. for (;;)
  90. {
  91. numBitsInSmallPrimes += 256;
  92. createSmallSieve (numBitsInSmallPrimes, smallPrimes);
  93. const int numPrimesFound = numBitsInSmallPrimes - smallPrimes.countNumberOfSetBits();
  94. if (numPrimesFound > iterations + 1)
  95. break;
  96. }
  97. int smallPrime = 2;
  98. while (--iterations >= 0)
  99. {
  100. smallPrime = smallPrimes.findNextClearBit (smallPrime + 1);
  101. BigInteger r (smallPrime);
  102. r.exponentModulo (d, n);
  103. if (r != one && r != nMinusOne)
  104. {
  105. for (int j = 0; j < s; ++j)
  106. {
  107. r.exponentModulo (two, n);
  108. if (r == nMinusOne)
  109. break;
  110. }
  111. if (r != nMinusOne)
  112. return false;
  113. }
  114. }
  115. return true;
  116. }
  117. }
  118. //==============================================================================
  119. BigInteger Primes::createProbablePrime (const int bitLength,
  120. const int certainty,
  121. const int* randomSeeds,
  122. int numRandomSeeds)
  123. {
  124. using namespace PrimesHelpers;
  125. int defaultSeeds [16];
  126. if (numRandomSeeds <= 0)
  127. {
  128. randomSeeds = defaultSeeds;
  129. numRandomSeeds = numElementsInArray (defaultSeeds);
  130. Random r;
  131. for (int j = 10; --j >= 0;)
  132. {
  133. r.setSeedRandomly();
  134. for (int i = numRandomSeeds; --i >= 0;)
  135. defaultSeeds[i] ^= r.nextInt() ^ Random::getSystemRandom().nextInt();
  136. }
  137. }
  138. BigInteger smallSieve;
  139. const int smallSieveSize = 15000;
  140. createSmallSieve (smallSieveSize, smallSieve);
  141. BigInteger p;
  142. for (int i = numRandomSeeds; --i >= 0;)
  143. {
  144. BigInteger p2;
  145. Random r (randomSeeds[i]);
  146. r.fillBitsRandomly (p2, 0, bitLength);
  147. p ^= p2;
  148. }
  149. p.setBit (bitLength - 1);
  150. p.clearBit (0);
  151. const int searchLen = jmax (1024, (bitLength / 20) * 64);
  152. while (p.getHighestBit() < bitLength)
  153. {
  154. p += 2 * searchLen;
  155. BigInteger sieve;
  156. bigSieve (p, searchLen, sieve,
  157. smallSieve, smallSieveSize);
  158. BigInteger candidate;
  159. if (findCandidate (p, sieve, searchLen, candidate, certainty))
  160. return candidate;
  161. }
  162. jassertfalse;
  163. return BigInteger();
  164. }
  165. bool Primes::isProbablyPrime (const BigInteger& number, const int certainty)
  166. {
  167. using namespace PrimesHelpers;
  168. if (! number[0])
  169. return false;
  170. if (number.getHighestBit() <= 10)
  171. {
  172. const int num = number.getBitRangeAsInt (0, 10);
  173. for (int i = num / 2; --i > 1;)
  174. if (num % i == 0)
  175. return false;
  176. return true;
  177. }
  178. else
  179. {
  180. if (number.findGreatestCommonDivisor (2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23) != 1)
  181. return false;
  182. return passesMillerRabin (number, certainty);
  183. }
  184. }
  185. END_JUCE_NAMESPACE