【问题标题】:How to convert hex to float如何将十六进制转换为浮点数
【发布时间】:2015-08-11 04:57:14
【问题描述】:

我必须将hex,表示为strings(例如"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("Error in conversion: %s\n", err)
  } else {
    fmt.Println(f)
  }
}

【问题讨论】:

  • 我从你的代码中得到3.289141843e+09。这是正确的吗?

标签: go floating-point hex type-conversion


【解决方案1】:

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

您可以使用strconv.ParseUint() 将十六进制表示中的字节解析为uint32ParseUint() 总是返回 uint64,它在内存中使用 8 个字节,因此您必须将其转换为 uint32,它使用 4 个字节,就像 float32

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

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

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

输出(在Go Playground上试试):

-561.2863

注意:

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

f := math.Float32frombits(n2)

【讨论】:

  • 虽然它使用相同的不安全方法,但 math 包有像 Float64FromBits 这样的方法来做到这一点
  • 根据this页面,结果必须是-561.2863
  • @Jan 不同之处在于该数字是 32 位浮点数,而不是您未说明的 64 位。这样做会得到预期的结果。
  • @icza 如果十六进制的大小代表多个 128 位怎么办,此代码将在 ParseUint 处失败
  • @AmitUpadhyay 显然是因为uint64 在 Go 中是 64 位的。如果您必须处理 128 位浮点数,请查看 big.Float
【解决方案2】:

以下是产生 -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】:

    输入为 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

    【讨论】:

    • 无需对其他答案进行社论。字节顺序也没有问题,因为数学包执行与*(*float32)(unsafe.Pointer(&b))完全相同的不安全操作。
    • Stack Overflow“上一个答案”没有意义,答案会根据投票和读者选项重新排序。如果您需要参考另一个答案,请使用“共享”链接获取链接。此外,仅链接的答案不适合 SO,您应该将链接中的相关部分(在本例中为代码)包含到帖子中。
    • 欢迎来到 Stack Overflow!您还应该从答案中的链接中添加相关代码,而不是将链接粘贴到解决方案中。这样,如果链接断开,答案仍然可用。
    猜你喜欢
    • 2014-03-01
    • 1970-01-01
    • 2010-12-08
    • 1970-01-01
    • 2016-06-02
    • 1970-01-01
    • 1970-01-01
    • 2016-06-01
    相关资源
    最近更新 更多