没有不值得去解决的问题,也没有不值得去学习的技术!

Go 实现 Sqrt() 的三种方式:固定迭代、误差控制与标准库对比

在学习 Go 官方教程 A Tour of Go 时,遇到了一个非常经典的练习: 实现一个平方根函数 Sqrt(x)

1、在学习 Go 官方教程 A Tour of Go 时,遇到了一个非常经典的练习:
实现一个平方根函数 Sqrt(x)。 如图1

在学习 Go 官方教程 A Tour of Go 时,遇到了一个非常经典的练习:
实现一个平方根函数 Sqrt(x)

这个练习不仅涉及 Go 的循环与函数,还引入了一个非常重要的数值计算方法:
牛顿迭代法(Newton’s method)。

本文将通过三个逐步优化的示例,演示如何从一个简单版本,
逐步实现一个更精确、更健壮的平方根函数:

  1. 固定 10 次循环
  2. 使用误差控制停止
  3. 与标准库 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)
	}

	return z
}

func main() {
	fmt.Println("result:", Sqrt(2))
}

4、运行结果示例

可以观察到:

每一次循环后,z 的值都会快速逼近 √2。

通常在第 4~5 次迭代后,
结果已经非常接近真实值。

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)
	}

	return z
}

func main() {
	fmt.Println("result:", Sqrt(2))
}

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 // 精度控制

	for {
		prev := z
		z -= (z*z - x) / (2 * z)

		// 判断变化是否足够小
		if math.Abs(z-prev) < epsilon {
			break
		}
	}

	return z
}

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 // 精度控制

	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
}

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


需要长期技术维护或远程问题排查?

我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。

如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:

  • ✅ PHP / Laravel / Yii2 老项目无人维护
  • ✅ Go / Gin 后端接口需要排查或优化
  • ✅ WordPress 网站访问慢、报错或插件冲突
  • ✅ Nginx / MySQL / Redis / Linux 服务器异常
  • ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
  • ✅ 需要长期远程技术支持或兼职维护

更多介绍请查看:关于我 & 合作

微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理