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.

240 lines
6.6KB

  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. namespace PrimesHelpers
  19. {
  20. static void createSmallSieve (const int numBits, BigInteger& result)
  21. {
  22. result.setBit (numBits);
  23. result.clearBit (numBits); // to enlarge the array
  24. result.setBit (0);
  25. int n = 2;
  26. do
  27. {
  28. for (int i = n + n; i < numBits; i += n)
  29. result.setBit (i);
  30. n = result.findNextClearBit (n + 1);
  31. }
  32. while (n <= (numBits >> 1));
  33. }
  34. static void bigSieve (const BigInteger& base, const int numBits, BigInteger& result,
  35. const BigInteger& smallSieve, const int smallSieveSize)
  36. {
  37. jassert (! base[0]); // must be even!
  38. result.setBit (numBits);
  39. result.clearBit (numBits); // to enlarge the array
  40. int index = smallSieve.findNextClearBit (0);
  41. do
  42. {
  43. const unsigned int prime = ((unsigned int) index << 1) + 1;
  44. BigInteger r (base), remainder;
  45. r.divideBy (prime, remainder);
  46. unsigned int i = prime - remainder.getBitRangeAsInt (0, 32);
  47. if (r.isZero())
  48. i += prime;
  49. if ((i & 1) == 0)
  50. i += prime;
  51. i = (i - 1) >> 1;
  52. while (i < (unsigned int) numBits)
  53. {
  54. result.setBit ((int) i);
  55. i += prime;
  56. }
  57. index = smallSieve.findNextClearBit (index + 1);
  58. }
  59. while (index < smallSieveSize);
  60. }
  61. static bool findCandidate (const BigInteger& base, const BigInteger& sieve,
  62. const int numBits, BigInteger& result, const int certainty)
  63. {
  64. for (int i = 0; i < numBits; ++i)
  65. {
  66. if (! sieve[i])
  67. {
  68. result = base + (unsigned int) ((i << 1) + 1);
  69. if (Primes::isProbablyPrime (result, certainty))
  70. return true;
  71. }
  72. }
  73. return false;
  74. }
  75. static bool passesMillerRabin (const BigInteger& n, int iterations)
  76. {
  77. const BigInteger one (1), two (2);
  78. const BigInteger nMinusOne (n - one);
  79. BigInteger d (nMinusOne);
  80. const int s = d.findNextSetBit (0);
  81. d >>= s;
  82. BigInteger smallPrimes;
  83. int numBitsInSmallPrimes = 0;
  84. for (;;)
  85. {
  86. numBitsInSmallPrimes += 256;
  87. createSmallSieve (numBitsInSmallPrimes, smallPrimes);
  88. const int numPrimesFound = numBitsInSmallPrimes - smallPrimes.countNumberOfSetBits();
  89. if (numPrimesFound > iterations + 1)
  90. break;
  91. }
  92. int smallPrime = 2;
  93. while (--iterations >= 0)
  94. {
  95. smallPrime = smallPrimes.findNextClearBit (smallPrime + 1);
  96. BigInteger r (smallPrime);
  97. r.exponentModulo (d, n);
  98. if (r != one && r != nMinusOne)
  99. {
  100. for (int j = 0; j < s; ++j)
  101. {
  102. r.exponentModulo (two, n);
  103. if (r == nMinusOne)
  104. break;
  105. }
  106. if (r != nMinusOne)
  107. return false;
  108. }
  109. }
  110. return true;
  111. }
  112. }
  113. //==============================================================================
  114. BigInteger Primes::createProbablePrime (const int bitLength,
  115. const int certainty,
  116. const int* randomSeeds,
  117. int numRandomSeeds)
  118. {
  119. using namespace PrimesHelpers;
  120. int defaultSeeds [16];
  121. if (numRandomSeeds <= 0)
  122. {
  123. randomSeeds = defaultSeeds;
  124. numRandomSeeds = numElementsInArray (defaultSeeds);
  125. Random r1, r2;
  126. for (int j = 10; --j >= 0;)
  127. {
  128. r1.setSeedRandomly();
  129. for (int i = numRandomSeeds; --i >= 0;)
  130. defaultSeeds[i] ^= r1.nextInt() ^ r2.nextInt();
  131. }
  132. }
  133. BigInteger smallSieve;
  134. const int smallSieveSize = 15000;
  135. createSmallSieve (smallSieveSize, smallSieve);
  136. BigInteger p;
  137. for (int i = numRandomSeeds; --i >= 0;)
  138. {
  139. BigInteger p2;
  140. Random r (randomSeeds[i]);
  141. r.fillBitsRandomly (p2, 0, bitLength);
  142. p ^= p2;
  143. }
  144. p.setBit (bitLength - 1);
  145. p.clearBit (0);
  146. const int searchLen = jmax (1024, (bitLength / 20) * 64);
  147. while (p.getHighestBit() < bitLength)
  148. {
  149. p += 2 * searchLen;
  150. BigInteger sieve;
  151. bigSieve (p, searchLen, sieve,
  152. smallSieve, smallSieveSize);
  153. BigInteger candidate;
  154. if (findCandidate (p, sieve, searchLen, candidate, certainty))
  155. return candidate;
  156. }
  157. jassertfalse;
  158. return BigInteger();
  159. }
  160. bool Primes::isProbablyPrime (const BigInteger& number, const int certainty)
  161. {
  162. using namespace PrimesHelpers;
  163. if (! number[0])
  164. return false;
  165. if (number.getHighestBit() <= 10)
  166. {
  167. const unsigned int num = number.getBitRangeAsInt (0, 10);
  168. for (unsigned int i = num / 2; --i > 1;)
  169. if (num % i == 0)
  170. return false;
  171. return true;
  172. }
  173. else
  174. {
  175. if (number.findGreatestCommonDivisor (2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23) != 1)
  176. return false;
  177. return passesMillerRabin (number, certainty);
  178. }
  179. }