开始,21e9
进行筛查以查找每个数字<= N的最小因数。生成goroutine来对数字空间的部分进行计数。
运行“开始运行prime.go -P 4 -N 21000000000”。
package main
import (
"flag"
"fmt"
"runtime"
)
const S = 1 << 16
func main() {
var N, P int
flag.IntVar(&N, "N", 10000, "N")
flag.IntVar(&P, "P", 4, "number of goroutines to use")
flag.Parse()
fmt.Printf("N = %d\n", N)
fmt.Printf("P = %d\n", P)
runtime.GOMAXPROCS(P)
// Spawn goroutines to check sections of the number range.
c := make(chan uint64, P)
for i := 0; i < P; i++ {
a := 2 + (N-1)*i/P
b := 2 + (N-1)*(i+1)/P
go process(a, b, c)
}
var sum uint64
for i := 0; i < P; i++ {
sum += <-c
}
fmt.Printf("T(%d) = %d\n", N, sum)
}
func process(a, b int, res chan uint64) {
// Find primes up to sqrt(b). Compute starting offsets.
var primes []int
var offsets []int
for p := 2; p*p < b; p++ {
if !prime(p) {
continue
}
primes = append(primes, p)
off := a % p
if off != 0 {
off = p - off
}
offsets = append(offsets, off)
}
// Allocate sieve array.
composite := make([]bool, S)
// Check factors of numbers up to b, a block of S at a time.
var sum uint64
for ; a < b; a += S {
runtime.Gosched()
// Check divisibility of [a,a+S) by our set of primes.
for i, p := range primes {
off := offsets[i]
for ; off < S; off += p {
if composite[off] {
continue // Divisible by a smaller prime.
}
composite[off] = true
if a+off < b {
sum += uint64(p)
}
}
// Remember offset for next block.
offsets[i] = off - S
}
// Any remaining numbers are prime.
for i := 0; i < S; i++ {
if composite[i] {
composite[i] = false // Reset for next block.
continue
}
if a+i < b {
sum += uint64(a + i)
}
}
}
res <- sum
}
func prime(n int) bool {
for i := 2; i*i <= n; i++ {
if n%i == 0 {
return false
}
}
return true
}
请注意,N = 21e9的答案在2 ^ 63和2 ^ 64之间,因此我必须使用无符号64位整数来正确计数...