我正在做Go教程,并且想知道是否有一种比牛顿的方法更灵活的方法可以使用牛顿方法在练习:循环和函数上计算平方根:
func Sqrt(x float64) float64 {
count := 0
var old_z, z float64 = 0, 1
for ; math.Abs(z-old_z) > .001; count++ {
old_z, z = z, z - (z*z - x) / 2*z
}
fmt.Printf("Ran %v iterations\n", count)
return z
}
(规范的一部分是提供迭代次数。)这是完整的程序,包括package语句,imports和main。
首先,您的算法不正确。公式为:
您使用以下方法对此建模:
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
以便return语句可以是“ bare”。另外,如果将当前的“退出”条件移入循环,则可以创建一个循环变量来计算迭代次数,如果满足该条件,则可以打印迭代次数并可以简单地返回。您也可以将计算移至的初始化部分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
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句