json - 解码 json 以 float 。为什么需要 float64?

标签 json go floating-point unmarshalling

我注意到 go unmarshals json floats 的方式有一些奇怪的行为。一些数字,但不是全部,拒绝正确解码。解决这个问题就像在目标变量中使用 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

最佳答案

您的断言是错误的: 369.1368 不能完全由 float32float64 表示。

最接近的 float32 值是(大约) 369.136810302734375 ,四舍五入到 369.13681 ,这是您的额外数字的来源。最接近的 float64 值是(大约) 369.13679999999999382 ,对于您的目的而言,它会更好地舍入。

(当然,如果你将其中任何一个四舍五入到小数点后四位,你就会得到你期望的数字。)
Decimal 表示是准确的:没有舍入误差。

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

This Go Playground example 使用新添加的 %x 格式,并展示了数字在内部是如何存储的:

as float32 = 369.13681030273437500 (float32), which is really 12095875p-15 or 0x1.712306p+08



和:

as float64 = 369.13679999999999382 (float64), which is really 6493923261440380p-44 or 0x1.712305532617cp+08



也就是说,数字 369.whatever 在内部以二进制表示。它在 28 = 256 和 29 = 512 之间。在二进制中,它是 1 256、没有 128、1 64、1 32、1 16、没有 8、没有 4、没有 2 和 1 1:1.01110001something x 28。%b格式表示这种方式,而 %x 格式表示另一种方式,%x1.72 (1 . 0111 0010) 开头。

有关更多信息,请参见 Is floating point math broken?(如 jub0bs 评论中的链接)。

关于json - 解码 json 以 float 。为什么需要 float64?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58566282/

相关文章:

javascript - 从 JSON 使用 Jquery 更新下拉列表

json - 如何在 Golang 中解码复杂的未命名 JSON

go - 当所有 goroutines 完成时退出程序

go - go list ./... 做什么?

binary - 浮点精度是可变的还是不变的?

javascript - 如何从 JSON 文件中获取数据

python - 将从 JSON 获取的 Python 字典写入文件中

PHP:如何防止 json_encode 自动舍入数字?

c - 将 float 转换为 double 如何工作?

具有相同键的 Python 字典排序