New to go; how to use math/big - go

I am new to Go but not to programming. I am trying to implement a few functions on prime numbers as a way to learn. Here's my code, which you can run at http://ideone.com/qxLQ0D:
// prime numbers
package main
import (
"fmt"
)
// list of primes less than n:
// sieve of eratosthenes
func primes(n int) (ps []int) {
sieve := make([]bool, n)
for i := 2; i < n; i++ {
if !(sieve[i]) {
ps = append(ps, i)
for j := i * i; j < n; j += i {
sieve[j] = true
}
}
}
return ps
}
// true if n is prime, else false:
// trial division via 2,3,5-wheel
func isPrime(n int) (bool) {
wheel := [11]int{1,2,2,4,2,4,2,4,6,2,6}
w := 0
f := 2
for f*f <= n {
if n % f == 0 { return false }
f += wheel[w]
w += 1
if w == 11 { w = 3 }
}
return true
}
// greatest common divisor of x and y:
// via euclid's algorithm
func gcd(x int, y int) (int) {
for y != 0 {
x, y = y, x % y
}
return x
}
// absolute value of x
func abs(x int) (int) {
if x < 0 {
return -1 * x
}
return x
}
// list of prime factors of n:
// trial division via 2,3,5-wheel
// to 1000 followed by pollard rho
func factors(n int) (fs []int) {
wheel := [11]int{1,2,2,4,2,4,2,4,6,2,6}
w := 0 // wheel pointer
f := 2 // current trial factor
for f*f <= n && f < 1000 {
for n % f == 0 {
fs = append(fs, f)
n /= f
}
f += wheel[w]; w += 1
if w == 11 { w = 3 }
}
if n == 1 { return fs }
h := 1 // hare
t := 1 // turtle
g := 1 // greatest common divisor
c := 1 // random number parameter
for !(isPrime(n)) {
for g == 1 {
h = (h*h+c) % n // the hare runs
h = (h*h+c) % n // twice as fast
t = (t*t+c) % n // as the tortoise
g = gcd(abs(t-h), n)
}
if isPrime(g) {
for n % g == 0 {
fs = append(fs, g)
n /= g
}
}
h, t, g, c = 1, 1, 1, c+1
}
fs = append(fs, n)
return fs
}
func main() {
fmt.Println(primes(100))
fmt.Println(isPrime(997))
fmt.Println(isPrime(13290059))
fmt.Println(factors(13290059))
}
That works fine. I would like to know how to initialize wheel as a constant at compile time so that it can be shared by isPrime and factors, and I would appreciate any comments on style or other aspects of my program.
I eventually want to implement some factoring algorithms on big integers, using the math/big package. But I'm having much trouble. Simplifying to just the trial division via a 2,3,5-wheel part of the algorithm, here's my code:
package main
import (
"fmt"
"math/big"
)
func factors(n big.Int) (fs []big.Int) {
zero := big.NewInt(0);
one := big.NewInt(1);
two := big.NewInt(2);
four := big.NewInt(4);
six := big.NewInt(6);
wheel := [11]big.Int{*one,*two,*two,*four,*two,*four,*two,*four,*six,*two,*six}
w := 0;
f := two;
for big.Mul(*f, *f).Cmp(n) <= 0 {
for big.Mod(n, *f).Cmp(*zero) {
fs = append(fs, *f)
n = big.Div(n, *f)
}
f = big.Add(f, wheel[w])
w += 1
if w > 11 { w = 3 }
}
fs = append(fs, n)
return fs
}
func main() {
fmt.Println(factors(*big.NewInt(13290059)))
}
That doesn't work; ideone complains that the Add, Div, Mod and Mul functions are not found. And it looks rather ugly to me, stylistically.
Please tell me how to fix my factors function.
EDIT 1: Thanks to #TClaverie, I now have a function that compiles. Now I am getting a runtime error, and ideone points to the Mul function. Once again, can anyone help? My revised code is shown below and at http://ideone.com/aVBgJg:
package main
import (
"fmt"
"math/big"
)
func factors(n *big.Int) (fs []big.Int) {
var z *big.Int
zero := big.NewInt(0)
one := big.NewInt(1)
two := big.NewInt(2)
four := big.NewInt(4)
six := big.NewInt(6)
wheel := [11]*big.Int{one,two,two,four,two,four,two,four,six,two,six}
w := 0
f := two
z.Mul(f, f)
for z.Cmp(n) <= 0 {
z.Mod(n, f)
for z.Cmp(zero) == 0 {
fs = append(fs, *f)
n.Div(n, f)
z.Mod(n, f)
}
f.Add(f, wheel[w])
w += 1
if w > 11 { w = 3 }
z.Mul(f, f)
}
fs = append(fs, *n)
return fs
}
func main() {
fmt.Println(factors(big.NewInt(13290059)))
}
EDIT 2: Thanks to #TClaverie, I've learned a lot about Go, and I'm close to a solution. But I still have one problem; the program
package main
import (
"fmt"
"math/big"
)
func main() {
one := big.NewInt(1);
two := big.NewInt(2);
four := big.NewInt(4);
six := big.NewInt(6);
wheel := [11]*big.Int{one,two,two,four,two,four,two,four,six,two,six}
f := two; w := 0
for f.Cmp(big.NewInt(40)) < 0 {
fmt.Println(f, w, wheel)
f.Add(f, wheel[w])
w += 1; if w == 11 { w = 3 }
}
}
prints the following output, which shows that wheel is being modified in the call to Add:
2 0 [1 2 2 4 2 4 2 4 6 2 6]
3 1 [1 3 3 4 3 4 3 4 6 3 6]
6 2 [1 6 6 4 6 4 6 4 6 6 6]
12 3 [1 12 12 4 12 4 12 4 6 12 6]
16 4 [1 16 16 4 16 4 16 4 6 16 6]
32 5 [1 32 32 4 32 4 32 4 6 32 6]
36 6 [1 36 36 4 36 4 36 4 6 36 6]
What's the right way to prevent that from happening?

