求平方根的两种实现方式:二分法、牛顿迭代法
一、二分法
思路: 假设要求一个数字 A 的平方根,可以想象一个长为a、宽为b的矩形,这个矩形的面积就是数字A 。 当长=宽时,这个矩形就是正方形。在面积不变的情况下,使矩形变成正方形就需要调整长、宽的值,无非是长变短一点、宽变长一点,通过不停的迭代,直到长=宽时就能求出A的平方根,由于一个数的平方根可能是小数,所以只需要求出近似值即可(符合给定的误差范围就行)
以下是用go语言实现的代码:
// 全局变量,精度 var precision = 0.000001 // Sqrt 计算开平方 , val是要计算平方根的值, mode是模式, 0 为二分法,1位牛顿迭代 func Sqrt(val float64, mode int8) (float64, error) { if val < 0 { return 0, errors.New("负数没有平方根") } switch mode { case 0: return sqrtBisection(val, 1, (val/2)-1) case 1: return sqrtNewtonRaphson(val) default: return 0, errors.New("不识别的模式") } } // 二分法求平方根 func sqrtBisection(val float64, left float64, right float64) (float64, error) { count := 0 for left <= right { // 左,右 边界值相加在除以2得到结果值 result := (left + right) / 2 tmp := result * result if tmp-val <= precision && tmp-val >= precision*-1 { fmt.Printf("二分法循环次数:%v\n", count) return result, nil } else if tmp > val { right = result } else { left = result } count += 1 } return -1, errors.New("计算错误") }
二、牛顿迭代法求平方根:
思想: 该方法的核心思想是通过在曲线上的某点做切线,该切线的根就很接近曲线的根,通过多次迭代即可无限逼近曲线真正的根 (前提是该曲线确实存在根,且给定范围内可导,平方方程可以写成: x^2 +c = 0 , 这个方程明显是可导的,所以可以用牛顿迭代法求平方根)。
参考: https://www.zhihu.com/question/20690553
go语言实现:
func sqrtNewtonRaphson(val float64) (float64, error) { // 平方的表达式: x^2 + val = 0 , val就是要开平方的数 // 平方的导数: k=2x // 第一个曲线上的点 (val/2, f(x) ) , // 求出该点的 切线方程,通用切线方程: y=kx+c => 2x^2 +c => c= y-2x^2 // 求出该切线方程的根(与x轴的交点) // 判断该根的平方与 val的误差是否在精度内容, 如果是则返回,否则继续以该根为x坐标,算出y坐标,得到下一次迭代的点坐标,然后继续上面的步骤 // ------------------------------------------------ // 求得曲线上y坐标的方程 getYval := func(x float64) float64 { return x*x - val } // 求切线方程的常数项c的函数 getTangentC := func(x float64, y float64) float64 { return y - 2*(x*x) } // 求切线的根的函数 getTangentRoot := func(k float64, c float64) float64 { return -c / k } // 第一个点的坐标 x := val / 2 y := getYval(x) // 求得切线c的值 c := getTangentC(x, y) // 求得切线的根 root := getTangentRoot(2*x, c) // 根的平方值 tmp := root * root // 迭代的次数 count := 1 // 迭代执行 for { if tmp-val <= precision && tmp-val >= precision*-1 { break } x = root y = getYval(x) c = getTangentC(x, y) root = getTangentRoot(2*x, c) tmp = root * root count += 1 } fmt.Printf("牛顿迭代法循环的次数:%v\n", count) return root, nil }
如何通俗易懂地讲解牛顿迭代法求开方(数值分析)? - 马同学的回答 - 知乎 https://www.zhihu.com/question/20690553/answer/146104283如何通俗易懂地讲解牛顿迭代法求开方(数值分析)? - 马同学的回答 - 知乎 https://www.zhihu.com/question/20690553/answer/146104283如何通俗易懂地讲解牛顿迭代法求开方(数值分析)? - 马同学的回答 - 知乎 https://www.zhihu.com/question/20690553/answer/146104283
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!