[英]How do you handle float64 comparisons in golang?
我正在瀏覽 go 並在“練習:循環和函數”中遇到 float64 比較問題,您在其中編寫了一個函數來確定平方根。
來自示例:計算機通常使用循環計算 x 的平方根。 從一些猜測 z 開始,我們可以根據 z² 與 x 的接近程度調整 z,從而產生更好的猜測:
z -= (z*z - x) / (2*z)
我寫了一個函數,它會繼續更新 z 直到值停止變化。 只有 float64 比較永遠不會失敗,這會導致無限循環。 解決這類問題的一種方法是四舍五入,但我不確定如何在不使用數學模塊的情況下在 golang 中做到這一點。
你如何在 golang 中舍入 float64 數字以及在 golang 中比較浮點數的標准方法是什么?
package main
import (
"fmt"
)
func Sqrt(x float64) float64 {
// Need to look into float rounding in go
z := 1.0
zprev := 0.01
for z != zprev {
zprev = z
z -= (z*z - x) /(2*z)
fmt.Printf("z: %g\nzprev: %g\n", z, zprev)
fmt.Println("_________________________________________")
}
fmt.Println("Finished")
return z
}
func main() {
fmt.Println(Sqrt(2))
}
輸出:
z: 1.5
zprev: 1
_________________________________________
z: 1.4166666666666667
zprev: 1.5
_________________________________________
z: 1.4142156862745099
zprev: 1.4166666666666667
_________________________________________
z: 1.4142135623746899
zprev: 1.4142156862745099
_________________________________________
z: 1.4142135623730951
zprev: 1.4142135623746899
_________________________________________
z: 1.414213562373095
zprev: 1.4142135623730951
_________________________________________
z: 1.4142135623730951
zprev: 1.414213562373095
_________________________________________
z: 1.414213562373095
zprev: 1.4142135623730951
_________________________________________
z: 1.4142135623730951
zprev: 1.414213562373095
_________________________________________
z: 1.414213562373095
zprev: 1.4142135623730951
_________________________________________
在一個點之后 z 和 zprev 繼續在兩個僅相差一個精度點(1.414213562373095 和 1.4142135623730951)的值之間無限期地交替
不要四舍五入,取要比較的兩個數字之間的差值,並檢查它是否在-epsilon
和epsilon
之間,其中epsilon
是您認為足夠小的差值。
注意:不可靠的相等比較不是 go-specific; 這是浮點數的普遍問題。
這就是我的做法——假定您根本不想使用math
包。
package main
import "fmt"
func abs(x float64) float64 {
if x < 0 {
return -x
}
return x
}
func Sqrt(x float64) float64 {
z := x
var zprev float64
for abs(zprev-z) > 1e-6 {
zprev, z = z, z-(z*z-x)/(2*z)
}
return z
}
func main() {
fmt.Println(Sqrt(2))
}
輸出:
1.4142135623730951
我發現解決這個問題的方法是將比較中的一個值添加到比較的兩側。
下面我將 z 添加到比較的兩側,現在比較按預期進行。
package main
import (
"fmt"
)
func Sqrt(x float64) float64 {
// Need to look into float rounding in go
z := 1.0
zprev := 0.01
for zprev + z != z + z {
zprev = z
z -= (z*z - x) /(2*z)
fmt.Printf("z: %g\nzprev: %g\n", z, zprev)
fmt.Println("_________________________________________")
}
fmt.Println("Finished")
return z
}
輸出:
z: 1.5
zprev: 1
_________________________________________
z: 1.4166666666666667
zprev: 1.5
_________________________________________
z: 1.4142156862745099
zprev: 1.4166666666666667
_________________________________________
z: 1.4142135623746899
zprev: 1.4142156862745099
_________________________________________
z: 1.4142135623730951
zprev: 1.4142135623746899
_________________________________________
z: 1.414213562373095
zprev: 1.4142135623730951
_________________________________________
z: 1.4142135623730951
zprev: 1.414213562373095
_________________________________________
Finished
1.4142135623730951
蘭斯,我相信你現在一定已經精通編程,但對於像我這樣仍在從這里開始的其他人來說,這是@Aasmund Eldhuset 建議的浮動比較。
package main
import (
"fmt"
)
func Sqrt(x float64) float64 {
z:=float64(x/2)
i:=1
oldz := -1.0
for {
fmt.Printf(" %d => %f\n",(i),z)
z-=(z*z-x)/(2*z)
if diff:=(oldz-z); diff>-0.0000000001 && diff<0.0000000001{
fmt.Println("Breaking!")
break
}
oldz = z
i+=1
}
return z
}
func main() {
fmt.Println(Sqrt(2))
}
輸出:
1 => 1.000000
2 => 1.500000
3 => 1.416667
4 => 1.414216
5 => 1.414214
Breaking!
1.4142135623730951
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.