我正在做Go教程,我想知道是否有更优雅的方法来计算平方根,使用Newton的方法练习:循环和函数比这个:
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
}
Run Code Online (Sandbox Code Playgroud)
(规范的一部分是提供迭代次数.)这是完整的程序,包括package语句,导入和main.
首先,你的算法不正确.公式是:

你用以下方法建模:
z - (z*z - x) / 2*z
Run Code Online (Sandbox Code Playgroud)
但它应该是:
z - (z*z - x)/2/z
Run Code Online (Sandbox Code Playgroud)
要么
z - (z*z - x)/(2*z)
Run Code Online (Sandbox Code Playgroud)
(你的不正确的公式必须运行五十万次迭代,甚至只能得到尽可能接近0.001!正确的公式使用4次迭代来获得尽可能接近1e-6的情况x = 2.)
接下来,初始值z=1不是随机数的最佳值(它可能适用于少数类似的2).你可以开始使用z = x / 2一个非常简单的初始值,并以更少的步骤更接近结果.
其他选项不一定使其更具可读性或优雅,它是主观的:
您可以将结果命名为,z以便return语句可以"裸".如果将当前的"退出"条件移动到循环中,您也可以创建一个循环变量来计算迭代次数,如果满足,则打印迭代计数并且可以简单地返回.您还可以将计算移动到以下的初始化部分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
}
}
}
Run Code Online (Sandbox Code Playgroud)
你也可以移动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
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意:我启动了迭代计数器,1因为我的情况下的"退出"条件是在内部for而不是条件for.
| 归档时间: |
|
| 查看次数: |
667 次 |
| 最近记录: |