big.Int slice rewriting itself on append() - go

I am trying to get a slice of big.Ints of the odd numbers between 3 and the square root of i.
When I run the following code:
import (
"fmt"
"math/big"
)
func main() {
i := big.NewInt(101)
var divisorsOfPrime []*big.Int
squareRoot := big.NewInt(0).Sqrt(i)
for n := big.NewInt(3); n.Cmp(squareRoot) == -1; n.Add(n, big.NewInt(2)) {
divisorsOfPrime = append(divisorsOfPrime, n)
}
fmt.Println(divisorsOfPrime)
}
I get the output:
[11 11 11 11]
But I expect the output:
[3 5 7 9 11]
What can I do to fix this?
Thanks

You have a slice of *big.Int in which you store the same pointer over and over again.
Instead, you need to store a copy of n on each iteration.
Replace:
divisorsOfPrime = append(divisorsOfPrime, n)
With:
nCopy := new(big.Int).Set(n)
divisorsOfPrime = append(divisorsOfPrime, nCopy)
By the way, this is not specific to *big.Int; as long as you're handling pointers you need to create new objects and store pointers to those new objects, not the original one. Notice that n is assigned exactly once.

Related

How does Go slice capacity change on append? [duplicate]

This question already has answers here:
How the slice is enlarged by append? Is the capacity always doubled?
(2 answers)
Closed 3 years ago.
Running the example The Go Tour on server (currently on version 1.12.7), I find the capacity of slice doubling to the next power of 2, if the new slice length is larger than current backing array's length.
If I run the same program on my machine (version 1.10.3 on windows), the slice capacity changes to next multiple of two.
Why are they different? Is it because of Go version or run-time implementations? Is the capacity change deterministic?
The output on remote server is this
len=0 cap=0 []
len=1 cap=2 [0]
len=2 cap=2 [0 1]
len=5 cap=8 [0 1 2 3 4]
The output on local machine is this
len=0 cap=0 []
len=1 cap=1 [0]
len=2 cap=2 [0 1]
len=5 cap=6 [0 1 2 3 4]
This is the code for reference
package main
import "fmt"
func main() {
var s []int
printSlice(s)
// append works on nil slices.
s = append(s, 0)
printSlice(s)
// The slice grows as needed.
s = append(s, 1)
printSlice(s)
// We can add more than one element at a time.
s = append(s, 2, 3, 4)
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
TL;DR: It depends on the size of the elements stored in the array
The implementation can be seen here:
https://github.com/golang/go/blob/master/src/runtime/slice.go
But as you can see looking into the history it can't be relied to stay the same over time.
That might also explain the difference you may note on different versions of Go.
Making some tests show how a 0-size struct will increment capacity by just 1 element, and int or string will duplicate on each growth, and a 3-byte struct "roughly" doubles on each growth.
You can execute code like this using different types to see these different cases in action:
arr := []struct{}{}
oldCap := 0
for i := 0; i < 100; i++ {
arr = append(arr, struct{}{})
if cap(arr) != oldCap {
oldCap = cap(arr)
fmt.Println("arr", cap(arr))
}
}
Playground showing the cases described above:
https://play.golang.org/p/OKtCFskbp2t
According to information from Go slice internal The implementation behaviour of append is as follows.
It is just a multiple of the (len(source slice) + len(new data)) * 2
func AppendByte(slice []byte, data ...byte) []byte {
m := len(slice)
n := m + len(data)
if n > cap(slice) { // if necessary, reallocate
// allocate double what's needed, for future growth.
newSlice := make([]byte, (n+1)*2)
copy(newSlice, slice)
slice = newSlice
}
slice = slice[0:n]
copy(slice[m:n], data)
return slice
}

Unknown bug in Golang code: insertion sort in 2nd pass?

I'm new to Go. I'm using go version go1.10.4 linux/amd64. My objective is to ask a single integer input from the user append it to an array and sort it. I'm using insertion sort for this. The program needs to exit on receiving 'X' as input from the user.
This is my code:
package main
import (
"fmt"
"strconv"
// "sort"
)
func insertionSort(arr []int) []int {
// Traverse through 1 to len(arr)
for i, _ := range arr[1:] {
key := arr[i]
j := i - 1
for {
if j >= 0 && key < arr[j] {
arr[j+1] = arr[j]
j = j - 1
} else {
break
}
}
arr[j+1] = key
}
return arr
}
func main() {
s := make([]int, 0, 3)
var x string
for {
fmt.Printf("Enter a number: ")
fmt.Scan(&x)
if x == "X" {
break
}
xInt, _ := strconv.Atoi(x)
fmt.Println(xInt)
s = append(s, xInt)
//sort.Ints(s)
s = insertionSort(s)
fmt.Printf("%v\n", s)
}
fmt.Printf("%v\n", s)
}
I'm getting the following output:
Enter a number: 5
[5]
Enter a number: 4
[5 4]
Enter a number: 3
[4 5 3]
Enter a number: 2
[3 4 5 2]
Enter a number: 1
[2 3 4 5 1]
Enter a number: X
[2 3 4 5 1]
Question:
Why is it getting sorted in 2nd pass? I mean it's first printing the appended array and then for next element, it's printing the sorted array of the previous element. Why? I'm sorting after appending so this should not be the case...
I took (and converted from Python code) insertion sort code from here
Your for loop is wrong. When you do, for i,_ := range arr[1:]{, i becomes 0, not 1. You want to start traversing the array from the second element with pos 1, but when you do arr[1:], your array changes, becomes a slice with one less element and your index still ends up being 0.
To fix it, check the c++ code in the page you posted and implement the for loop that operates on the length of the original array.
The range arr is similar to foreach in other languages and makes it hard to operate with indexes.
Note: I also checked the python code of the page. It also has a for loop for the python code. Long story short, use range arr[1:] with caution :)
The fix :
for i, _ := range arr[1:] => for i:=1;i<len(arr);i++
It is given with a spoiler tag because I don't want to steal your joy of fixing the error.

create two dimensional string array in golang

I need to create a 2 dimensional string array as shown below -
matrix = [['cat,'cat','cat'],['dog','dog']]
Code:-
package main
import (
"fmt"
)
func main() {
{ // using append
var matrix [][]string
matrix[0] = append(matrix[0],'cat')
fmt.Println(matrix)
}
}
Error:-
panic: runtime error: index out of range
goroutine 1 [running]:
main.main()
/tmp/sandbox863026592/main.go:11 +0x20
You have a slice of slices, and the outer slice is nil until it's initialized:
matrix := make([][]string, 1)
matrix[0] = append(matrix[0],'cat')
fmt.Println(matrix)
Or:
var matrix [][]string
matrix = append(matrix, []string{"cat"})
fmt.Println(matrix)
Or:
var matrix [][]string
var row []string
row = append(row, "cat")
matrix = append(matrix, row)
The problem with doing two-dimensional arrays with Go is that you have to initialise each part individually, e.g., if you have a [][]bool, you gotta allocate []([]bool) first, and then allocate the individual []bool afterwards; this is the same logic regardless of whether you're using make() or append() to perform the allocations.
In your example, the matrix[0] doesn't exist yet after a mere var matrix [][]string, hence you're getting the index out of range error.
For example, the code below would create another slice based on the size of an existing slice of a different type:
func solve(board [][]rune, …) {
x := len(board)
y := len(board[0])
visited := make([][]bool, x)
for i := range visited {
visited[i] = make([]bool, y)
}
…
If you simply want to initialise the slice based on a static array you have, you can do it directly like this, without even having to use append() or make():
package main
import (
"fmt"
)
func main() {
matrix := [][]string{{"cat", "cat", "cat"}, {"dog", "dog"}}
fmt.Println(matrix)
}
https://play.golang.org/p/iWgts-m7c4u

Flipping a slice with a for loop logic error

So I am trying to write a method that takes two slices, flips both of them and then gives them to each other.
Ex.
s1 = {1,2,3,4,5}
s2 = {6,7,8,9,10}
Should return:
s1 = {10,9,8,7,6}
s2 = {5,4,3,2,1}
Here is my code:
package main
import(
"fmt"
)
func main(){
f:= [5]int{1,2,3,4,5}
h:= [5]int{6,7,8,9,10}
var sliceF []int = f[0:5]
var sliceH []int = h[0:5]
fmt.Println(reverseReverse(sliceF,sliceH))
}
func reverseReverse(first []int, second []int) ([]int, []int){
//creating temp arrays to hold the traversed arrays before swapping.
var tempArr1 []int = first
var tempArr2 []int = second
//count is used for counting up the tempArrays in the correct order in the For loops
var count int= 0
//goes through the first array and sets the values starting from the end equal to the temp array
//which increases normally from left to right.
for i :=len(first)-1; i>=0;i--{
tempArr1[count] = first[i]
fmt.Println(i)
count++
}
count =0
//same as first for loop just on the second array
for i :=len(second)-1; i>=0;i--{
tempArr2[count] = second[i]
count++
}
//trying to replace the values of the param arrays to be equal to the temp arrays
first=tempArr2
second = tempArr1
//returning the arrays
return first,second
}
When run here is the output:
4
3
2
1
0
[10 9 8 9 10]
[5 4 3 4 5]
*Not I included a print statement in the for loop to check if the index is decreasing properly.
I understand there are better ways to do this but for proof of concept I want to use a for loop.
Any help appreciated. I am new to go and tend to have java habits so I assume somehow my problem is related to that.
This can be done much simpler by realizing there's no need to actually swap the individual elements. Instead, reverse each array and swap their order. Much simpler!
func reverseReverse( a, b []int ) ([]int, []int) {
return reverse(b), reverse(a)
}
func reverse( a []int ) []int {
end := len(a) - 1
// Allocate a new array slice of the same length to copy to.
ret := make( []int, len(a) )
// Copy each element of a into ret, reversed.
for i := range a {
ret[end-i] = a[i]
}
return ret
}
With that revelation, there's little need for the very specialized reverseReverse function. Swap the order yourself.
fmt.Println(reverse(sliceH), reverse(sliceF))
Note that if you just want to take a slice of an array, it's sufficient to write sliceH []int := h[:] without specifying the start and end. The start is assumed to be 0 and the end is the end. Also note there's no need to declare the type, := takes care of that for you.
Even better, you can declare and initialize them directly.
sliceF:= []int{1,2,3,4,5}
sliceH:= []int{6,7,8,9,10}
Short answer:
tempArr1[count] = first[i]
This line is logically identical to:
first[count] = first[i]
Detailed answer:
x := [5]int{} and x := []int{} are in fact two very different assignments. In the first case x is actually a static array. In the second case x is a slice which is in fact a data structure which has a length, capacity and a pointer to the underlying array. Therefore, var tempArr1 []int = first means copy the pointer to the underlying array of first into the tempArr1, so any modification to first[i] will be reflected in tempArr1 and vice versa
For example,
package main
import "fmt"
func reverse(s []int) []int {
for i := 0; i < len(s)/2; i++ {
s[i], s[len(s)-1-i] = s[len(s)-1-i], s[i]
}
return s
}
func main() {
s1, s2 := []int{1, 2, 3, 4, 5}, []int{6, 7, 8, 9, 10}
fmt.Println(s1, s2)
s1, s2 = reverse(s2), reverse(s1)
fmt.Println(s1, s2)
}
Output:
[1 2 3 4 5] [6 7 8 9 10]
[10 9 8 7 6] [5 4 3 2 1]

Slice index greater than length and less than capacity gives error

Following code gives a error at runtime.
package main
import fmt "fmt"
func main(){
type b []int
var k = make([]b, 5, 10)
fmt.Printf("%d\n",k[8])
fmt.Printf("%d", len(k))
}
Error is as follows.
panic: runtime error: index out of range
runtime.panic+0x9e /go/src/pkg/runtime/proc.c:1060
runtime.panic(0x453b00, 0x300203f0)
runtime.panicstring+0x94 /go/src/pkg/runtime/runtime.c:116
runtime.panicstring(0x4af6c6, 0xc)
runtime.panicindex+0x26 /go/src/pkg/runtime/runtime.c:73
runtime.panicindex()
main.main+0x8d C:/GOEXCE~1/basics/DATATY~1/slice.go:9
main.main()
runtime.mainstart+0xf 386/asm.s:93
runtime.mainstart()
runtime.goexit /go/src/pkg/runtime/proc.c:178
runtime.goexit()
----- goroutine created by -----
_rt0_386+0xbf 386/asm.s:80
While if k[0] or k[1] is printed, it runs fine. Can you please explain what exactly capacity means for slices.
You are simply indexing, so the index must be less than the length. The relevant section of the Go specification says that
A primary expression of the form
a[x]
...
For a of type A or *A where A is an array type, or for a of type S
where S is a slice type:
x must be an integer value and 0 <= x < len(a)
However, if you were "slicing" (e.g. a[6:9]), then it would work with indexes that are greater than the length but within the capacity.
Read the Go Programming Language Specification.
Length and capacity
The capacity of a slice is the number of elements for which there is
space allocated in the underlying array. At any time the following
relationship holds:
0 <= len(s) <= cap(s)
var slice = make([]b, 5, 10)
is equal to
var array [10]b
slice := array[:5]
The difference is that when you use var slice = make([]b, 5, 10), you can't access the array under slice. The slice := array[:5] means the first element of slice is array[0] and the length of slice is 5, which means slice[0] == array[0], slice[1] == array[1], ... slice[4] == array[4]. Because you can only access the index that is less than the length(which means 0 <= index < length). The length of slice is 5 and the length of array is 10, so you can access array[8](0<=8<10) but can't access slice[8](8>5).
Full sample:
package main
import fmt "fmt"
func main(){
type b []int
var array [10]b
slice := array[:5]
// []
fmt.Printf("%d\n",slice[1])
// []
fmt.Printf("%d\n",array[8])
// panic: runtime error: index out of range
fmt.Printf("%d\n",slice[8])
}
Reference
https://blog.golang.org/go-slices-usage-and-internals

Resources