如何将十六进制转换为浮点数

huangapple go评论87阅读模式
英文:

How to convert hex to float

问题

我需要将以字符串形式表示的十六进制数(例如"0xC40C5253")转换为浮点数值(IEEE-754转换)。我尝试使用strconv.ParseFloat函数进行转换,但没有成功。我还尝试先将其转换为整数,然后再转换为浮点数,但结果是错误的。

以下是我最后一次尝试的代码:

package main

import (
  "fmt"
  "strconv"
)

func main() {
  x, err := strconv.ParseInt("C40C5253", 16, 64)
  f, err := strconv.ParseFloat(fmt.Sprintf("%d", x), 64)

  if err != nil {
    fmt.Printf("转换错误:%s\n", err)
  } else {
    fmt.Println(f)
  }
}

请问有其他方法可以实现这个转换吗?

英文:

I have to convert hex, represeneted as strings (e.g. "0xC40C5253") to float values (IEEE-754 conversion). I did not manage to do that using the strconv.ParseFloat function. Is there anything else I have to use?
I couldn't find it so far. I also tried converting it to an integer first and then to a float, but the results were wrong.

Code of my last try:

package main

import (
  "fmt"
  "strconv"
)

func main () {
  x, err := strconv.ParseInt("C40C5253", 16, 64) 
  f, err := strconv.ParseFloat(fmt.Sprintf("%d", x), 64) 
  
  if err != nil {
    fmt.Printf("Error in conversion: %s\n", err)
  } else {
    fmt.Println(f)
  }
}

答案1

得分: 10

首先需要说明输入的位长度。由于十六进制表示有4个字节(8个十六进制数字),很可能是float32(需要向提问者澄清)。

您可以使用strconv.ParseUint()将十六进制表示中的字节解析为uint32ParseUint()始终返回uint64,它在内存中使用8个字节,因此您需要将其转换为与float32一样使用4个字节的uint32

s := "C40C5253"
n, err := strconv.ParseUint(s, 16, 32)
if err != nil {
    panic(err)
}
n2 := uint32(n)

现在,您已经获得了字节,但它们存储在uint32类型的变量中,因此被解释为整数的字节。如果您想将它们解释为IEEE-754浮点数的字节,可以使用unsafe包来实现:

import (
    "fmt"
    "unsafe"
)

f := *(*float32)(unsafe.Pointer(&n2))
fmt.Println(f)

输出结果(在Go Playground上尝试):

-561.2863

注意:

正如JimB指出的,对于第二部分(将uint32转换为float32),math包中有一个内置函数math.Float32frombits()可以在底层执行此操作:

import "math"

f := math.Float32frombits(n2)
英文:

First it needs to be stated the bit-length of the input. Since the hex representation has 4 bytes (8 hex digits), it is most likely a float32 (needs clarification from the asker).

You can parse the bytes from the hex representation into an uint32 using strconv.ParseUint(). ParseUint() always returns uint64 which uses 8 bytes in memory so you have to convert it to uint32 which uses 4 bytes just like float32:

s := "C40C5253"
n, err := strconv.ParseUint(s, 16, 32)
if err != nil {
	panic(err)
}
n2 = uint32(n)

Now you have the bytes but they are stored in a variable of type uint32 and therefore interpreted as the bytes of an integer. And you want to interpret them as the bytes of a IEEE-754 floating point number, you can use the unsafe package to do that:

f := *(*float32)(unsafe.Pointer(&n2))
fmt.Println(f)

Output (try it on the Go Playground):

-561.2863

Note:

As JimB noted, for the 2nd part (translating uint32 to float32) the math package has a built-in function math.Float32frombits() which does exactly this under the hood:

f := math.Float32frombits(n2)

答案2

得分: 6

这里有两种不同的方法可以得到-561.2863:http://play.golang.org/p/Y60XB820Ib

import (
    "bytes"
    "encoding/binary"
    "encoding/hex"
    "math"
    "strconv"
)

func parse_read(s string) (f float32, err error) {
    b, err := hex.DecodeString(s)

    if err != nil {
        return
    }

    buf := bytes.NewReader(b)

    err = binary.Read(buf, binary.BigEndian, &f)

    return
}

func parse_math(s string) (f float32, err error) {
    i, err := strconv.ParseUint(s, 16, 32)

    if err != nil {
        return
    }

    f = math.Float32frombits(uint32(i))

    return
}
英文:

Here are two different approaches that produce -561.2863: http://play.golang.org/p/Y60XB820Ib

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"math"
	"strconv"
)

func parse_read(s string) (f float32, err error) {
	b, err := hex.DecodeString(s)

	if err != nil {
		return
	}

	buf := bytes.NewReader(b)

	err = binary.Read(buf, binary.BigEndian, &f)

	return
}

func parse_math(s string) (f float32, err error) {
	i, err := strconv.ParseUint(s, 16, 32)

	if err != nil {
		return
	}

	f = math.Float32frombits(uint32(i))

	return
}

答案3

得分: 1

输入是32位的,因此必须将其视为32位数字。它还是无符号的,因此应该解析为uint而不是int。最后,没有必要使用不安全的操作,实际上,在这里使用它们将在具有不同字节顺序的机器上失败。

相反,使用math.Float32frombits,它正好可以满足你的需求:

package main

import (
	"fmt"
	"math"
	"strconv"
)

func main() {
	s := "C40C5253"
	n, err := strconv.ParseUint(s, 16, 32)
	if err != nil {
		panic(err)
	}

	nn := uint32(n)

	g := math.Float32frombits(nn)
	fmt.Println(g)
}

输出:

-561.2863

http://play.golang.org/p/y1ZjH9pscy

英文:

The input is 32 bits, so must be treated as a 32-bit number. It is also unsigned, so should be parsed as a uint, not int. Finally, there is no need to use unsafe operations, and in fact as used here they will fail on a machine with a different byte order.

Instead, use math.Float32frombits, which does exactly what you want:

package main

import (
	"fmt"
	"math"
	"strconv"
)

func main() {
	s := "C40C5253"
	n, err := strconv.ParseUint(s, 16, 32)
	if err != nil {
		panic(err)
	}

	nn := uint32(n)

	g := math.Float32frombits(nn)
	fmt.Println(g)
}

Output:

-561.2863

http://play.golang.org/p/y1ZjH9pscy

huangapple
  • 本文由 发表于 2015年5月28日 23:20:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/30510711.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定