dongyun7571
2014-11-29 02:58
浏览 444
已采纳

golang十进制到十六进制转换错误

Problem with precision

The setup is a physical i-button (1-wire specification) with printed hex value by manufacturer (trusted value). An IoT device encodes the binary as decminal - Golang returns the received value to Hex.

received decimal value is:

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

provides 000015877CD1

The expected trusted output is 000015877CD0

the engraved Hex on the key is 95 000015877CD0 01

http://www.rapidtables.com/convert/number/decimal-to-hex.htm (trusted?) indicates that the golang function used has lost precision. binary values that encode to 19 decimal digits can be converted to Hex by Golang without loss of precision (using function above)

图片转代码服务由CSDN问答提供 功能建议

精度问题

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

接收到的十进制值为:

  var V =  10736581604118680000 
fmt.Sprintf(“%016X”,mV)[2:14])//添加大写和输出截断
   
 
 

提供了 000015877CD1 < / code>

预期的可信输出为 000015877CD0

密钥上刻有十六进制的字符为 95 000015877CD0 01

http ://www.rapidtables.com/convert/number/decimal-to-hex.htm (受信任?)表示所使用的golang函数已失去精度。 可以使用Golang将编码为19个十进制数字的二进制值转换为十六进制,而不会损失精度(使用上述函数)

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • douzao2590 2014-11-29 03:56
    已采纳

    For example,

    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))
    }
    

    Output:

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

    Note that you are near the limits of 64-bit integers:

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

    Where does

    Var V = 10736581604118680000
    

    come from?


    The number 10736581604118680000 is a floating-point approximation (1.073658160411868e+19) of the integer 10736581604118679553. The manufacturer probably doesn't understand floating-point: What Every Computer Scientist Should Know About Floating-Point Arithmetic. Given the integer 10736581604118680000, Go calculates the correct result. Go is mathematically correct.

    So let's try telling Go that 10736581604118680000 is not an exact integer, that it's an approximate floating-point number.

    For example,

    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)
    }
    

    Output:

    1.073658160411868e+19 <nil>
    10736581604118679552
    000015877CD0
    

    While this trick works in this case, it's not guaranteed to work in all cases. The real solution is for the manufacturer to employ some competent mathematicians. I wonder what other bugs there are in their software and hardware.

    点赞 打赏 评论

相关推荐 更多相似问题