How to resolve the algorithm Sieve of Eratosthenes step by step in the Go programming language

Published on 12 May 2024 09:40 PM
#Go

How to resolve the algorithm Sieve of Eratosthenes step by step in the Go programming language

Table of Contents

Problem Statement

The Sieve of Eratosthenes is a simple algorithm that finds the prime numbers up to a given integer.

Implement the   Sieve of Eratosthenes   algorithm, with the only allowed optimization that the outer loop can stop at the square root of the limit, and the inner loop may start at the square of the prime just found. That means especially that you shouldn't optimize by using pre-computed wheels, i.e. don't assume you need only to cross out odd numbers (wheel based on 2), numbers equal to 1 or 5 modulo 6 (wheel based on 2 and 3), or similar wheels based on low primes. If there's an easy way to add such a wheel based optimization, implement it as an alternative version.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Sieve of Eratosthenes step by step in the Go programming language

Source code 1:

This is a basic implementation of the sieve of Eratosthenes to find prime numbers up to a limit of 201.

  • The program creates a boolean array c of size limit with all values initialized to false.
  • It iterates over numbers from 2 to the square root of limit, marking their multiples as composite in the c array.
  • After the sieve is complete, it iterates over the c array and prints the prime numbers.

Source code 2:

This is a more efficient implementation of the sieve of Eratosthenes that uses bit operations to store the prime numbers.

  • The program creates a slice cmpsts of uint values to represent the composite numbers.
  • It iterates over the odd numbers up to the square root of the top limit, marking their multiples as composite in the cmpsts slice using bitwise operations.
  • The primesOdds function returns a closure that generates the next prime number.
  • The main function prints the prime numbers up to 100 and counts the number of prime numbers up to 1 million.

Source code 3:

This is a recursive implementation of the sieve of Eratosthenes using goroutines.

  • The primes function generates a channel of prime numbers.
  • The Generate function generates a channel of increasing numbers.
  • The Filter function filters out the multiples of a given prime number from a channel of numbers.
  • The Sieve function daisy-chains Filter processes to create a channel of prime numbers.
  • The main function prints the first 100,000 prime numbers.

Source code 4:

This is another implementation of the sieve of Eratosthenes using goroutines and a different filter algorithm.

  • The Generate function generates a channel of increasing numbers.
  • The Filter function filters out the multiples of a given prime number from a channel of numbers by counting.
  • The Sieve function postpones the creation of Filter processes until they are needed, making the recursion shallower.
  • The main function prints the first 25,000 prime numbers, but it could be modified to print a different number of prime numbers.

Source code 5:

This is a simple implementation of the sieve of Eratosthenes that uses channels to communicate between goroutines.

  • The PrimeSieve function generates a channel of prime numbers.
  • The main function prints the first 100 prime numbers from the channel.
  • The PrimeSieve function generates prime numbers by repeatedly removing the multiples of the current prime number from a channel of increasing numbers.

Source code in the go programming language

package main
import "fmt"

func main() {
    const limit = 201 // means sieve numbers < 201

    // sieve
    c := make([]bool, limit) // c for composite.  false means prime candidate
    c[1] = true              // 1 not considered prime
    p := 2
    for {
        // first allowed optimization:  outer loop only goes to sqrt(limit)
        p2 := p * p
        if p2 >= limit {
            break
        }
        // second allowed optimization:  inner loop starts at sqr(p)
        for i := p2; i < limit; i += p {
            c[i] = true // it's a composite

        }
        // scan to get next prime for outer loop
        for {
            p++
            if !c[p] {
                break
            }
        }
    }

    // sieve complete.  now print a representation.
    for n := 1; n < limit; n++ {
        if c[n] {
            fmt.Print("  .")
        } else {
            fmt.Printf("%3d", n)
        }
        if n%20 == 0 {
            fmt.Println("")
        }
    }
}

package main

import (
	"fmt"
	"math"
)

func primesOdds(top uint) func() uint {
	topndx := int((top - 3) / 2)
	topsqrtndx := (int(math.Sqrt(float64(top))) - 3) / 2
	cmpsts := make([]uint, (topndx/32)+1)
	for i := 0; i <= topsqrtndx; i++ {
		if cmpsts[i>>5]&(uint(1)<<(uint(i)&0x1F)) == 0 {
			p := (i << 1) + 3
			for j := (p*p - 3) >> 1; j <= topndx; j += p {
				cmpsts[j>>5] |= 1 << (uint(j) & 0x1F)
			}
		}
	}
	i := -1
	return func() uint {
		oi := i
		if i <= topndx {
			i++
		}
		for i <= topndx && cmpsts[i>>5]&(1<<(uint(i)&0x1F)) != 0 {
			i++
		}
		if oi < 0 {
			return 2
		} else {
			return (uint(oi) << 1) + 3
		}
	}
}

func main() {
	iter := primesOdds(100)
	for v := iter(); v <= 100; v = iter() {
		print(v, " ")
	}
	iter = primesOdds(1000000)
	count := 0
	for v := iter(); v <= 1000000; v = iter() {
		count++
	}
	fmt.Printf("\r\n%v\r\n", count)
}

package main
import "fmt"

type xint uint64
type xgen func()(xint)

