I have implemented a function to list prime numbers using the Sieve of Eratosthenes algorithm as follows:
func ListPrimes(n int) []int {
primeList := make([]int, 0)
primeBooleans := SieveOfEratosthenes(n)
for p := 0; p < n+1; p++ {
if primeBooleans[p] == true {
primeList = append(primeList, p)
}
}
return primeList
}
func SieveOfEratosthenes(n int) []bool {
primeBooleans := make([]bool, n+1)
sqrtN := math.Sqrt(float64(n))
for k := 2; k <= n; k++ {
primeBooleans[k] = true
}
for p := 2; float64(p) <= sqrtN; p++ {
if primeBooleans[p] == true {
primeBooleans = CrossOffMultiples(primeBooleans, p)
}
}
return primeBooleans
}
func CrossOffMultiples(primeBooleans []bool, p int) []bool {
n := len(primeBooleans) - 1
for k := 2 * p; k <= n; k += p {
primeBooleans[k] = false
}
return primeBooleans
}
But I've spotted an inefficiency: namely, that CrossOffMultiples
is being called more times than is necessary. IOW, integers that have already been "crossed off" are getting crossed off a second or third time (or even more) due to the fact that any multiple m
is going to have multiple factors that divide it. But what I can't seem to figure out is how to leverage this bit of information in such a way that allows me to reduce the number of times CrossOffMultiples
is called. I'm sure there is a way to do so, but for some reason it's eluding me.
Any suggestions?
If you reduce the number of times CrossOffMultiples
is called, i.e., you don't call it for some prime p
, then p * p
won't get crossed off. But what you can do is start its loop at p * p
instead of 2 * p
.
It's normal to cross out numbers multiple times, the sieve of Eratosthenes does that. Linear Sieve is a similar algorithm you might be interested in.