Skip to content

Instantly share code, notes, and snippets.

@taiypeo
Last active March 14, 2023 11:27
Show Gist options
  • Save taiypeo/4978eace46c88ab7aebba20e3273255b to your computer and use it in GitHub Desktop.
Save taiypeo/4978eace46c88ab7aebba20e3273255b to your computer and use it in GitHub Desktop.
Concurrent π calculation with Golang!
package main
import (
"fmt"
"math"
)
func partialSum(c chan<- float64, kStart int, kOffset int, amount int) {
// Using the Bailey–Borwein–Plouffe formula
var sum float64
for k := float64(kStart); k < float64(kStart + kOffset * amount); k += float64(kOffset) {
sum += 1 / math.Pow(16, k) * (4 / (8 * k + 1) - 2 / (8 * k + 4) - 1 / (8 * k + 5) - 1 / (8 * k + 6))
}
c <- sum
}
func main() {
var pi float64
const workers int = 5
const kOffset int = workers
const amount int = 10
doneChannel := make(chan bool)
for i := 0; i < workers; i++ {
go (func(kStart int) {
c := make(chan float64)
go partialSum(c, kStart, kOffset, amount)
pi += <-c
doneChannel <- true
})(i)
}
for i := 0; i < workers; i++ {
<-doneChannel
}
fmt.Println("Calculated π:", pi)
fmt.Println("Difference between math.Pi and calculated:", pi - math.Pi)
}
@Jamesits
Copy link

This code actually have a race condition at pi += <-c where multiple goroutines might write to pi at the same time. Here is a version that fixes this issue (and use sync package to implement the synchronization which I personally think is semantically more "correct").

package main

import (
	"fmt"
	"math"
	"sync"
)

type Float64 struct {
	value float64
	lock  sync.RWMutex
}

func (f *Float64) Inc(diff float64) float64 {
	f.lock.Lock()
	ret := f.value + diff
	f.value = ret
	f.lock.Unlock()
	return ret
}

func (f *Float64) Get() float64 {
	f.lock.RLock()
	ret := f.value
	f.lock.RUnlock()
	return ret
}

func partialSum(kStart int, kOffset int, amount int) (sum float64) {
	for k := float64(kStart); k < float64(kStart+kOffset*amount); k += float64(kOffset) {
		sum += 1 / math.Pow(16, k) * (4/(8*k+1) - 2/(8*k+4) - 1/(8*k+5) - 1/(8*k+6))
	}

	return
}

func PiMultiThread(workers int, iteration int) float64 {
	wg := sync.WaitGroup{}
	ret := Float64{}

	for i := 0; i < workers; i++ {
		wg.Add(1)
		go (func(kStart int) {
			ret.Inc(partialSum(int(kStart), workers, iteration))
			wg.Done()
		})(i)
	}

	wg.Wait()
	return ret.Get()
}

func main() {
	pi := PiMultiThread(4, 1024)
	fmt.Println("Calculated π:", pi)
	fmt.Println("Difference between math.Pi and calculated:", pi-math.Pi)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment