为什么我在将 float32 转换为 float64 时会丢失精度?

Why am I losing precision while converting float32 to float64?

虽然将 float32 数字转换为 float64 精度在 Go 中丢失。例如,将 359.9 转换为 float64 会生成 359.8999938964844。如果 float32 可以精确存储,为什么 float64 会丢失精度?

示例代码:

package main

import (
    "fmt"
)

func main() {
    var a float32 = 359.9
    fmt.Println(a)
    fmt.Println(float64(a))
}

试试 Playground

当从 float(即 float32)转换为 double(float64)时,您 永远不会 失去精度。前者必须是后者的子集

更多的是与输出格式化程序的默认精度有关。

最接近 359.9 的 IEEE754 float

359.899993896484375

最接近 359.9 的 IEEE754 double

359.8999999999999772626324556767940521240234375

距离 359.899993896484375 最近的 IEEE754 double

359.899993896484375

(即相同;由于我已经提到的子集规则)。

所以你可以看到 float64(a)float64(359.899993896484375) 相同,即 359.899993896484375。这解释了该输出,尽管您的格式化程序正在四舍五入最后的 2 位数字。

这帮助我理解了@FaceyMcFaceFace 的回答:

var a float32 = math.Pi
fmt.Println(a)
fmt.Println(float64(a))
fmt.Println(float64(math.Pi))

3.1415927
3.1415927410125732
3.141592653589793

https://play.golang.org/p/-bAQLqjlLG

我遇到了同样的问题,我对接受的答案不满意,因为它并没有真正解释 Go 中的 float 转换行为。这是一个令我困惑的示例代码,它表明在 Golang 中将 float32 转换为 float64 时发生了一些奇怪的事情。如果有人能更详细地解释一下,我将不胜感激。

package main

import (
    "fmt"
)

func main() {
    var f32 float32 = 0.2
    var f64 float64 = 0.2

    if float64(f32) == f64 { // this is false
        fmt.Println("Check succeeded")
    } else {
        fmt.Println("Check failed")
    }

    if float32(f64) == f32 { // this is true
        fmt.Println("Check succeeded")
    } else {
        fmt.Println("Check failed")
    }

    if float64(float32(f64)) == f64 { // this is false
        fmt.Println("Check succeeded")
    } else {
        fmt.Println("Check failed")
    }
}

https://play.golang.org/p/k2ctx4Zfehy

如果转换后数字不一样,是不是精度损失了?或者也许它应该被称为其他术语,但这绝对不是预期的行为,它可能会导致很多讨厌的错误和混乱。我在对我的应用程序进行单元测试时遇到了这个问题,其中第三方库正在执行从 float32 到 float64 的转换。我无法正确解释这一点,但我在这里学到的是,你必须非常小心地转换浮点数,除非你真的需要,否则你不应该这样做 =)