【问题标题】:Why am I losing precision while converting float32 to float64?为什么在将 float32 转换为 float64 时会丢失精度?
【发布时间】:2017-01-31 06:05:39
【问题描述】:

在将 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

【问题讨论】:

  • 当我需要使用有理数时,这让我很不爽。转换为 float64 的额外精度“获得”给出了 int32 无法表示的不同分子和分母。具有讽刺意味的是,这奏效了:strconv.ParseFloat(fmt.Sprint(f32var), 64)

标签: go floating-point precision


【解决方案1】:

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 位进行四舍五入。

【讨论】:

  • 我在这里特别谈论 golang。 golang 可以准确存储 359.9 但转换为 float64 后值更改为 359.8999938964844。
  • @MayankPatel:查看各种浮点格式动词的输出:play.golang.org/p/9CDBLy7DMQ
  • 在这里我认为这个答案是完美的。你看不出这是因为将 359.9 转换为浮点数,即 359.899993896484375,将其转换为 float64 没有任何效果,而你只是打印出来?
  • @MayankPatel:不,因为浮点数不是十进制数。您正在乘以 32 位浮点数精度内的数字 (1.405859351158142x2^8) * (1.5625x2^6)
  • 要验证没有精度损失,请将 double 转换回 float 并将其打印为 float。
【解决方案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

【讨论】:

    【解决方案3】:

    我遇到了同样的问题,我对接受的答案不满意,因为它并没有真正解释 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 的转换。我无法正确解释这一点,但我在这里学到的是,你必须非常小心地转换浮点数,除非你真的需要,否则你不应该这样做 =)

    【讨论】:

      猜你喜欢
      • 2021-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-15
      • 2016-06-14
      • 1970-01-01
      • 2010-10-29
      相关资源
      最近更新 更多