BitSieve.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #include <vector>
  2. #include <cstdint>
  3. class BitSieve {
  4. using uint64_t = std::uint64_t;
  5. /**
  6. * Stores the bits in this bitSieve.
  7. */
  8. std::vector<uint64_t> bits;
  9. /**
  10. * Length is how many bits this sieve holds.
  11. */
  12. int length;
  13. /**
  14. * A small sieve used to filter out multiples of small primes in a search
  15. * sieve.
  16. */
  17. static BitSieve smallSieve = new BitSieve();
  18. /**
  19. * Construct a "small sieve" with a base of 0. This constructor is
  20. * used internally to generate the set of "small primes" whose multiples
  21. * are excluded from sieves generated by the main (package private)
  22. * constructor, BitSieve(BigInteger base, int searchLen). The length
  23. * of the sieve generated by this constructor was chosen for performance;
  24. * it controls a tradeoff between how much time is spent constructing
  25. * other sieves, and how much time is wasted testing composite candidates
  26. * for primality. The length was chosen experimentally to yield good
  27. * performance.
  28. */
  29. BitSieve() {
  30. length = 150 * 64;
  31. bits = std::vector<uint64_t>((unitIndex(length - 1) + 1));
  32. // Mark 1 as composite
  33. set(0);
  34. int nextIndex = 1;
  35. int nextPrime = 3;
  36. // Find primes and remove their multiples from sieve
  37. do {
  38. sieveSingle(length, nextIndex + nextPrime, nextPrime);
  39. nextIndex = sieveSearch(length, nextIndex + 1);
  40. nextPrime = 2*nextIndex + 1;
  41. } while((nextIndex > 0) && (nextPrime < length));
  42. }
  43. /**
  44. * Construct a bit sieve of searchLen bits used for finding prime number
  45. * candidates. The new sieve begins at the specified base, which must
  46. * be even.
  47. */
  48. BitSieve(BigInteger base, int searchLen) {
  49. /*
  50. * Candidates are indicated by clear bits in the sieve. As a candidates
  51. * nonprimality is calculated, a bit is set in the sieve to eliminate
  52. * it. To reduce storage space and increase efficiency, no even numbers
  53. * are represented in the sieve (each bit in the sieve represents an
  54. * odd number).
  55. */
  56. bits = std::vector<uint64_t>((unitIndex(length - 1) + 1));
  57. length = searchLen;
  58. int start = 0;
  59. int step = smallSieve.sieveSearch(smallSieve.length, start);
  60. int convertedStep = (step *2) + 1;
  61. // Construct the large sieve at an even offset specified by base
  62. MutableBigInteger b(base);
  63. MutableBigInteger q;
  64. do {
  65. // Calculate base mod convertedStep
  66. start = b.divideOneWord(convertedStep, q);
  67. // Take each multiple of step out of sieve
  68. start = convertedStep - start;
  69. if (start%2 == 0)
  70. start += convertedStep;
  71. sieveSingle(searchLen, (start-1)/2, convertedStep);
  72. // Find next prime from small sieve
  73. step = smallSieve.sieveSearch(smallSieve.length, step+1);
  74. convertedStep = (step *2) + 1;
  75. } while (step > 0);
  76. }
  77. /**
  78. * Given a bit index return unit index containing it.
  79. */
  80. static int unitIndex(unsigned int bitIndex) {
  81. return bitIndex >> 6;
  82. }
  83. /**
  84. * Return a unit that masks the specified bit in its unit.
  85. */
  86. static long bit(unsigned int bitIndex) {
  87. return 1ULL << (bitIndex & ((1<<6) - 1));
  88. }
  89. /**
  90. * Get the value of the bit at the specified index.
  91. */
  92. bool get(unsigned int bitIndex) {
  93. unsigned int unitIndex = unitIndex(bitIndex);
  94. return ((bits[unitIndex] & bit(bitIndex)) != 0);
  95. }
  96. /**
  97. * Set the bit at the specified index.
  98. */
  99. void set(unsigned int bitIndex) {
  100. unsigned int unitIndex = unitIndex(bitIndex);
  101. bits[unitIndex] |= bit(bitIndex);
  102. }
  103. /**
  104. * This method returns the index of the first clear bit in the search
  105. * array that occurs at or after start. It will not search past the
  106. * specified limit. It returns -1 if there is no such clear bit.
  107. */
  108. int sieveSearch(unsigned int limit, unsigned int start) {
  109. if (start >= limit)
  110. return -1;
  111. int index = start;
  112. do {
  113. if (!get(index))
  114. return index;
  115. index++;
  116. } while(index < limit-1);
  117. return -1;
  118. }
  119. /**
  120. * Sieve a single set of multiples out of the sieve. Begin to remove
  121. * multiples of the specified step starting at the specified start index,
  122. * up to the specified limit.
  123. */
  124. void sieveSingle(int limit, int start, int step) {
  125. while(start < limit) {
  126. set(start);
  127. start += step;
  128. }
  129. }
  130. /**
  131. * Test probable primes in the sieve and return successful candidates.
  132. */
  133. BigInteger retrieve(const BigInteger& initValue, unsigned int certainty, java.util.Random random) {
  134. // Examine the sieve one long at a time to find possible primes
  135. int offset = 1;
  136. for (int i=0; i<bits.length; i++) {
  137. uint64_t nextLong = ~bits[i];
  138. for (int j=0; j<64; j++) {
  139. if ((nextLong & 1) == 1) {
  140. BigInteger candidate = initValue.add(
  141. BigInteger.valueOf(offset));
  142. if (candidate.primeToCertainty(certainty, random))
  143. return candidate;
  144. }
  145. nextLong >>= 1;
  146. offset += 2;
  147. }
  148. }
  149. return BigInteger(0);
  150. }
  151. }