Golang, math/big: what is the max value of *big.Int - go

What is the max value of *big.Int and max precision of *big.Rat?

Here are the structure definitions :
// A Word represents a single digit of a multi-precision unsigned integer.
type Word uintptr
type nat []Word
type Int struct {
neg bool // sign
abs nat // absolute value of the integer
}
type Rat struct {
// To make zero values for Rat work w/o initialization,
// a zero value of b (len(b) == 0) acts like b == 1.
// a.neg determines the sign of the Rat, b.neg is ignored.
a, b Int
}
There is no explicit limit. The limit will be your memory or, theoretically, the max array size (2^31 or 2^63, depending on your platform).
If you have practical concerns, you might be interested by the tests made in http://golang.org/src/pkg/math/big/nat_test.go, for example the one where 10^100000 is benchmarked.
And you can easily run this kind of program :
package main
import (
"fmt"
"math/big"
)
func main() {
verybig := big.NewInt(1)
ten := big.NewInt(10)
for i:=0; i<100000; i++ {
verybig.Mul(verybig, ten)
}
fmt.Println(verybig)
}
(if you want it to run fast enough for Go Playground, use a smaller exponent than 100000)
The problem won't be the max size but the used memory and the time such computations take.

Related

How to convert an sha3 hash to an big integer in golang

