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...

4
  • 1
    What does the byte array contain ? Commented Mar 18, 2014 at 22:00
  • 1
    Post an example of the data Commented Mar 18, 2014 at 22:31
  • 4
    If you're unexpectedly getting a zero value and ignoring the returned error, perhaps it is worth checking that error? Commented Mar 19, 2014 at 0:02
  • 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) Commented Apr 21, 2021 at 14:39

5 Answers 5

70

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
Sign up to request clarification or add additional context in comments.

3 Comments

Odd that you defaulted to little endian. Network byte order is on the internet more and... ma asked sense.
This was it except we're using BigEndian. Thanks sir!
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).
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

2 Comments

This pretty much does exactly what the accepted answer does under the hood when inspecting the source code for binary.Read FYI
Yep, and I guess that’s why it’s an accepted answer and has more upvotes, despite being submitted later that this one ;)
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

Comments

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
}

2 Comments

Please be more clear when posting code, posting a code and an example isn't enough sometimes, please edit your answer with more explanation.
I will amend it accordingly. This is my first post on StackOverflow. Sorry for not complying with the regulations in StackOverflow.
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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.