-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathproblem12.go
More file actions
105 lines (99 loc) · 3.3 KB
/
Copy pathproblem12.go
File metadata and controls
105 lines (99 loc) · 3.3 KB
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
94
95
96
97
98
99
100
101
102
103
104
105
package projecteuler
import "sync"
// GetXthTriangularNumber - Returns triangular number at given position `x`
func GetXthTriangularNumber(x int) int {
return x * (x + 1) / 2
}
// GetFactorCount - Return number of factors a given number have
func GetFactorCount(x int) int {
if x == 1 {
return 1
}
count := 2
for i := 2; i <= x/2; i++ {
if x%i == 0 {
count++
}
}
return count
}
// TriangularNumber - Holds a triangular number, along with number of its factors
type TriangularNumber struct {
num int
factorC int
}
// this function tries to find out maximum triangular number
// with in a given range ( i.e. denotes position of triangular numbers )
//
// we're also having two communication channels, which will help us
// in sending back computed value & checking whether to abort computation or not, respectively
//
// `maxFactorC` - denotes maximum count of factors, from all triangular numbers of this given range ( by position of triangular number )
// `channel` - used to send computed result back to listener
// `channelEnd` - used for monitoring whether this goroutine is asked to abort its computation immediately or not
func getHighlyDivisibleTriNumFromRange(init int, end int, maxFactorC int, channel chan TriangularNumber, channelEnd chan bool) {
triNum := TriangularNumber{1, 1}
for i := init; i <= end; i++ {
select {
case <-channelEnd:
return
default:
tmpX := GetXthTriangularNumber(i)
if tmp := GetFactorCount(tmpX); tmp > triNum.factorC {
triNum.factorC = tmp
triNum.num = tmpX
if triNum.factorC >= maxFactorC {
break
}
}
}
}
// pushing value ( triangular number with maximum number of factors, from given range ) via channel
channel <- triNum
if triNum.factorC >= maxFactorC {
close(channel) // if found desired value, we go for closing this channel, to let listener know, there's nothing more to read
}
}
// HighlyDivisibleTriangularNumber - Finds out first triangular number, which has
// factors >=500
func HighlyDivisibleTriangularNumber() int {
triNum := TriangularNumber{1, 1}
channel := make(chan TriangularNumber, 2)
channelEnd := make(chan bool)
startAt := 1
const workerC = 4
// this anonymous function is designed to create requested number of
// goroutines, by invoking a certain function, with varied arguments
createWorkers := func(startAt *int, incrBy int, c int) {
for i := 0; i < c; i++ {
go getHighlyDivisibleTriNumFromRange(*startAt, *startAt+incrBy-1, 500, channel, channelEnd)
*startAt += incrBy
}
}
var wg sync.WaitGroup
wg.Add(1)
// anonymous function, keeps track of computed values, from completed goroutines,
// if not reached expected value, can create more goroutines, for perfroming next stage
// of computation
go func() {
defer wg.Done()
respC := 0 // keeps track how many worker has completed, upto this point
for v := range channel {
if v.factorC > triNum.factorC {
triNum = v
}
if triNum.factorC >= 500 {
channelEnd <- true
break
}
respC++
if respC%workerC == 0 {
createWorkers(&startAt, 500, workerC)
}
}
}()
// initially creating specified number of goroutines, later on, if needed, we may request more workers ( for next stage of computation )
createWorkers(&startAt, 500, workerC)
wg.Wait() // blocking wait, until worker denotes work is completed
return triNum.num
}