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.

267 lines
7.0KB

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