aboutsummaryrefslogtreecommitdiff
path: root/gcd/gcd.go
blob: 562e53b328f46f4ece69d9efd475ffb39040ee04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package main

import (
	"fmt"
	"math"
	"os"
	"strconv"
	"sync"
)

func main() {
	if len(os.Args) != 3 {
		fmt.Println("we need 2 numbers. usage: ./gcd 200 50")
		os.Exit(2)
	}
	a, err := strconv.Atoi(os.Args[1])
	if err != nil {
		fmt.Printf("whatever %s is… I can't make it an integer: %v\n", os.Args[1], err)
		os.Exit(1)
	}
	b, err := strconv.Atoi(os.Args[2])
	if err != nil {
		fmt.Printf("whatever %s is… I can't make it an integer: %v\n", os.Args[2], err)
		os.Exit(1)
	}

	fmt.Println(gcd(a, b))
}

func gcd(a, b int) int {
	if a == 0 || b == 0 {
		return 0
	}

	adiv := make(chan []int)
	bdiv := make(chan []int)

	go getDivisors(a, adiv)
	go getDivisors(b, bdiv)

	adivs := <-adiv
	bdivs := <-bdiv

	var gcd int

	for i := 0; i < len(adivs); i++ {
		for j := 0; j < len(bdivs); j++ {
			if adivs[i] == bdivs[j] && adivs[i] > gcd {
				gcd = adivs[i]
			}
		}
	}

	return gcd
}

func getDivisors(num int, out chan []int) {
	results := make(chan int, 4096)
	joined := make(chan struct{})
	var res []int
	var wg sync.WaitGroup

	go func(r chan int) {
		for i := range r {
			res = append(res, i)
		}
		joined <- struct{}{}
	}(results)

	concurrency := int(math.Ceil(float64(num) / 512))

	for i := 0; i < concurrency; i++ {
		wg.Add(1)
		go func(n, l, u int) {
			defer wg.Done()
			getDivisorsLimit(n, l, u, results)
		}(num, i*512+1, i*512+512)
	}

	wg.Wait()
	close(results)
	<-joined

	out <- res
}

func getDivisorsLimit(num, lowerBound, upperBound int, results chan int) {
	for i := lowerBound; i <= upperBound && i <= num; i++ {
		if num%i == 0 {
			results <- i
		}
	}
}