将JSON解组到浮动状态。为什么需要float64?

问题描述 投票:0回答:1

[我注意到去编组json浮点数的方式有些奇怪的行为。有些数字(但不是全部)拒绝正确解组。修复此问题就像在目标变量中使用float64而不是float32一样容易,但是对于我来说,我找不到找到这种情况的充分理由。

这里是演示问题的代码:

package main

import (
    "encoding/json"
    "fmt"
    . "github.com/shopspring/decimal"
)

func main() {
    bytes, _ := json.Marshal(369.1368) // not every number is broken, but this one is
    fmt.Println("bytes", string(bytes))

    var f32 float32
    json.Unmarshal(bytes, &f32)
    fmt.Printf("f32 %f\n", f32) // adds an extra 0.00001 to the number

    var d Decimal
    json.Unmarshal(bytes, &d)
    fmt.Printf("d %s\n", d) // 3rd party packages work

    // naw, you can just float64
    var f64 float64
    json.Unmarshal(bytes, &f64)
    fmt.Printf("f64 %f\n", f64) // float64 works
}

不需要float64即可准确表示我的示例编号,为什么在这里需要?

去游乐场链接:https://play.golang.org/p/tHkonQtZoCt

json go floating-point unmarshalling
1个回答
0
投票
中使用float64而不是float32一样容易

您的断言是错误的:369.1368不能用任一float32 float64准确表示。

最接近的float32值是(大约)369.136810302734375,四舍五入到369.13681,这是您的多余数字的来源。最接近的float64值是(大约)369.13679999999999382,根据您的目的,该值更舍入。

(当然,如果您将其中任何一个四舍五入到小数点后四位,您都会得到期望的数字。)

Decimal表示是准确的:没有舍入错误。

JSON发送和接收以十进制表示的浮点值,但以各种语言表示实际的implementations,然后以不同的方式encode这些数字。根据您通过JSON交谈的实体的类型,通过Decimal进行编码和解码可以完全保留所需的数字,但是请注意,用C ++或Python编写的程序可能会将您的数字解码为不同的浮点精度,并引入各种舍入误差。

[This Go Playground example使用新添加的%x格式,并向您显示数字在内部的存储方式:

作为float32 = 369.13681030273437500(float32),它实际上是12095875p-15或0x1.712306p + 08

和:

作为float64 = 369.13679999999999382(float64),它实际上是6493923261440380p-44或0x1.712305532617cp + 08

也就是数字369。whatever在内部以二进制表示。它在2 8 = 256和2 9 = 512之间。在二进制中,它是1256,no 128、1 64、1 32、1 16,no 8,no 4,no 2和1 1:1.01110001 某物]×2 8%b格式以这种方式表达,%x格式以另一种方式表达,其中%x1.72开头(1.0111 0010)。

请参阅Is floating point math broken?(作为jub0bs在评论中链接)。

© www.soinside.com 2019 - 2024. All rights reserved.