I generated a hash value using sha3 and I need to convert it to a big.Int value. Is it possible ? or is there a method to get the integervalue of the hash ?
the following code throws an error that cannot convert type hash.Hash to type int64 :
package main
import (
"math/big"
"golang.org/x/crypto/sha3"
"fmt"
)
func main(){
chall := "hello word"
b := byte[](chall)
h := sha3.New244()
h.Write(chall)
h.Write(b)
d := make([]byte, 16)
h.Sum(d)
val := big.NewInt(int64(h))
fmt.Println(val)
}
TL;DR;
sha3.New224() cannot be represented in uint64 type.
There are many hash types - and of differing sizes. Go standard library picks a very generic interface to cover all type of hashes: https://golang.org/pkg/hash/#Hash
type Hash interface {
io.Writer
Sum(b []byte) []byte
Reset()
Size() int
BlockSize() int
}
Having said that some Go hash implementations optionally include extra methods like hash.Hash64:
type Hash64 interface {
Hash
Sum64() uint64
}
others may implement encoding.BinaryMarshaler:
type BinaryMarshaler interface {
MarshalBinary() (data []byte, err error)
}
which one can use to preserve a hash state.
sha3.New224() does not implement the above 2 interfaces, but crc64 hash does.
To do a runtime check:
h64, ok := h.(hash.Hash64)
if ok {
fmt.Printf("64-bit: %d\n", h64.Sum64())
}
Working example: https://play.golang.org/p/uLUfw0gMZka
(See Peter's comment for the simpler version of this.)
Interpreting a series of bytes as a big.Int is the same as interpreting a series of decimal digits as an arbitrarily large number. For example, to convert the digits 1234 into a "number", you'd do this:
Start with 0
Multiply by 10 = 0
Add 1 = 1
Multiply by 10 = 10
Add 2 = 12
Multiply by 10 = 120
Add 3 = 123
Multiply by 10 = 1230
Add 4 = 1234
The same applies to bytes. The "digits" are just base-256 rather than base-10:
val := big.NewInt(0)
for i := 0; i < h.Size(); i++ {
val.Lsh(val, 8)
val.Add(val, big.NewInt(int64(d[i])))
}
(Lsh is a left-shift. Left shifting by 8 bits is the same as multiplying by 256.)
Playground

Printing type of the numeric constant causes overflow

I am new to Go and currently following A Tour of Go.
I am currently at page Numeric Constants. Down below is a trimmed down version of the code that runs on that page:
package main
import "fmt"
const Big = 1 << 100
func needFloat(x float64) float64 {
return x * 0.1
}
func main() {
fmt.Println(needFloat(Big))
// fmt.Printf("Type of Big %T", Big)
}
this code compiles successfully with the output 1.2676506002282295e+29
The following code however will not compile and give an error:
package main
import "fmt"
const Big = 1 << 100
func needFloat(x float64) float64 {
return x * 0.1
}
func main() {
fmt.Println(needFloat(Big))
fmt.Printf("Type of Big %T", Big)
}
Output:
./prog.go:9:13: constant 1267650600228229401496703205376 overflows int
Why do you think this happened? I hope you will kindly explain.
The constant Big is an untyped constant. An untyped constant can be arbitrarily large and it doesn't have to fit into any predefined type's limits. It is interpreted and truncated in the context it is used.
The function needFloat gets a float64 argument. At this instance Big is converted to a float64 and used that way.
When you use it for Printf, it tries to pass it in as an int because it is not a decimal number (otherwise it would've converted it to float64), and it causes an overflow. Pass it as float64(Big), and it should work.
I guess the reason is that Big gets computed (i.e. casted right before being passed to needFloat, and gets instead computed as a int64 before the Printf. As a proof, the following statement computes correctly:
package main
import "fmt"
const Big = 1 << 100
func main() {
fmt.Printf("Type of Big %T", float64(Big))
}
Hope this helps.
The untyped constant n must be converted to a type before it can be assigned to the interface{} parameter in the call to fmt.Println.
fmt.Println(a ...interface{})
When the type can’t be inferred from the context, an untyped constant is converted to a bool, int, float64, complex128, string or rune depending of the format of the constant.
In this case the constant is an integer, but n is larger than the maximum value of an int.
However, n can be represented as a float64.
const n = 9876543210 * 9876543210
fmt.Println(float64(n))
For exact representation of big numbers, the math/big package implements arbitrary-precision arithmetic. It supports signed integers, rational numbers and floating-point numbers.
This is taken from https://yourbasic.org/golang/gotcha-constant-overflows-int/.

Freeing map of struct

I am working with a very large map of pointer to struct. It is growing over the lifetime of the program (I use it as a buffer) and I wrote a function that is supposed to reduce it size when it is called.
type S struct {
a uint32
b []uint32
}
s := make(map[uint32]*S)
for k, v := range s {
delete(s, k)
s[k] = &S{a: v.a}
}
I remove b from every element of the map, so I expected the size of the map in memory to shrink (b is a slice of length > 10). However the memory is not freed, why?
The size of the map value &S, a pointer, is the same irrespective of the capacity of slice b.
package main
import (
"fmt"
"unsafe"
)
type S struct {
a uint32
b []uint32
}
func main() {
size := unsafe.Sizeof(&S{})
fmt.Println(size)
size = unsafe.Sizeof(&S{b: make([]uint32, 10)})
fmt.Println(size)
s := make(map[uint32]*S)
for k, v := range s {
delete(s, k)
s[k] = &S{a: v.a}
}
}
Output:
8
8
A slice is represented internally by
type slice struct {
array unsafe.Pointer
len int
cap int
}
When you set &S{a: v.a} you set b to initial values: array to nil and len and cap to zero. The memory formerly occupied by the underlying array is returned to the garbage collector for reuse.
The map size is bounded to the maximum size it had at any point. Because you store pointers (map[uint32]*S) and not values the deleted objects will get garbage collected eventually but usually not immediately and that why you don’t see it in top/htop like monitors.
The runtime is clever enough and reserves memory for future use if the system is not under pressure or low on resources.
See https://stackoverflow.com/a/49963553/1199408 to understand more about memory.
In your example you don't need to call delete. You will achieve what you want just by clearing the slice in the struct.
type S struct {
a uint32
b []uint32
}
s := make(map[uint32]*S)
for k, v := range s {
v.b = []uint32{}
}

Golang overflows int64

I try to use this code, but gives me an error: constant 100000000000000000000000 overflows int64
How can I fix that ?
// Initialise big numbers with small numbers
count, one := big.NewInt(100000000000000000000000), big.NewInt(1)
for example so:
count,one := new(big.Int), big.NewInt(1)
count.SetString("100000000000000000000000",10)
link:
http://play.golang.org/p/eEXooVOs9Z
It won't work because under the hood, big.NewInt is actually allocating an int64. The number that you want to allocate into a big.NewInt would need more than 64bits to exist, so it failed.
However, with how big works, if you wanted to add two large numbers below MaxInt64, you can do that! Even if the sum is greater than MaxInt64. Here is an example I just wrote up (http://play.golang.org/p/Jv52bMLP_B):
func main() {
count := big.NewInt(0);
count.Add( count, big.NewInt( 5000000000000000000 ) );
count.Add( count, big.NewInt( 5000000000000000000 ) );
//9223372036854775807 is the max value represented by int64: 2^63 - 1
fmt.Printf( "count: %v\nmax int64: 9223372036854775807\n", count );
}
Which results in:
count: 10000000000000000000
max int64: 9223372036854775807
Now, if you're still curious about how NewInt works under the hood, here is the function you're using, taken from Go's documentation,:
// NewInt allocates and returns a new Int set to x.
func NewInt(x int64) *Int {
return new(Int).SetInt64(x)
}
Sources:
https://golang.org/pkg/math/big/#NewInt
https://golang.org/src/math/big/int.go?s=1058:1083#L51

Golang Fibonacci calculation appears off

I currently have the following codes for my fibonacci calculations. I'm trying to calculate large numbers, but it appears once it gets to 100, the calculations are off. For fib(100), my code returns 3736710778780434371, but when I look at other sources, it tells me the correct calculation should be 354224848179261915075. Is there a problem in my code or does it have to do with my computer hardware or something else?
package main
import "fmt"
func fib(N uint) uint{
var table []uint
table = make([]uint, N+1)
table[0] = 0
table[1] = 1
for i := uint(2); i <= N; i += 1 {
table[i] = table[i-1] + table[i-2]
}
return table[N]
}
func main() {
fmt.Println(fib(100))
}
You're hitting an integer overflow! You can only calculate using a uint up to the size of a uint; once you go beyond its bounds, it will (silently) wrap back round again.
In your case, it looks as though a uint is 64 bits long. (Its size depends on the platform you're running on.) That means that you will be able to store values up to 264-1. If you then add one more, it'll wrap back to 0, and won't return an error.
If you convert the answer you're getting, and the right answer, into hex, then you'll see that this is the case. You're ending up with
33DB76A7C594BFC3
whereas the right answer is
1333DB76A7C594BFC3
Note that your answer is correct as far as it goes... it just doesn't go far enough. You've only got the lower 64 bits of the answer; you're missing the other 13*264.
To correct it, you'll need to use an arbitrary size integer from Package big, instead of a uint.
Here is a version using big.Int which produces the correct answer (playground)
package main
import (
"fmt"
"math/big"
)
func fib(N uint) *big.Int {
var table []*big.Int
table = make([]*big.Int, N+1)
table[0] = new(big.Int).SetInt64(0)
table[1] = new(big.Int).SetInt64(1)
for i := uint(2); i <= N; i += 1 {
table[i] = new(big.Int).Add(table[i-1], table[i-2])
}
return table[N]
}
func main() {
fmt.Println(fib(100))
}
Which produces
354224848179261915075

Resources