So, if you look at the documentation, you'll see that Add, Div and Mul are defined for the type *big.Int, so you have to call them using a *big.Int with the dot notation. Also, they expect arguments of type *big.Int, but you're giving them big.Int.
If you look at the documentation, you'll also see that those functions are of the type: z.Op(x, y). They apply x Op y and store the result into another *big.Int called z. So, you need a dummy *big.Int, that I'll call z (the methods return it at the same time).
Finally, it's better to work with pointers in this case, as all methods work with pointers.
func factors(n big.Int) (fs []big.Int) --> func factors(n *big.Int) (fs []big.Int)
wheel := [11]big.Int{*one,*two,*two,*four,*two,*four,*two,*four,*six,*two,*six} -->
wheel := [11]*big.Int{one,two,two,four,two,four,two,four,six,two,six}
big.Mul(*f, *f) --> z.Mul(f, f)
big.Mod(n, *f) --> z.Mod(n, f)
n = big.Div(n, *f) --> n.Div(n, f)
f = big.Add(f, wheel[w]) -−> f.Add(f, wheel[w])
A last thing: your condition is broken in the second for, because you are giving it an int instead of a boolean.
So, I do not guarantee the code works after those modifications, but you will be able to make it compile and debug it.

Related

Golang gives different result everytime using map for AOC 2021 Day 6 problem

I've been trying to solve Advent of Code 2021 and in day 6, I am trying this solution but the result is different everytime. What seems to be the problem? Is there any memory leakage with map?
The input file can be found here
The details of the problem can be read here
For part one it was straight-forward looping over arrays but as the number of days increases, the population grows exponentially and the time complexity grows in similar manner.
with go version go1.19.3
I have tried this:
package main
import (
"fmt"
"os"
"strconv"
"strings"
)
func getInput() []int {
var parsedData []int
rawData, _ := os.ReadFile("input.txt")
data := strings.Split(string(rawData), ",")
for _, strNum := range data {
num, _ := strconv.Atoi(strNum)
parsedData = append(parsedData, num)
}
return parsedData
}
func main() {
data := getInput()
var total int64
// create a map t0 hold the number of fish with the same timer
fishWithSameTimer := make(map[int]int64)
for _, timer := range data {
if _, ok := fishWithSameTimer[timer]; ok {
fishWithSameTimer[timer] += 1
} else {
fishWithSameTimer[timer] = 1
}
}
const days int = 18
currDay := 1
for currDay <= days {
tempFishTimerData := make(map[int]int64)
for timer, numOfFishes := range fishWithSameTimer {
if timer == 0 {
tempFishTimerData[8] = numOfFishes
tempFishTimerData[6] = numOfFishes
}else{
tempFishTimerData[timer - 1] += numOfFishes
}
}
fishWithSameTimer = tempFishTimerData
fmt.Println("Day:", currDay, fishWithSameTimer)
currDay++
}
fmt.Println(fishWithSameTimer)
for _, num := range fishWithSameTimer {
total += num
}
fmt.Println(total)
}
Can anyone help?
I hope this piece of code does the work, please add the input file reading part and print the output slice as comma separated string. You can also validate if the input has all numbers between 0 and 8.
package main
import "fmt"
func refreshTimer(x int) (int, bool) {
if x == 0 {
return 6, true
} else {
return x - 1, false
}
}
func spawnFish(i []int) []int {
var parentIntTimer []int
var childIntTimer []int
for _, d := range i {
y, c := refreshTimer(d)
parentIntTimer = append(parentIntTimer, y)
if c {
childIntTimer = append(childIntTimer, 8)
}
}
return append(parentIntTimer, childIntTimer...)
}
func main() {
initialFishes := []int{3, 4, 3, 1, 2}
var spFishes []int
noOfDays := 18
for i := 1; i <= noOfDays; i++ {
spFishes = spawnFish(initialFishes)
initialFishes = spFishes
}
fmt.Println(spFishes)
}
Output: [6 0 6 4 5 6 0 1 1 2 6 0 1 1 1 2 2 3 3 4 6 7 8 8 8 8]

