Golang cannot convert []byte("1575455669.4") to float64 using math.Float64frombits - go

I have the following code:
x := []byte("1575455669.4")
bits := binary.LittleEndian.Uint64(x)
f := math.Float64frombits(bits)
On calling fmt.Println(f) I expect 1.5754556694e+09. But instead I end up with 1.451098468672448e-47
When I try the same conversion through strconv.ParseFloat(string(x), 64) I get the correct result. What am I doing wrong here?

This:
x := []byte("1575455669.4")
will give you the (UTF-8 encoded) bytes of the "1575455669.4" string. This has nothing to do with the memory representation of the floating point number 1575455669.4 which uses the IEEE 754 standard. But what you do next would assume just that:
bits := binary.LittleEndian.Uint64(x)
f := math.Float64frombits(bits)
You have a number given as its base-10 string representation, you have to use strconv.ParseFloat(string(x), 64) to parse it and have it as a float64.

Related

How to store a big float64 in a string without overflow?

func main() {
target := 20190201518310870.0
fmt.Println(int64(target))
z3 := big.NewInt(int64(target))
fmt.Println(z3)
}
The result is 20190201518310872
How do I convert it and not make overflow?
The problem is that even your input target number is not equal to the constant you assign to it.
The float64 type uses the double-precision floating-point format (IEEE 754) to store the number, which has finite bits to utilize (64 bits in total, but only 53 bits are used to store the significand). This means it can roughly store ~16 digits, but your input number has 17, so it will be rounded to the nearest representable float64.
If you print target, you will see the exact number that is "transfered" to big.Int:
target := 20190201518310870.0
fmt.Printf("%f\n", target)
Outputs (try it on the Go Playground):
20190201518310872.000000
Note that it works if the input constant "fits" into float64:
target := 20190201518310.0
fmt.Printf("%f\n", target)
fmt.Println(int64(target))
z3 := big.NewInt(int64(target))
fmt.Println(z3)
Outputs (try it on the Go Playground):
20190201518310.000000
20190201518310
20190201518310
If you need to work with big numbers exactly such as 20190201518310870.0, you have to use another type to store it in the first place, e.g. string, big.Int or big.Float, but not float64.
For example:
target := "20190201518310870"
fmt.Println(target)
z3, ok := big.NewInt(0).SetString(target, 10)
fmt.Println(z3, ok)
Output (try it on the Go Playground):
20190201518310870
20190201518310870 true

keep negative number in string negative when converted golang

I'm trying to extract LAT / LONG from a string, but my negative float for the longitude keeps changing to zero, so far I have:
loc1 := "33.333333"
loc2 := "-44.44444"
However when using the strvconv package my results:
nloc1, _ := strconv.ParseFloat(loc1, 64)
RESULT: 33.333333 (successful float64)
nloc2, _ := strconv.ParseFloat(loc2, 64)
RESULT: 0 (successful float64)
any ideas on how to stop that from going to zero? I need to keep it the same number just a negative float. Thanks in advance!
EDIT:: The issue was a leading space, once reformatted, it works as it should. Thanks all.
This usually happens when you have leading or trailing whitespaces.
Try this:
nloc2, _ := strconv.ParseFloat(strings.TrimSpace(loc2), 64)

Strange loss of precision multiplying big.Float

If you parse a string into a big.Float like f.SetString("0.001"), then multiply it, I'm seeing a loss of precision. If I use f.SetFloat64(0.001), I don't lose precision. Even doing a strconv.ParseFloat("0.001", 64), then calling f.SetFloat() works.
Full example of what I'm seeing here:
https://play.golang.org/p/_AyTHJJBUeL
Expanded from this question: https://stackoverflow.com/a/47546136/105562
The difference in output is due to imprecise representation of base 10 floating point numbers in float64 (IEEE-754 format) and the default precision and rounding of big.Float.
See this simple code to verify:
fmt.Printf("%.30f\n", 0.001)
f, ok := new(big.Float).SetString("0.001")
fmt.Println(f.Prec(), ok)
Output of the above (try it on the Go Playground):
0.001000000000000000020816681712
64 true
So what we see is that the float64 value 0.001 is not exactly 0.001, and the default precision of big.Float is 64.
If you increase the precision of the number you set via a string value, you will see the same output:
s := "0.001"
f := new(big.Float)
f.SetPrec(100)
f.SetString(s)
fmt.Println(s)
fmt.Println(BigFloatToBigInt(f))
Now output will also be the same (try it on the Go Playground):
0.001
1000000000000000

Proper way for casting uint16 to int16 in Go

Bitwise manipulation and Go newbie here :D I am reading some data from sensor with Go and I get it as 2 bytes - let's say 0xFFFE. It is easy too cast it to uint16 since in Go we can just do uint16(0xFFFE) but what I need is to convert it to integer, because the sensor returns in fact values in range from -32768 to 32767. Now I thought "Maybe Go will be this nice and if I do int16(0xFFFE) it will understand what I want?", but no. I ended up using following solution (I translated some python code from web):
x := 0xFFFE
if (x & (1 << 15)) != 0 {
x = x - (1<<16)
}
It seems to work, but A) I am not entirely sure why, and B) It looks a bit ugly to what I imagined should be a trivial solution for casting uint16 to int16. Could anyone give me a hand and clarify why this is only way to do this? Or is there any other possible way?
But what you want works, "Go is nice":
ui := uint16(0xFFFE)
fmt.Println(ui)
i := int16(ui)
fmt.Println(i)
Output (try it on the Go Playground):
65534
-2
int16(0xFFFE) doesn't work because 0xfffe is an untyped integer constant which cannot be represented by a value of type int16, that's why the the compiler complains. But you can certainly convert any uint16 non-constant value to int16.
See possible duplicates:
Golang: on-purpose int overflow
Does go compiler's evaluation differ for constant expression and other expression

How to parse long hexadecimal string into uint

I'm pulling in data that is in long hexadecimal string form which I need to convert into decimal notation, truncate 18 decimal places, and then serve up in JSON.
For example I may have the hex string:
"0x00000000000000000000000000000000000000000000d3c21bcecceda1000000"
At first I was attempting to use ParseUint(), however since the highest it supports is int64, my number ends up being way too big.
This example after conversion and truncation results in 10^6.
However there are instances where this number can be up to 10^12 (meaning pre truncation 10^30!).
What is the best strategy to attack this?
Use math/big for working with numbers larger than 64 bits.
From the Int.SetString example:
s := "d3c21bcecceda1000000"
i := new(big.Int)
i.SetString(s, 16)
fmt.Println(i)
https://play.golang.org/p/vf31ce93vA
The math/big types also support the encoding.TextMarshaler and fmt.Scanner interfaces.
For example
i := new(big.Int)
fmt.Sscan("0x000000d3c21bcecceda1000000", i)
Or
i := new(big.Int)
fmt.Sscanf("0x000000d3c21bcecceda1000000", "0x%x", i)

Resources