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

时间:2016-09-22 15:13:21

标签: go floating-point precision

在Go中丢失了将float32数转换为float64的精度。例如,将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

上试试

3 个答案:

答案 0 :(得分:9)

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

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

最近的IEEE754 float到359.9

359.899993896484375

最近的IEEE754 double到359.9

359.8999999999999772626324556767940521240234375

最近的IEEE754 double至359.899993896484375

359.899993896484375

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

因此,您可以看到float64(a)float64(359.899993896484375)相同,即359.899993896484375。这解释了输出,虽然您的格式化程序正在舍入最后的2位数。

答案 1 :(得分:5)

这有助于我理解@ 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

答案 2 :(得分:1)

我遇到了同样的问题,我对接受的答案不满意,因为它并没有真正解释 Go 中的浮点转换行为。这是一个让我感到困惑的示例代码,它表明在 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 的转换。我无法正确解释这一点,但我在这里学到的是,转换浮点数时必须非常小心,除非确实需要,否则不应这样做 =)