为了账号安全,请及时绑定邮箱和手机立即绑定

将 json 解组为浮动。为什么需要 float64?

将 json 解组为浮动。为什么需要 float64?

Go
翻阅古今 2023-07-31 15:58:50
我注意到 go unmarshals json floats 的方式有一些奇怪的行为。有些数字(但不是全部)拒绝正确解组。解决这个问题就像在目标变量中使用 float64 而不是 float32 一样简单,但我一生都找不到出现这种情况的充分理由。这是演示该问题的代码:package mainimport (    "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
查看完整描述

1 回答

?
30秒到达战场

TA贡献1828条经验 获得超6个赞

您的断言是错误的:不能369.1368精确表示。 float32 float64

最接近的float32值是(大约)369.136810302734375,它四舍五入到369.13681您的额外数字的来源。最接近的float64值是(大约)369.13679999999999382,它更适合您的目的。

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

表示Decimal是精确的:没有舍入误差。

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

此 Go Playground 示例使用新添加的%x格式,并向您展示数字如何在内部存储:

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

和:

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

也就是说,数字 369。无论内部以二进制表示。它在 2 8 = 256 和 2 9 = 512 之间。在二进制中,它是 1 256、无 128、1 64、1 32、1 16、无 8、无 4、无 2 和 1 1:1.01110001 某物x 2 8。格式%b以一种方式表达%x,另一种格式以(1 . 0111 0010)%x开头。1.72

查看完整回答
反对 回复 2023-07-31
  • 1 回答
  • 0 关注
  • 88 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信