Convert byte slice "[]uint8" to float64 in GoLang
Asked Answered
B

5

36

I'm trying to convert a []uint8 byte slice into a float64 in GoLang. I can't find a solution for this issue online. I've seen suggestions of converting to a string first and then to a float64 but this doesn't seem to work, it loses it's value and I end up with zeroes.

Example:

metric.Value, _ = strconv.ParseFloat(string(column.Value), 64)

And it doesn't work...

Bibliopole answered 18/3, 2014 at 21:57 Comment(4)
What does the byte array contain ?Allotrope
Post an example of the dataGalvano
If you're unexpectedly getting a zero value and ignoring the returned error, perhaps it is worth checking that error?Commutative
FWIW I had the same issue (ended up with 0s after conversion) and my problem was I had a space/line terminator character in my []byte (was not visible when dumping %s to stdout) so I fixed it with strconv.ParseFloat(strings.TrimSpace(string(b)), 64)Hamford
D
69

For example,

package main

import (
    "encoding/binary"
    "fmt"
    "math"
)

func Float64frombytes(bytes []byte) float64 {
    bits := binary.LittleEndian.Uint64(bytes)
    float := math.Float64frombits(bits)
    return float
}

func Float64bytes(float float64) []byte {
    bits := math.Float64bits(float)
    bytes := make([]byte, 8)
    binary.LittleEndian.PutUint64(bytes, bits)
    return bytes
}

func main() {
    bytes := Float64bytes(math.Pi)
    fmt.Println(bytes)
    float := Float64frombytes(bytes)
    fmt.Println(float)
}

Output:

[24 45 68 84 251 33 9 64]
3.141592653589793
Delegate answered 18/3, 2014 at 22:37 Comment(3)
Odd that you defaulted to little endian. Network byte order is on the internet more and... ma asked sense.Jerrybuilt
This was it except we're using BigEndian. Thanks sir!Bibliopole
Little endian is nearly universal these days. Even modern network protocols use it (which makes sense - virtually all processors are little endian so you'd just be swapping bytes at both ends pointlessly).Picardi
K
7

I think this example from Go documentation is what you are looking for: http://golang.org/pkg/encoding/binary/#example_Read

var pi float64
b := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40}
buf := bytes.NewReader(b)
err := binary.Read(buf, binary.LittleEndian, &pi)
if err != nil {
  fmt.Println("binary.Read failed:", err)
}
fmt.Print(pi)

Prints 3.141592653589793

Kattiekatuscha answered 18/3, 2014 at 22:25 Comment(2)
This pretty much does exactly what the accepted answer does under the hood when inspecting the source code for binary.Read FYITertias
Yep, and I guess that’s why it’s an accepted answer and has more upvotes, despite being submitted later that this one ;)Kattiekatuscha
G
6

As the comments read, it all depends on what kind of data you have in your []uint8 slice.

If it is bytes representing an IEEE 754 floating-point value in Little Endian order, then use Kluyg's or peterSo's (better performance without use of reflection) answer.

If it is a textual representation in Latin-1/UTF-8 encoding, then you should be able to do what you just did:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    var f float64
    text := []uint8("1.23") // A decimal value represented as Latin-1 text

    f, err := strconv.ParseFloat(string(text), 64)
    if err != nil {
        panic(err)
    }

    fmt.Println(f)
}

Result:

1.23

Playground: http://play.golang.org/p/-7iKRDG_ZM

Gareri answered 18/3, 2014 at 22:35 Comment(0)
S
2

I hope this hack helps. The purpose of it is to convert the long stream of binary numbers to float.

For example: 0110111100010010100000111100000011001010001000010000100111000000 -> -3.1415

func binFloat(bin string) float64 {

    var s1 []byte
    var result float64

    if len(bin) % 8 == 0 {

            for i := 0; i < len(bin) / 8; i++ {

                    //Chop the strings into a segment with a length of 8.
                    //Convert the string to Integer and to byte

                    num, _ := strconv.ParseInt(bin[8*i: 8*(i + 1)], 2, 64) 
                    //Store the byte into a slice s1
                    s1 = append(s1, byte(num)) 
            }

    }

    //convert the byte slice to a float64. 
    //The algorithm below are copied from golang binary examples. 

    buf := bytes.NewReader(s1)

    //You can also change binary.LittleEndian to binary.BigEndian
    //For the details of Endianness, please google Endianness

    err := binary.Read(buf, binary.LittleEndian, &result) 

    if err != nil {

            panic(err)
            fmt.Println("Length of the binary is not in the length of 8")
    }

    return result
}
Sports answered 26/7, 2016 at 10:21 Comment(2)
Please be more clear when posting code, posting a code and an example isn't enough sometimes, please edit your answer with more explanation.Rawhide
I will amend it accordingly. This is my first post on StackOverflow. Sorry for not complying with the regulations in StackOverflow.Sports
J
0

The so far accepted answer does only work for longer arrays with 8 bytes bot for short arrays.

This covers also small numbers:

bits := big.NewInt(0).SetBytes(raw).Uint64()
float := math.Float64frombits(bits)
Joycejoycelin answered 5/2 at 2:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.