我想下面的方法使用 Eratosthenes筛选(包含 - 排除算法)来生成最多给定数量的素数。
我特别不明白的是,为什么它清除(j/2)
位置上设置的位。是否遵循了特定的规则? BitSet
包含在位置x处设置的位,此数字是素数或是复合数。所以,我无法跟踪发生的事情。
public static List<Integer> generatePrimes(int max) {
BitSet primeSet = new BitSet(max / 2);
primeSet.set(1, max / 2);
int limit = (int) Math.sqrt(max);
for (int i = 3; i <= limit; i += 2) {
if (!primeSet.get(i / 2)) continue;
for (int j = i * i; j < max; j += i * 2)
primeSet.clear(j / 2);
}
List<Integer> listOfPrimes = new ArrayList<>();
listOfPrimes.add(2);
for (int i = primeSet.nextSetBit(0); i >= 0; i = primeSet.nextSetBit(i + 1)) {
listOfPrimes.add(i * 2 + 1);
}
return listOfPrimes;
}
答案 0 :(得分:2)
似乎该算法试图通过primeSet
代表奇数仅来节省内存。因此,重复乘法和除以2。
涉及primeSet.clear()
的循环只是将i
的每个倍数标记为复合。
答案 1 :(得分:2)
public static List<Integer> generatePrimes(int max) {
BitSet primeSet = new BitSet(max / 2); // host the numbers i up to max/2
primeSet.set(1, max / 2); // representing the odds (2i+1)
int limit = (int) Math.sqrt(max); // below max
for (int i = 3; i <= limit; i += 2) // enumerate odds in range
{ // 3 .. sqrt(max)
if (!primeSet.get(i / 2)) continue; // i=2k+1, i/2==(2k+1)/2== k
// (here i is value, k is index)
for (int j = i * i; j < max; j += i * 2) // j=i*i is the first multiple
primeSet.clear(j / 2); // of i, where the marking off begins
} // with step 2*i: 3: 9,6,15,21,...
// 7: 49,63,77,91,...
List<Integer> listOfPrimes = new ArrayList<>();
listOfPrimes.add(2); // 2 is known to be prime a priori
for (int i = primeSet.nextSetBit(0); // starting with first set bit in
// BitSet primeSet,
i >= 0; // 1: until the end of primeSet
i = primeSet.nextSetBit(i + 1) // 3: and go to next set bit
) {
listOfPrimes.add(i * 2 + 1); // 2: add 2i+1 to the list of primes,
} // (here i is index)
return listOfPrimes;
}
作为筛子的一部分,我们必须在从9开始的几率中标记每个第三个数字,并且通常从 n 2开始每个 n < / sup>,显然只有一个Rev. Samuel Horsley F.R.S. knew back in 1772。
沿着列表计算是低效的 - 筛选效率的关键是通过地址直接访问内存。这里数字数字中的数字地址只是数字的值本身(这个
要直接计算每个第3个奇数,我们必须将6添加到前一个以获得下一个。对于每个第5个,我们添加10个,每个i
- 2*i
。
顺便说一句,这段代码可以稍微改进一下。对于它们之间距离2*i
处的数字,集合中的索引将位于i
的距离处。无需一直删除2,只需计算起始索引和增量i
。
编辑:该代码等同于以下伪代码:
defn primes(max):
sieve := makeArray(3,5,7 ... max, True)
for p from 3 to sqrt(max) step 2:
if sieve[p]:
for i from p * p to max step 2*p:
sieve[i] := False
primes = {2} + {all i in (3,5,7, ... max) such that sieve[i] is True}
答案 2 :(得分:1)
除了2之外的所有偶数都不是素数,因此不需要迭代它们。
答案 3 :(得分:1)
primeset的位表示数字2x + 1,其中x是bitset的索引。因此,当你的primeset包含{1,2,3,5,6,8,9,11,14}时,它们代表数字{3,5,7,11,13,17,19,23,29}。 / p>
如果您对素数编程感兴趣,我会在我的博客上谦虚地推荐this essay。除此之外,它解释了Eratosthenes的Sieve以及导致你悲伤的计算。
编辑:添加简单的Eratosthenes筛选,如评论中所述。
function primes(n)
sieve := makeArray(2..n, True)
for p from 2 to n step 1
if sieve[p]
output p
for i from p * p to n step p
sieve[i] := False