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

我注意到 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


翻阅古今
浏览 97回答 1
1回答

30秒到达战场

您的断言是错误的:不能用或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
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go