How to convert scientific notation string to a big.Int? - go

In golang I have a large number in a string like this: "4.49955000449955e+24".
How can I convert this to a big.Int?

use big.ParseFloat to get a big.Float and then the Int method to convert it to a big.Int:
flt, _, err := big.ParseFloat(input, 10, 0, big.ToNearestEven)
if err != nil {
/* handle a parsing error here */
}
var i = new(big.Int)
i, acc := flt.Int(i)
see it on the Go Playground.
By adjusting the prec argument to ParseFloat you can control the precision of the intermediate float — it takes at least 72 bits of precision for your example input to come out exactly (to a value ending in ten zeroes) but the default if you pass 0 is 64 bits.

Related

how to force to save all decimal points of bigFloat in file, instead of rounding

Let's assume I have a very accurate input number(string format), and after math/big manipulation, I want to convert to string format again.
package main
import (
"fmt"
"math/big"
"os"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
// edit
s := "3.1415926123456789123456789123456789123456789"
var n, _ = new(big.Float).SetString(s)
// var n = big.NewFloat(3.1415926123456789123456789123456789123456789)
fmt.Println(n) // 3.1415926123456788
N := n.String()
fmt.Println(N) // 3.141592612
d1 := []byte(N)
err := os.WriteFile("./dat1.txt", d1, 0644) // 3.141592612
check(err)
}
How to save a big Float like 3.1415926123456789123456789123456789123456789 into a file? I want to keep all the decimal points, or at least as much as possible
You can parse and store your input "precisely", but you must increase the precision (the default precision doesn't cover that). Use Float.SetPrec() for that (requires a bit-count).
When generating text representation, use Float.Text(), again, with sufficiently large precision (requires a decimal digit-count). If you don't know the required digit-precision, as per the doc, you may use a negative value to have the smallest number of decimal digits that is needed for the Float's mantissa bits.
For example:
s := "3.1415926123456789123456789123456789123456789"
fmt.Println(s)
n := big.NewFloat(0)
n.SetPrec(200)
n.SetString(s)
N := n.Text('f', 50)
fmt.Println(N)
N = n.Text('f', -1)
fmt.Println(N)
This will output (try it on the Go Playground):
3.1415926123456789123456789123456789123456789
3.14159261234567891234567891234567891234567890000000
3.1415926123456789123456789123456789123456789
I've just looked what String method does and its documentation (https://pkg.go.dev/math/big#Float.String).
String formats x like x.Text('g', 10)...
So let's go to that method doc.
func (x *Float) Text(format byte, prec int) string
Text converts the floating-point number x to a string according to the given format and precision prec.
The precision prec controls the number of digits ... A negative precision selects the smallest number of decimal digits necessary to identify the value x uniquely
All you need is just reading the doc.

Golang string to uint

In my project, ID is designed as snowflakeid. The front end passes a string to me, and the database storage is bigint. This means that before I store it, it needs to be converted to uint. Please tell me what to do?
demo data :
m := "156343853366906880"
my code:
u, _ := strconv.ParseUint(m, 0, 19)
The expected results are accurate and will not lose accuracy
Third parameter of strconv.parseUint() is bitSize. 19 bits are not sufficient to represents the number 156343853366906880. So the method returns an error. (which you are ignoring by assigning it to _)
m := "156343853366906880"
_, err := strconv.ParseUint(m, 0, 19)
fmt.Println(err)
//strconv.ParseUint: parsing "156343853366906880": value out of range 524287
2^19 - 1 = 524287 is the biggest unsigned number that can be represented with 19 bits.
Pass 64 as bitSize :
m := "156343853366906880"
u, err := strconv.ParseUint(m, 0, 64)
if err == nil {
fmt.Print(u)
//156343853366906880
}
If your number is going to greater than uint64 use big.Int :
string to big Int in Go?
SnowflakeID is a time based 64-bit unique id. Since you need to convert string to a 64-bit number, strconv.ParseUint() is quite good. See, the reference at ParseUint.
In your code, you used 19 as bit size. Do not mix it with the number of digit(s) in the integer (unsigned) represented by the string from frontend.
For convert a 64-bit SnowflakeID (string) into a 64-bit unsigned integer, use 64 as bitSize arg.
U, err := strvonv.ParseUint(s, 0, 64)
if err != nil {
// handle error...
}
Also do not try to ignore error, when it really matters.

How to bit shift hex value using Golang?

Let's say I have a string with the value of 4ADDF6C259EBAFF8.
Using this I want to get a timestamp, using the formula (hex(val) >> 25) + 1008000400.
Using t he encoding/hex package, I have come up with the following:
srcBytes := []byte(src)
dst := make([]byte, hex.EncodedLen(len(srcBytes)))
hex.Encode(dst, srcBytes)
After this, I need a way to bit shift dst 25 times, and then add a constant to it.
However dst is of type []byte.
I need it to be of type hex so I can bit shift after. How do I convert []byte so that it can be shifted?
Assuming your input string varies but has a maximum of 16 hex digits, you just convert to a 64 bit (unsigned) integer and do the math. I also prefixed your constant with 0x assuming it is hex (judging by the digits).
s := "4ADDF6C259EBAFF8"
if i, err := strconv.ParseUint(s, 16, 64); err == nil {
fmt.Printf("%x\n", i >> 25 + 0x1008000400)
}
BTW hex is not a type but a way of displaying integers.

Working with bitstrings and big.Int in Go

I'm new to Go and I'm working on a few exercises to get up to speed. How can I convert a string representing a sequence of bits to the appropriate datatype in Go?
For eg, I see that if its a bitstring representing a 64-bit number, I can do :-
val, err := strconv.ParseInt(bitstring, 2, 64)
However, if the bitstring represents a larger number(say 1024 or 2048 bits), how can I go about converting that number to the appropriate type in Go? I believe the type for managing big integers in Go is big.Int.
Yes, you may use the big.Int type, and its Int.SetString() method, passing 2 as the base.
Example:
i := big.NewInt(0)
if _, ok := i.SetString("10101010101010101010101010101010101010101010101010101010101010101010101010", 2); !ok {
fmt.Println("Invalid number!")
} else {
fmt.Println(i)
}
Output (try it on the Go playground):
12592977287652387236522

Clearing the most significant bit

I have a file containing two bytes, in Big Endian order, hexdump gives me:
81 50
which is 1000 0001 0101 0000 in binary. However, I want the most significant bit to be a flag, so in golang I have to load the file content, clear the most significant bit, and only then read the value.
So:
valueBuf := make([]byte, 2)
_, err := f.Read(valueBuf) // now printing valueBuf gives me [129 80] in decimal
value := int16(binary.BigEndian.Uint16(valueBuf[0:2])) // now value is -32432
Ok, I have tried to use something like:
func clearBit(n int16, pos uint) int16 {
mask := ^(1 << pos)
n &= mask
return n
}
But it apparently doesn't work as expected. The output value should be 336 in decimal, as normal int, and I cannot get it. How should I do this?
for n &= mask to work, n and mask have to be matching types. So you should write
mask := int16(^(1 << pos))
then, value = clearBit(value, 15) works fine.
Or, since constants are untyped, you can eliminate mask, and also eliminate the assignment to n since it's just returned on the following line, and shorten clearBit to
func clearBit(n int16, pos uint) int16 {
return n & ^(1 << pos)
}

Resources