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 TLS1.2协议通信解密
  • ¥40 图书信息管理系统程序编写
  • ¥20 Qcustomplot缩小曲线形状问题
  • ¥15 企业资源规划ERP沙盘模拟
  • ¥15 树莓派控制机械臂传输命令报错,显示摄像头不存在
  • ¥15 前端echarts坐标轴问题
  • ¥15 ad5933的I2C
  • ¥15 请问RTX4060的笔记本电脑可以训练yolov5模型吗?
  • ¥15 数学建模求思路及代码
  • ¥50 silvaco GaN HEMT有栅极场板的击穿电压仿真问题