Ваша оптимизация должна быть применена после избавления от четного числа сначала (кроме 2). потому что когда i==2
, вы фактически пропустили все четные числа, увеличив на i*2
.
Вот рабочий код:
// prime-3
// sieve implementation
function prime3(n) {
let sieve = (new Array(n)).fill(true);
for (let i = 4; i < n; i+=2) {
sieve[i] = false;
}
// Only iterate up to the square root n for marking
for (let i = 2; i * i <= n; i += 1) {
if (sieve[i]) {
// now it works
// j = j + ( i * 2 )
for (let j = i * i; j <= n; j = j + i*2) {
sieve[j] = false;
}
}
}
return makePrimes(sieve, n);
};
function makePrimes(sieve, n) {
let primes = [];
for (let i = 2; i < n; i++) {
if (sieve[i]) {
primes.push(i);
}
}
return primes;
}
console.log(prime3(100));
Редактировать
Поцарапайте это. Дальнейшее тестирование показывает, что prime3 работает в 3 раза быстрее, чем простое сито.
Код, хотя и работает, кажется, содержит слишком много хитростей и вносит дополнительные вычисления и путаницу. Простой ситовый код, подобный следующему в моем сравнении, выполняет тот, который содержится в ответе. Опять же, KISS - это принцип.
Ситуация в исходном ответе потребовала 317 мс для просеивания чисел 1M, в то время как простому ситу потребовалось всего 241 мс.
function simpleSieve(n) {
let a = new Array(n)
let answer = []
let p
for (let i = 2; i < n; i ++) {
a[i] = i
}
for (let i = 2; i < n; i++) {
if (a[i]) {
answer.push(a[i])
p = a[i]
for(let j = p; j < n; j += p) {
a[j] = 0
}
}
}
return answer
}
Править 2
Проверено с cpp и prime3 улучшается примерно в 3 раза быстрее, чем простое сито:
p3:
n = 100000000, t = 866717 microseconds.
n = 200000000, t = 2354425 microseconds.
n = 300000000, t = 3689165 microseconds.
n = 400000000, t = 4950224 microseconds.
n = 500000000, t = 6119779 microseconds.
n = 600000000, t = 7375925 microseconds.
n = 700000000, t = 8647293 microseconds.
n = 800000000, t = 10477116 microseconds.
n = 900000000, t = 11589894 microseconds.
n = 1000000000, t = 12806997 microseconds.
simple:
n = 100000000, t = 2316019 microseconds.
n = 200000000, t = 6063749 microseconds.
n = 300000000, t = 9783295 microseconds.
n = 400000000, t = 13315450 microseconds.
n = 500000000, t = 16640474 microseconds.
n = 600000000, t = 20282461 microseconds.
n = 700000000, t = 24219469 microseconds.
n = 800000000, t = 29203786 microseconds.
n = 900000000, t = 32965856 microseconds.
n = 1000000000, t = 37694084 microseconds.
Коды здесь для полноты:
void simpleSieve(int n) {
bool *a = (bool *)calloc(n, sizeof(bool));
int p;
memset(a, true, sizeof(bool) * n);
for (int i = 2; i < n; i++) {
if (a[i]) {
p = i;
for (int j = p; j < n; j += p) {
a[j] = 0;
}
}
}
free(a);
}
void prime3(int n) {
bool *sieve = (bool*)calloc(n, sizeof(bool));
sieve[2] = true;
for (int i = 3; i < n; i+=2) {
sieve[i] = true;
}
int step;
for (int i = 2; i * i <= n; i += 1) {
if (sieve[i]) {
step = i*2;
for (int j = i * i; j <= n; j = j + step) {
sieve[j] = false;
}
}
}
free(sieve);
}