What should I change in the code to generate a fibonacci sequence starting from 0 1 1

I've searched older questions, there are tons of them. However I couldn't find the answer to my case.
func fibonacci() func() int {
y := 0
z := 1
return func () int {
res := y + z
y = z
z = res
return res
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
This produces 1 2 3 5 8
What should I change (as little as possible) to get 0 1 1 2 3 5 8 ?
Actually I managed to solve that if initial y and z were like this:
y := -1
z := 1
But that's a fortunate hack, and I want a logical solution.
Change your function to return res to this:
return func () int {
res := y
y = z
z = res + z
return res
}
This way you output the initial values first, and calculate the next values. Your current solution overwrites the initial values before they are returned.
If you added:
x := y
and changed the return statement to
return x
you would be returning the initial y := 0 value, instead of the computed res := y + z, so returning the values 2 earlier in the sequence, giving you 0, 1, 1, 2, 3, 5, ...
(But I wouldn’t consider the -1, 1 initializer a hack.)
For example,
package main
import "fmt"
// fibonacci returns a function that returns
// successive Fibonacci numbers.
func fibonacci() func() int {
a, b := 0, 1
return func() (f int) {
if a < 0 {
panic("overflow")
}
f, a, b = a, b, a+b
return f
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
Playground: https://play.golang.org/p/uYHEK_ZgE6K
Output:
0
1
1
2
3
5
8
13
21
34

Writing Pascal's Triangle using big.Int int

I have some code for Pascal's Triangle using big.Int. How do I add the values? I get an error:
invalid operation:
PascalTriangle[r - 1][c - 1] + PascalTriangle[r - 1][c]
(operator + not defined on struct)
I am using a big.Int array so I cannot use Add from the big package.
func generatePascalTriangle(n int) [][]big.Int {
PascalTriangle := make([][]big.Int, n)
for i := range PascalTriangle {
PascalTriangle[i] = make([]big.Int, n)
}
var one big.Int
one.SetInt64(1)
for r := 0; r < n; r++ {
PascalTriangle[r][0] = one
PascalTriangle[r][r] = one
}
for r := 2; r < n; r++ {
for c := 1; c < r; c++ {
PascalTriangle[r][c] = PascalTriangle[r-1][c-1] + PascalTriangle[r-1][c]
}
}
return PascalTriangle
}
I am using big.Int array so cannot use "Add" from "big" package.
That claim is false. You can, and you should.
For example,
package main
import (
"fmt"
"math/big"
)
func generatePascalTriangle(n int) [][]big.Int {
PascalTriangle := make([][]big.Int, n)
for i := range PascalTriangle {
PascalTriangle[i] = make([]big.Int, n)
}
var one big.Int
one.SetInt64(1)
for r := 0; r < n; r++ {
PascalTriangle[r][0] = one
PascalTriangle[r][r] = one
}
for r := 2; r < n; r++ {
for c := 1; c < r; c++ {
// PascalTriangle[r][c] = PascalTriangle[r-1][c-1] + PascalTriangle[r-1][c]
PascalTriangle[r][c] = *PascalTriangle[r][c].Add(&PascalTriangle[r-1][c-1], &PascalTriangle[r-1][c])
}
}
return PascalTriangle
}
func main() {
t := generatePascalTriangle(7)
for i, r := range t {
for _, n := range r[:i+1] {
fmt.Print(n.String() + " ")
}
fmt.Println()
}
}
Playground: https://play.golang.org/p/KUGsjr8Mon5
Output:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1

How to return the sorted indices for Counting Sort?

I want to return the sorted indices for x array from the Counting Sort algorithm below, it must be simple but I can not figure out how to do that! Can someone please guide me on how to do that in Matlab or Golang or any idomatic c-style demonstration for the algorithm below? thanks a lot in advance.
x=[6 2 5 3 2 2 ];
MAX=10;
n = length(x);
C = zeros(MAX,1); // intialize counting array
for j = 1:n
C(x(j)) = C(x(j)) + 1;
end
z=1;
sorted_x = zeros(n,1); // empty array -container for sorted elements
for j = 1:n;
while ( C(j) >0)
sorted_x(z) = j;
z=z+1;
C(j) = C(j) - 1;
end
end
the code above returns the sorted_x=[2 2 2 3 5 6]
But I want to modify it to also return the sorted_indices=[2 5 6 4 3 1]
Thanks
You can use a map to store the indices -
package main
import "fmt"
func main(){
nums := [6]int{6, 2, 5, 3, 2, 2}
count := make(map[int][]int)
for i, v := range nums {
count[v] = append(count[v], i+1)
}
output := []int{}
for i := 0; i < 10; i++ {
output = append(output, count[i]...)
}
for i := 0; i < len(output); i++ {
fmt.Printf("%d ", nums[output[i]-1])
}
fmt.Println()
fmt.Println("The indices are:")
fmt.Println(output)
}
Output -
2 2 2 3 5 6
The indices are:
[2 5 6 4 3 1]
In matlab the second output value of sort function is the indices. Simply try this:
[sorted, s_ind] = sort(x);
For example, using the Go sort package,
package main
import (
"fmt"
"sort"
)
type AX struct{ A, X []int }
func (ax AX) Len() int {
return len(ax.A)
}
func (ax AX) Swap(i, j int) {
ax.A[i], ax.A[j] = ax.A[j], ax.A[i]
ax.X[i], ax.X[j] = ax.X[j], ax.X[i]
}
func (ax AX) Less(i, j int) bool {
return ax.A[i] < ax.A[j]
}
func sortAX(a []int) (x []int) {
x = make([]int, len(a))
for i := range x {
x[i] = i
}
sort.Stable(AX{A: a, X: x})
return x
}
func main() {
a := []int{6, 2, 5, 3, 2, 2}
fmt.Println("a:", a)
x := sortAX(a)
fmt.Println("a:", a)
fmt.Println("x:", x)
}
Output (Go indices start at 0):
a: [6 2 5 3 2 2]
a: [2 2 2 3 5 6]
x: [1 4 5 3 2 0]
References:
Go: Package sort

Returning the lenght of a vector idiomatically

I'm writing a function that returns a sequence of numbers of variable length:
func fib(n int) ??? {
retval := ???
a, b := 0, 1
for ; n > 0; n-- {
??? // append a onto retval here
c := a + b
a = b
b = c
}
}
It can be observed that the final length of the returned sequence will be n. How and what should fib return to achieve idiomatic Go? If the length was not known in advance, how would the return value, and usage differ? How do I insert values into retval?
Here, we know how many numbers; we want n Fibonacci numbers.
package main
import "fmt"
func fib(n int) (f []int) {
if n < 0 {
n = 0
}
f = make([]int, n)
a, b := 0, 1
for i := 0; i < len(f); i++ {
f[i] = a
a, b = b, a+b
}
return
}
func main() {
f := fib(7)
fmt.Println(len(f), f)
}
Output: 7 [0 1 1 2 3 5 8]
Here, we don't know how many numbers; we want all the Fibonacci numbers less than or equal to n.
package main
import "fmt"
func fibMax(n int) (f []int) {
a, b := 0, 1
for a <= n {
f = append(f, a)
a, b = b, a+b
}
return
}
func main() {
f := fibMax(42)
fmt.Println(len(f), f)
}
Output: 10 [0 1 1 2 3 5 8 13 21 34]
You could also use IntVector from the Go vector package. Note that type IntVector []int.
Don't use Vectors, use slices. Here are some mapping of various vector operations to idiomatic slice operations.

Resources