具有不同结果的数学运算

标签 go

(我希望)这不是关于 Go 中 float 学准确性的问题。下面我有一个包含 2 个表达式的测试函数,我认为它们应该产生相同的结果,但是给定输入,产生不同的输出。

编辑 这最终只是关于浮点精度。

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
}

第一个表达式 (value/plays) + rate 打印:

0.2
0.30000000000000004
0.4
0.5
0.6

第二个表达式 (plays*rate + value)/plays 打印预期输出:

0.2
0.3
0.4
0.5
0.6

这是为什么?

最佳答案

由于涉及浮点运算,即使输入相同,两个表达式的结果也不会相同。一旦四舍五入到较小数量的精确位置,它们可能看起来是相同的。

其中一个输出显示小数点后 17 位,而其余输出仅显示 1 位的原因可能是因为您正在使用 3.0000.... Println 四舍五入浮点值的方式达到边界条件在格式化输出时。为了演示边界条件,请考虑以下代码:

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)
}

输出是:

0.3
0.3
0.30000000000000004
0.30000000000000004
0.30000000000000004
0.30000000000000004
0.30000000000000004
0.30000000000000004
0.3000000000000001

前两个值的结果被截断,因此输出显示精度为 1,而其他值被四舍五入,但精度更高。我没有查看 fmt 包的源代码,但这似乎是 Println 截断浮点值的方式的结果。

将上述问题中的 playground 代码更改为使用具有较大精度值的 Printf,可以了解结果的实际情况。这是 Go Playground 中修改后的代码

关于具有不同结果的数学运算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27008113/

相关文章:

go - 如何为wosagger服务websocket?

go - 如何使 `go get` 构建为针对 x86_64 而不是 i386

dataframe - 使用 gota ReadCSV 时跳过行

rest - 去 SSL 监听器

arrays - 数组精简或类似

node.js - 编写服务端实现RPC客户端Node.js

go - 如何检查通过 logrus 生成的日志,以获取编号。错误和警告

golang 在子目录中找不到包 gin

time - 在 Go 中解析日期

go - 具有非固定类型参数的函数