Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Linear prime sieve #219

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/algorithms/math/linear-prime-sieve/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Linear Prime Sieve

Linear Prime Sieve is an algorithm for finding all prime numbers up to some limit `n` in linear time.



## How it works

1. Create an array `leastPrimeFactor` of `n + 1` positions filled with `0`(to represent the least prime factors of numbers `0` through `n`)
2. Start at position `i = 2` (the first prime number)
3. If the least prime factor of `i` is `0` it means `i` is a prime number, so we add it to our list of `primes`.
4. We start setting the least prime factor for numbers `x`, where x = `p` * `i`, `p` is `x`'s least prime factor and `p` <= `leastPrimeFactor(i)`, we do
this by traversing the list of primes accumulated till now.
5. Increment the value of `i`.
6. We repeat steps 3 through 5 until `i` exceeds `n`.


When the algorithm terminates, all the prime numbers from `0` through `n` will be added to our primes list



## Complexity

The algorithm has a complexity of `O(n)`.



## Proof Of Correctness

In order to prove the time complexity, we need to show that the alogrithm sets all leastPrimeFactor[] correctly, and that every value will be set only once.
If so the algorithm will have linear time complexity, since all the remaining work of the algorithm is of `O(n)`.
We Observe that every number `i` has exactly one representation of form:
`i = leastPrimeFactor[i] * x`, where leastPrimeFactor[i] <= leastPrimeFactor[x].

In our Alogrith, for every `x`, it goes through all prime numbers it could be multiplied by, i.e. all prime numbers up to leastPrimeFactor[x] inclusive,
in order to get the numbers in the form given above.
Hence, the algorithm will go through every composite number exactly once, setting the correct values for leastPrimeFactor[] there.



## References

- David Gries, Jayadev Misra. A Linear Sieve Algorithm for Finding Prime Numbers [1978].
- [CP-Algorithms/Linear-Sieve](https://cp-algorithms.com/algebra/prime-sieve-linear.html).
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import linearPrimeSieve from '../linearPrimeSieve';

describe('linearPrimeSieve', () => {
it('should find all primes less than or equal to n', () => {
expect(linearPrimeSieve(5)).toEqual([2, 3, 5]);
expect(linearPrimeSieve(10)).toEqual([2, 3, 5, 7]);
expect(linearPrimeSieve(100)).toEqual([
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
]);
});
});
35 changes: 35 additions & 0 deletions src/algorithms/math/linear-prime-sieve/linearPrimeSieve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @param {number} maxNumber
* @return {number[]}
*/
export default function linearPrimeSieve(maxNumber) {
const primes = [];
// leastPrimeFactor[i] gives us the least prime factor of 'i'
const leastPrimeFactor = new Array(maxNumber + 1).fill(0);

for (let i = 2; i <= maxNumber; i += 1) {
if (!leastPrimeFactor[i]) {
/* leastPrimeFactor[i] = 0 means 'i' itself is its least prime factor,
* i.e 'i' is prime
*/
leastPrimeFactor[i] = i;
primes.push(i);
}

/*
* start setting leastPrimeFactor[] for numbers 'x', where x = p * i, p is x's
* least prime factor and p <= leastPrimeFactor[i]. x = p*i, this representation will
* be unique for any number, therefore leastPrimeFactor[x] will be
* set only once.
*/

let j = 0;
while (j < primes.length) {
if ((primes[j] * i > maxNumber) || (primes[j] > leastPrimeFactor[i])) { break; }
leastPrimeFactor[primes[j] * i] = primes[j];
j += 1;
}
}

return primes;
}