I have two variables with big numbers set as strings:
var numA = "340282366920938463463374607431768211456"
var numB = "17014118346046923173168730371588410572"
I want to be able to add and subtract these kinds of large string numbers in Go.
I know I need to use math/big but I still can not for the life of me figure out how, so any example help will be greatly appreciated!
You may use big.NewInt() to create a new big.Int value initialized with an int64 value. It returns you a pointer (*big.Int). Alternatively you could simply use the builtin new() function to allocate a big.Int value which will be 0 like this: new(big.Int), or since big.Int is a struct type, a simple composite literal would also do: &big.Int{}.
Once you have a value, you may use Int.SetString() to parse and set a number given as string. You can pass the base of the string number, and it also returns you a bool value indicating if parsing succeeded.
Then you may use Int.Add() and Int.Sub() to calculate the sum and difference of 2 big.Int numbers. Note that Add() and Sub() write the result into the receiver whose method you call, so if you need the numbers (operands) unchanged, use another big.Int value to calculate and store the result.
See this example:
numA := "340282366920938463463374607431768211456"
numB := "17014118346046923173168730371588410572"
ba, bb := big.NewInt(0), big.NewInt(0)
if _, ok := ba.SetString(numA, 10); !ok {
panic("invalid numA")
}
if _, ok := bb.SetString(numB, 10); !ok {
panic("invalid numB")
}
sum := big.NewInt(0).Add(ba, bb)
fmt.Println("a + b =", sum)
diff := big.NewInt(0).Sub(ba, bb)
fmt.Println("a - b =", diff)
Output (try it on the Go Playground):
a + b = 357296485266985386636543337803356622028
a - b = 323268248574891540290205877060179800884
I have simplified the problem incredibly to a small runnable example of my issue, shown below:
package main
import "fmt"
type A struct {
Name string
}
func main() {
main_list := []A{A{"1"}, A{"b"}, A{"3"}}
second_list := make([]*A, 0)
fmt.Println("FIRST LIST:")
for _, x := range main_list {
fmt.Println(x.Name)
second_list = append(second_list, &x)
}
fmt.Println("SECOND LIST:")
for _, x := range second_list {
fmt.Println((*x).Name)
}
}
Which provides:
FIRST LIST:
1
b
3
SECOND LIST:
3
3
3
The simple task is creating main_list with some dummy structs. The real issue is creating references (pointers) from the values in main_list into second_list. I absolutely do not want copies of the structs, only pointers/references to the main_list structs. The second for loop iterates through the newly populated second_list and shows only the last value from main_list (3 in this example) three times.
I expect the issue arrises with the way I am using &x in the first loop. With the way I get all three values of second_list to all be the same struct instance; I am going to assume that I actually made a pointer to the for-loop's iterator (as if it were a reference?). So all the pointers in second_list will always be the last item referenced in the first loop.
The question: How could I make a pointer from what x was pointing to at that moment in the for loop?
You're adding the address of the same x in every call to append.
You could initialize a new x and copy the value:
for _, x := range main_list {
x := x
second_list = append(second_list, &x)
}
Or create a new x directly indexing the slice:
for i := range main_list {
x := main_list[i]
second_list = append(second_list, &x)
}
Or if you want the address of the original value in the slice, you can use:
for i := range main_list {
second_list = append(second_list, &main_list[i])
}
I encountered weird behaviour in go code today: when I append elements to slice in loop and then try to create new slices based on the result of the loop, last append overrides slices from previous appends.
In this particular example it means that sliceFromLoop j,g and h slice's last element are not 100,101 and 102 respectively, but...always 102!
Second example - sliceFromLiteral behaves as expected.
package main
import "fmt"
func create(iterations int) []int {
a := make([]int, 0)
for i := 0; i < iterations; i++ {
a = append(a, i)
}
return a
}
func main() {
sliceFromLoop()
sliceFromLiteral()
}
func sliceFromLoop() {
fmt.Printf("** NOT working as expected: **\n\n")
i := create(11)
fmt.Println("initial slice: ", i)
j := append(i, 100)
g := append(i, 101)
h := append(i, 102)
fmt.Printf("i: %v\nj: %v\ng: %v\nh:%v\n", i, j, g, h)
}
func sliceFromLiteral() {
fmt.Printf("\n\n** working as expected: **\n")
i := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Println("initial slice: ", i)
j := append(i, 100)
g := append(i, 101)
h := append(i, 102)
fmt.Printf("i: %v\nj: %v\ng: %v\nh:%v\n", i, j, g, h)
}
link to play.golang:
https://play.golang.org/p/INADVS3Ats
After some reading, digging and experimenting I found that this problem is originated in slices referencing the same underlaying array values and can be solved by copying slice to new one before appending anything, however it looks quite... hesitantly.
What's the idomatic way for creating many new slices based on old ones and not worrying about changing values of old slices?
Don't assign append to anything other than itself.
As you mention in the question, the confusion is due to the fact that append both changes the underlying array and returns a new slice (since the length might be changed). You'd imagine that it copies that backing array, but it doesn't, it just allocates a new slice object that points at it. Since i never changes, all those appends keep changing the value of backingArray[12] to a different number.
Contrast this to appending to an array, which allocates a new literal array every time.
So yes, you need to copy the slice before you can work on it.
func makeFromSlice(sl []int) []int {
result := make([]int, len(sl))
copy(result, sl)
return result
}
func main() {
i := make([]int, 0)
for ii:=0; ii<11; ii++ {
i = append(i, ii)
}
j := append(makeFromSlice(i), 100) // works fine
}
The slice literal behavior is explained because a new array is allocated if the append would exceed the cap of the backing array. This has nothing to do with slice literals and everything to do with the internals of how exceeding the cap works.
a := []int{1,2,3,4,5,6,7}
fmt.Printf("len(a) %d, cap(a) %d\n", a, len(a), cap(a))
// len(a) 7, cap(a) 7
b := make([]int, 0)
for i:=1; i<8, i++ {
b = append(b, i)
} // b := []int{1,2,3,4,5,6,7}
// len(b) 7, cap(b) 8
b = append(b, 1) // any number, just so it hits cap
i := append(b, 100)
j := append(b, 101)
k := append(b, 102) // these work as expected now
If you need a copy of a slice, there's no other way to do it other than, copying the slice. You should almost never assign the result of append to a variable other than the first argument of append. It leads to hard to find bugs, and will behave differently depending on whether the slice has the required capacity or not.
This isn't a commonly needed pattern, but as with all things of this nature if you need to repeate a few lines of code multiple times, then you can use a small helper function:
func copyAndAppend(i []int, vals ...int) []int {
j := make([]int, len(i), len(i)+len(vals))
copy(j, i)
return append(j, vals...)
}
https://play.golang.org/p/J99_xEbaWo
There is also a little bit simpler way to implement copyAndAppend function:
func copyAndAppend(source []string, items ...string) []string {
l := len(source)
return append(source[:l:l], items...)
}
Here we just make sure that source has no available capacity and so copying is forced.
I was reading this doc and saw the following fragment:
The := syntax is shorthand for declaring and initializing a variable, e.g. for var f string = "short" in this case.
f := "short"
fmt.Println(f)
The point is: is it only for strings? Or is it dymanic enough to understand what datatype should it store?
And plus: isn't it the same of var f = "short"?
Of course it infers the obvious type(s) returned by the expression on the right side.
The specification gives those examples :
i, j := 0, 10
f := func() int { return 7 }
ch := make(chan int)
r, w := os.Pipe(fd) // os.Pipe() returns two values
_, y, _ := coord(p) // coord() returns three values; only interested in y coordinate
Note that it's not dynamic : everything happens at compile time, the type(s) being given by the right part expression.
I am trying to learn Go. I really don't understand why the compiler is saying that I am not using a variable. It seems to me that I am using the variable as an argument to Println.
My textbook states:
In this for loop i represents the current position in the array and
value is the same as x[i]
package main
import "fmt"
func main() {
x := [5]float64{ 1,2,3,4,5 }
i := 0
var total float64 = 0
for i, value := range x {
total += value
fmt.Println(i, value)
}
fmt.Println("Average:", total / float64(len(x)))
}
Output on OS X:
go run main.go
# command-line-arguments
./main.go:8: i declared and not used
Surely this fmt.Println(i, value) is using the variable i?
How to fix the compiler message?
Remove the outer i from your program:
package main
import "fmt"
func main() {
x := [5]float64{1, 2, 3, 4, 5}
var total float64 = 0
for i, value := range x {
total += value
fmt.Println(i, value)
}
fmt.Println("Average:", total/float64(len(x)))
}
Surely this fmt.Println(i, value) is using the variable i?
Yes, but the one you're defining inside the for loop. (note the :=), here:
for i, value := range x
^ ^
The outer variable i is never used.