Go 实现 Sqrt() 的三种方式:固定迭代、误差控制与标准库对比
1、在学习 Go 官方教程 A Tour of Go 时,遇到了一个非常经典的练习:
实现一个平方根函数 Sqrt(x)。 如图1

这个练习不仅涉及 Go 的循环与函数,还引入了一个非常重要的数值计算方法:
牛顿迭代法(Newton’s method)。
本文将通过三个逐步优化的示例,演示如何从一个简单版本,
逐步实现一个更精确、更健壮的平方根函数:
- 固定 10 次循环
- 使用误差控制停止
- 与标准库 math.Sqrt 进行结果对比
所有代码均按照以下目录组织:
go-tour/
├── sqrt-iterations/
├── sqrt-epsilon/
├── sqrt-iteration-count/
2、## 牛顿迭代法简介
平方根的目标是:
给定一个数 x,找到一个数 z,使得:
z² ≈ x
牛顿法通过不断修正 z,使其逐渐接近真实值。
每一步的更新公式如下:
z = z – (zz – x) / (2z)
其中:
- z*z – x 表示当前误差
- 2*z 表示函数 z² 的导数
- 每次更新都会让结果更接近真实值
这个方法收敛速度非常快,
通常只需要几次迭代就可以达到很高精度。
3、示例 1:固定 10 次迭代,对应 sqrt-iterations/main.go
package main
import (
"fmt"
)
func Sqrt(x float64) float64 {
z := 1.0 // 初始猜测值
for i := 0; i < 10; i++ {
z -= (z*z - x) / (2 * z)
fmt.Println("iteration", i, "z =", z)
}
<pre><code>return z</code></pre>
}
func main() {
fmt.Println("result:", Sqrt(2))
}
4、运行结果示例
可以观察到:
每一次循环后,z 的值都会快速逼近 √2。
通常在第 4~5 次迭代后,
结果已经非常接近真实值。
/app/go-tour/sqrt-iterations # go run main.go iteration 0 z = 1.5 iteration 1 z = 1.4166666666666667 iteration 2 z = 1.4142156862745099 iteration 3 z = 1.4142135623746899 iteration 4 z = 1.4142135623730951 iteration 5 z = 1.414213562373095 iteration 6 z = 1.4142135623730951 iteration 7 z = 1.414213562373095 iteration 8 z = 1.4142135623730951 iteration 9 z = 1.414213562373095 result: 1.414213562373095
5、示例 2:使用 epsilon 控制收敛 + 对比 math.Sqrt 对应:sqrt-epsilon/main.go
package main
import (
"fmt"
"math"
)
func Sqrt(x float64) float64 {
z := 1.0 // 初始猜测值
const epsilon = 1e-10 // 精度控制
<pre><code>for {
prev := z
z -= (z*z - x) / (2 * z)
// 判断变化是否足够小
if math.Abs(z-prev) < epsilon {
break
}
}
return z</code></pre>
}
func main() {
fmt.Println("My sqrt:", Sqrt(2))
fmt.Println("Math sqrt:", math.Sqrt(2))
}
6、运行结果示例
为什么这样更好?
这种方式:
自动判断收敛
避免无意义计算
提高程序效率
为了验证我们的实现是否正确,
可以将结果与 Go 标准库中的 math.Sqrt 进行对比。
可以看到,两者几乎完全一致(完全相等)。
/app/go-tour/sqrt-epsilon # go run main.go My sqrt: 1.4142135623730951 Math sqrt: 1.4142135623730951
7、示例 3:统计迭代次数(观察收敛效率) 对应:sqrt-iteration-count/main.go
package main
import (
"fmt"
"math"
)
func Sqrt(x float64) float64 {
z := 1.0 // 初始猜测值
const epsilon = 1e-10 // 精度控制
<pre><code>count := 0
for {
prev := z
z -= (z*z - x) / (2 * z)
count++
// 判断变化是否足够小
if math.Abs(z-prev) < epsilon {
break
}
}
fmt.Println("iterations:", count)
return z</code></pre>
}
func main() {
fmt.Println("result:", Sqrt(2))
}
8、运行结果示例
特点:
统计 count
输出 iterations
用途:
观察算法效率。
通常:
iterations: 5
只需 5 次就能得到高精度结果。
/app/go-tour/sqrt-iteration-count # go run main.go iterations: 5 result: 1.4142135623730951