dqnf28092 2014-11-19 02:50
浏览 12
已采纳

进行数学运算得到不同的结果

(I hope) this is not a question about the accuracy of floating point math in Go. Below I have a test function with 2 expressions that I think should produce equal results, but given the inputs, produce different output.

Edit This ended up being just about floating point precision.

Playground Source

package main

import "fmt"

func main() {
    fmt.Println(test(10.0, 0.1, 1.0)) // 0.2
    fmt.Println(test(10.0, 0.2, 1.0)) // 0.3
    fmt.Println(test(10.0, 0.3, 1.0)) // 0.4
    fmt.Println(test(10.0, 0.4, 1.0)) // 0.5
    fmt.Println(test(10.0, 0.5, 1.0)) // 0.6
}

func test(plays float64, rate float64, value float64) float64 {
    // return (value/plays) + rate
    return (plays*rate + value) / plays
}

The first expression (value/plays) + rate prints:

0.2
0.30000000000000004
0.4
0.5
0.6

while the second expression (plays*rate + value) / plays prints the expected output:

0.2
0.3
0.4
0.5
0.6

Why is this?

  • 写回答

1条回答 默认 最新

  • ds1379551 2014-11-19 12:20
    关注

    Since floating point arithmetic is involved, the results for the two expressions will not be the same, even when the input is the same. They may appear to be the same once rounded off to a smaller number of precision positions.

    The reason one of the outputs shows 17 digits after the decimal, while the remaining show only 1, is probably because you are hitting a boundary condition with the 3.0000.... result for the way Println rounds off the floating point values while formating output. To demonstrate the boundary condition, consider the following code:

    package main
    
    import "fmt"
    
    func main() {
        fmt.Println(0.30000000000000000)
        fmt.Println(0.30000000000000001)
        fmt.Println(0.30000000000000002)
        fmt.Println(0.30000000000000003)
        fmt.Println(0.30000000000000004)
        fmt.Println(0.30000000000000005)
        fmt.Println(0.30000000000000006)
        fmt.Println(0.30000000000000007)
        fmt.Println(0.30000000000000008)
    }
    

    The output is:

    0.3
    0.3
    0.30000000000000004
    0.30000000000000004
    0.30000000000000004
    0.30000000000000004
    0.30000000000000004
    0.30000000000000004
    0.3000000000000001
    

    The results of the first two values are truncated and hence the output shows precision of 1 while the other values are rounded off but the precision is much greater. I did not look into the source code of fmt package but this seems to be a result of the way Println truncates floating point values.

    Changing the playground code in the question above to use Printf with a large value for precision gives an idea about what the results actually look like. Here's the modified code in the Go Playground

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题