(我希望)这不是关于 Go 中 float 学准确性的问题。下面我有一个包含 2 个表达式的测试函数,我认为它们应该产生相同的结果,但是给定输入,产生不同的输出。
编辑 这最终只是关于浮点精度。
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/