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.

268 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[8];
  98. if (numRandomSeeds <= 0)
  99. {
  100. randomSeeds = defaultSeeds;
  101. numRandomSeeds = 8;
  102. for (int j = 10; --j >= 0;)
  103. {
  104. Random r (0);
  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. Random::getSystemRandom().setSeed (randomSeeds[i]);
  117. BitArray p2;
  118. p2.fillBitsRandomly (0, bitLength);
  119. p.xorWith (p2);
  120. }
  121. Random::getSystemRandom().setSeedRandomly();
  122. p.setBit (bitLength - 1);
  123. p.clearBit (0);
  124. const int searchLen = jmax (1024, (bitLength / 20) * 64);
  125. while (p.getHighestBit() < bitLength)
  126. {
  127. p.add (2 * searchLen);
  128. BitArray sieve;
  129. bigSieve (p, searchLen, sieve,
  130. smallSieve, smallSieveSize);
  131. BitArray candidate;
  132. if (findCandidate (p, sieve, searchLen, candidate, certainty))
  133. return candidate;
  134. }
  135. jassertfalse
  136. return BitArray();
  137. }
  138. static bool passesMillerRabin (const BitArray& n, int iterations) throw()
  139. {
  140. const BitArray one (1);
  141. const BitArray two (2);
  142. BitArray nMinusOne (n);
  143. nMinusOne.subtract (one);
  144. BitArray d (nMinusOne);
  145. const int s = d.findNextSetBit (0);
  146. d.shiftBits (-s);
  147. BitArray smallPrimes;
  148. int numBitsInSmallPrimes = 0;
  149. for (;;)
  150. {
  151. numBitsInSmallPrimes += 256;
  152. createSmallSieve (numBitsInSmallPrimes, smallPrimes);
  153. const int numPrimesFound = numBitsInSmallPrimes - smallPrimes.countNumberOfSetBits();
  154. if (numPrimesFound > iterations + 1)
  155. break;
  156. }
  157. int smallPrime = 2;
  158. while (--iterations >= 0)
  159. {
  160. smallPrime = smallPrimes.findNextClearBit (smallPrime + 1);
  161. BitArray r (smallPrime);
  162. //r.createRandomNumber (nMinusOne);
  163. r.exponentModulo (d, n);
  164. if (! (r == one || r == nMinusOne))
  165. {
  166. for (int j = 0; j < s; ++j)
  167. {
  168. r.exponentModulo (two, n);
  169. if (r == nMinusOne)
  170. break;
  171. }
  172. if (r != nMinusOne)
  173. return false;
  174. }
  175. }
  176. return true;
  177. }
  178. bool Primes::isProbablyPrime (const BitArray& number,
  179. const int certainty) throw()
  180. {
  181. if (! number[0])
  182. return false;
  183. if (number.getHighestBit() <= 10)
  184. {
  185. const int num = number.getBitRangeAsInt (0, 10);
  186. for (int i = num / 2; --i > 1;)
  187. if (num % i == 0)
  188. return false;
  189. return true;
  190. }
  191. else
  192. {
  193. const BitArray screen (2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23);
  194. if (number.findGreatestCommonDivisor (screen) != BitArray (1))
  195. return false;
  196. return passesMillerRabin (number, certainty);
  197. }
  198. }
  199. END_JUCE_NAMESPACE