【问题标题】:golang decimal to hex conversion errorgolang十进制到十六进制转换错误
【发布时间】:2014-11-29 02:58:10
【问题描述】:

精度问题

设置是一个物理 i 按钮(1-wire 规格),带有制造商打印的十六进制值(可信值)。物联网设备将二进制编码为十进制 - Golang 将接收到的值返回为十六进制。

收到的十进制值为:

var V = 10736581604118680000
fmt.Sprintf("%016X", m.V)[2:14]) // adds uppercase and truncation of output

提供000015877CD1

预期的可信输出是000015877CD0

钥匙上刻的Hex是95 000015877CD0 01

http://www.rapidtables.com/convert/number/decimal-to-hex.htm (trusted?) 表示使用的 golang 函数失去了精度。编码为 19 位十进制数字的二进制值可以通过 Golang 转换为 Hex 而不会损失精度(使用上面的函数)

【问题讨论】:

    标签: go printf hex decimal


    【解决方案1】:

    例如,

    package main
    
    import (
        "fmt"
        "math/big"
        "strconv"
    )
    
    func hexdec(s string) uint64 {
        d := uint64(0)
        for i := 0; i < len(s); i++ {
            x := uint64(s[i])
            if x >= 'a' {
                x -= 'a' - 'A'
            }
            d1 := x - '0'
            if d1 > 9 {
                d1 = 10 + d1 - ('A' - '0')
            }
            if 0 > d1 || d1 > 15 {
                panic("hexdec")
            }
            d = (16 * d) + d1
        }
        return d
    }
    
    func main() {
        x := "95000015877CD001"
        fmt.Println(x)
        n, err := strconv.ParseUint(x, 16, 64)
        fmt.Println(n, err)
        s := fmt.Sprintf("%016X", n)[2:14]
        fmt.Println(s)
        z, t := big.NewInt(0).SetString(x, 16)
        fmt.Println(z, t)
        s = fmt.Sprintf("%016X", z)[2:14]
        fmt.Println(s)
        fmt.Println(hexdec(x))
    }
    

    输出:

    95000015877CD001
    10736581604118679553 <nil>
    000015877CD0
    10736581604118679553 true
    000015877CD0
    10736581604118679553
    

    请注意,您已接近 64 位整数的限制:

    uint64  the set of all unsigned 64-bit integers (0 to 18446744073709551615)
    

    在哪里

    Var V = 10736581604118680000
    

    从哪里来?


    数字 10736581604118680000 是整数 10736581604118679553 的浮点近似值 (1.073658160411868e+19)。制造商可能不理解浮点:What Every Computer Scientist Should Know About Floating-Point Arithmetic。给定整数 10736581604118680000,Go 计算出正确的结果。 Go 在数学上是正确的。

    所以让我们试着告诉 Go 10736581604118680000 不是一个精确的整数,它是一个近似的浮点数。

    例如,

    package main
    
    import (
        "fmt"
        "strconv"
    )
    
    func main() {
        d := "10736581604118680000"
        f, err := strconv.ParseFloat(d, 64)
        fmt.Println(f, err)
        z := uint64(f)
        fmt.Println(z)
        s := fmt.Sprintf("%016X", z)[2:14]
        fmt.Println(s)
    }
    

    输出:

    1.073658160411868e+19 <nil>
    10736581604118679552
    000015877CD0
    

    虽然这个技巧在这种情况下有效,但不能保证在所有情况下都有效。真正的解决方案是制造商聘请一些有能力的数学家。我想知道他们的软件和硬件中还有哪些其他错误。

    【讨论】:

    • 十进制表示的生成是一个远程硬件设备,我们无法假设它用于创建它的函数(无论是否出错)。经过进一步的研究和测试,我们得到了我们所得到的。与其他提供不同结果的参考工具相比,我需要了解在使用 GoLang 时如何获得正确的精度
    • 如您所见并为自己证明,Go 是正确的。
    • 他们可能使用 64 位浮点近似值:1.073658160411868e+19。 IEEE floating point.
    • 同意 - 硬件将 10736581604118679553 近似为 10736581604118680000,但我尝试过的所有在线 DectoHex 转换器都将其计算为 95000015877cd000 - 很想知道为什么 GO 函数将给定的近似值转换为另一个值?
    • @user2314105:很简单。大多数人不了解浮点运算。去吧。 What Every Computer Scientist Should Know About Floating-Point Arithmetic。请参阅我修改后的答案。
    猜你喜欢
    • 1970-01-01
    • 2017-08-29
    • 1970-01-01
    • 2022-01-16
    • 2015-12-12
    • 1970-01-01
    • 2017-05-05
    • 1970-01-01
    相关资源
    最近更新 更多