2 回答
TA贡献1799条经验 获得超9个赞
首先,你的算法不正确。公式为:
您对此进行了建模:
z - (z*z - x) / 2*z
但它应该是:
z - (z*z - x)/2/z
或者
z - (z*z - x)/(2*z)
(您不正确的公式不得不像半个百万次迭代甚至只得到尽可能接近运行0.001!正确的公式使用像4次迭代来获得尽可能接近1e-6的情况下x = 2)。
其次, 的初始值z=1对于随机数不是最好的(它可能适用于像 那样的小数2)。您可以使用z = x / 2一个非常简单的初始值开始,并以更少的步骤使您更接近结果。
其他选项不一定使它更具可读性或优雅,这是主观的:
您可以将结果命名为,z以便返回语句可以是“裸”的。如果您将当前的“退出”条件移动到循环中,您也可以创建一个循环变量来计算迭代次数,如果满足,则打印迭代次数并可以简单地返回。您还可以将计算移至 的初始化部分if:
func Sqrt(x float64) (z float64) {
z = x / 2
for i, old := 1, 0.0; ; i++ {
if old, z = z, z-(z*z-x)/2/z; math.Abs(old-z) < 1e-5 {
fmt.Printf("Ran %v iterations\n", i)
return
}
}
}
您还可以将 移动z = x / 2到 的初始化部分,for但是您不能命名结果(否则z将创建一个本地变体,它会影响命名的返回值):
func Sqrt(x float64) float64 {
for i, z, old := 1, x/2, 0.0; ; i++ {
if old, z = z, z-(z*z-x)/2/z; math.Abs(old-z) < 1e-5 {
fmt.Printf("Ran %v iterations\n", i)
return z
}
}
}
注:我开始了我的迭代计数器,1因为在我的情况下,“退出”的条件是内部的for,而不是条件for。
TA贡献1811条经验 获得超6个赞
package main
import (
"fmt"
"math"
)
func Sqrt(x float64) float64 {
z := 1.0
// First guess
z -= (z*z - x) / (2*z)
// Iterate until change is very small
for zNew, delta := z, z; delta > 0.00000001; z = zNew {
zNew -= (zNew * zNew - x) / (2 * zNew)
delta = z - zNew
}
return z
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(math.Sqrt(2))
}
- 2 回答
- 0 关注
- 173 浏览
添加回答
举报