func primes() func()(xint) {
	pp, psq := make([]xint, 0), xint(25)

	var sieve func(xint, xint)xgen
	sieve = func(p, n xint) xgen {
		m, next := xint(0), xgen(nil)
		return func()(r xint) {
			if next == nil {
				r = n
				if r <= psq {
					n += p
					return
				}

				next = sieve(pp[0] * 2, psq) // chain in
				pp = pp[1:]
				psq = pp[0] * pp[0]

				m = next()
			}
			switch {
			case n < m: r, n = n, n + p
			case n > m: r, m = m, next()
			default:    r, n, m = n, n + p, next()
			}
			return
		}
	}

	f := sieve(6, 9)
	n, p := f(), xint(0)

	return func()(xint) {
		switch {
		case p < 2: p = 2
		case p < 3: p = 3
		default:
			for p += 2; p == n; {
				p += 2
				if p > n {
					n = f()
				}
			}
			pp = append(pp, p)
		}
		return p
	}
}

func main() {
	for i, p := 0, primes(); i < 100000; i++ {
		fmt.Println(p())
	}
}

package main
import "fmt"
 
// Send the sequence 2, 3, 4, ... to channel 'out'
func Generate(out chan<- int) {
	for i := 2; ; i++ {
		out <- i                  // Send 'i' to channel 'out'
	}
}
 
// Copy the values from 'in' channel to 'out' channel,
//   removing the multiples of 'prime' by counting.
// 'in' is assumed to send increasing numbers
func Filter(in <-chan int, out chan<- int, prime int) {
        m := prime + prime                // first multiple of prime
	for {
		i := <- in                // Receive value from 'in'
		for i > m {
			m = m + prime     // next multiple of prime
			}
		if i < m {
			out <- i          // Send 'i' to 'out'
			}
	}
}
 
// The prime sieve: Daisy-chain Filter processes
func Sieve(out chan<- int) {
	gen := make(chan int)             // Create a new channel
	go Generate(gen)                  // Launch Generate goroutine
	for  {
		prime := <- gen
		out <- prime
		ft := make(chan int)
		go Filter(gen, ft, prime)
		gen = ft
	}
}

func main() {
	sv := make(chan int)              // Create a new channel
	go Sieve(sv)                      // Launch Sieve goroutine
	for i := 0; i < 1000; i++ {
		prime := <- sv
		if i >= 990 { 
		    fmt.Printf("%4d ", prime) 
		    if (i+1)%20==0 {
			fmt.Println("")
		    }
		}
	}
}

package main
import "fmt"
 
// Send the sequence 2, 3, 4, ... to channel 'out'
func Generate(out chan<- int) {
	for i := 2; ; i++ {
		out <- i                  // Send 'i' to channel 'out'
	}
}
 
// Copy the values from 'in' channel to 'out' channel,
//   removing the multiples of 'prime' by counting.
// 'in' is assumed to send increasing numbers
func Filter(in <-chan int, out chan<- int, prime int) {
        m := prime * prime                // start from square of prime
	for {
		i := <- in                // Receive value from 'in'
		for i > m {
			m = m + prime     // next multiple of prime
			}
		if i < m {
			out <- i          // Send 'i' to 'out'
			}
	}
}
 
// The prime sieve: Postponed-creation Daisy-chain of Filters
func Sieve(out chan<- int) {
	gen := make(chan int)             // Create a new channel
	go Generate(gen)                  // Launch Generate goroutine
	p := <- gen
	out <- p
	p = <- gen          // make recursion shallower ---->
	out <- p            // (Go channels are _push_, not _pull_)
	
	base_primes := make(chan int)     // separate primes supply  
	go Sieve(base_primes)             
	bp := <- base_primes              // 2           <---- here
	bq := bp * bp                     // 4

	for  {
		p = <- gen
		if p == bq {                    // square of a base prime
			ft := make(chan int)
			go Filter(gen, ft, bp)  // filter multiples of bp in gen out
			gen = ft
			bp = <- base_primes     // 3
			bq = bp * bp            // 9
		} else {
			out <- p
		}
	}
}

func main() {
	sv := make(chan int)              // Create a new channel
	go Sieve(sv)                      // Launch Sieve goroutine
	lim := 25000              
	for i := 0; i < lim; i++ {
		prime := <- sv
		if i >= (lim-10) { 
		    fmt.Printf("%4d ", prime) 
		    if (i+1)%20==0 {
			fmt.Println("")
		    }
		}
	}
}

package main

import "fmt"

func main() {
    primes := make(chan int)
    go PrimeSieve(primes)

    p := <-primes
    for p < 100 {
        fmt.Printf("%d ", p)
        p = <-primes
    }

    fmt.Println()
}

func PrimeSieve(out chan int) {
    out <- 2
    out <- 3

    primes := make(chan int)
    go PrimeSieve(primes)

    var p int
    <-primes
    p = <-primes

    sieve := make(map[int]int)
    q := p * p
    n := p

    for {
        n += 2
        step, isComposite := sieve[n]
        if isComposite {
            delete(sieve, n)
            m := n + step
            for sieve[m] != 0 {
                m += step
            }
            sieve[m] = step

        } else if n < q {
            out <- n

        } else {
            step = p + p
            m := n + step
            for sieve[m] != 0 {
                m += step
            }
            sieve[m] = step
            p = <-primes
            q = p * p
        }
    }
}

  

You may also check:How to resolve the algorithm Window creation step by step in the Delphi programming language
You may also check:How to resolve the algorithm SHA-256 Merkle tree step by step in the Perl programming language
You may also check:How to resolve the algorithm Canonicalize CIDR step by step in the Haskell programming language
You may also check:How to resolve the algorithm Find common directory path step by step in the Swift programming language
You may also check:How to resolve the algorithm Permutations step by step in the JavaScript programming language