Skip to content

Commit beca90d

Browse files
committed
Add an iterative rational implementation for exact results
Adds an implementation in golang using rational number types to get exact results, and an iterative algorithm for performance improvement compared to recursive approaches. Outputs to CSV for easy data integration with tooling.
1 parent dce3f27 commit beca90d

File tree

4 files changed

+88
-1
lines changed

4 files changed

+88
-1
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Build go binary
2+
3+
frog

README.md

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,39 @@
11
# frog_problem
22
Here is the frog problem code I wrote in an Edinburgh pub.
33

4-
Feel free to make better version. This one has not changed since I wrote it. V1 was the same code but saved before I changed it to work for different distances so I have not bothered upload it as well (it was still very unifinished).
4+
Feel free to make better version. This one has not changed since I wrote it. V1
5+
was the same code but saved before I changed it to work for different distances
6+
so I have not bothered upload it as well (it was still very unifinished).
57

68
Video is here: https://youtu.be/ZLTyX4zL2Fc
9+
10+
## Iterative Rational Implmentation
11+
12+
Written in Golang by Taylor Wrobel
13+
14+
Makes use of big rationals in golang to get exact expectation for all number of
15+
pads, up to and including the specified target number of pads (including target
16+
bank). Makes use of an interative approach, which performs better than its
17+
recursive equivalent (calculating all results up to 1,000 pads takes ~12.5
18+
seconds for me).
19+
20+
Outputs to STDOUT in CSV format with the following columns (output for `n=10`
21+
displayed in table form):
22+
23+
n | numerator | denominator | float64 representation
24+
-- | --------- | ----------- | ----------------------
25+
1 | 1 | 1 | 1.000000
26+
2 | 3 | 2 | 1.500000
27+
3 | 11 | 6 | 1.833333
28+
4 | 25 | 12 | 2.083333
29+
5 | 137 | 60 | 2.283333
30+
6 | 49 | 20 | 2.450000
31+
7 | 363 | 140 | 2.592857
32+
8 | 761 | 280 | 2.717857
33+
9 | 7129 | 2520 | 2.828968
34+
10 | 7381 | 2520 | 2.928968
35+
36+
37+
Building: `go build`
38+
Running: `./frog [n]` (`n` defaults to 10 if not provided)
39+
Outputting to file (on a UNIX system): `./frog 100 > output.csv`

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module wrobel.dev/frog
2+
3+
go 1.12

main.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package main
2+
3+
import (
4+
"encoding/csv"
5+
"fmt"
6+
"math/big"
7+
"os"
8+
"strconv"
9+
"strings"
10+
)
11+
12+
func main() {
13+
// Parse input value from command line args. Do simple validation.
14+
n := 10
15+
if len(os.Args) > 1 {
16+
parsed, err := strconv.ParseInt(os.Args[1], 10, 64)
17+
if err != nil || parsed < 1 {
18+
panic("Input target must be a positive integer")
19+
}
20+
n = int(parsed)
21+
}
22+
23+
// Likelihoods is a slice that's built up iteratively, as the expected value
24+
// on lillypad n is dependent on the expected value for all lillypads from
25+
// 1 to n-1.
26+
likelihoods := make([]*big.Rat, n+1)
27+
likelihoods[0] = big.NewRat(0, 1)
28+
29+
w := csv.NewWriter(os.Stdout)
30+
31+
for i := 1; i <= n; i++ {
32+
expected := big.NewRat(0, 1)
33+
for j := 0; j < i; j++ {
34+
value := big.NewRat(0, 1)
35+
value.Add(big.NewRat(1, 1), likelihoods[j])
36+
value.Mul(value, big.NewRat(1, int64(i)))
37+
38+
expected.Add(expected, value)
39+
}
40+
likelihoods[i] = expected
41+
42+
numDenom := strings.Split(expected.String(), "/")
43+
f, _ := expected.Float64()
44+
w.Write([]string{fmt.Sprintf("%d", i), numDenom[0], numDenom[1], fmt.Sprintf("%f", f)})
45+
}
46+
47+
w.Flush()
48+
}

0 commit comments

Comments
 (0)