2种方法求解根号2


前言

这是一道经典的面试题:自己编写函数实现根号2(根号n)的求解。
(说明:笔者习惯使用python编程,因此以下算法实现均使用python)
首先,python内置的math(数学运算)库中包含了求非负实数平方根的函数sqrt (square root):

from math import sqrt
print(sqrt(2))

可以得到一个高精度的结果,具体精度取决于操作系统限制。在笔者的64位Windows系统中,输出的结果为
1.4142135623730951

这已经是令人满意的答案了,但有没有数学方法,可以不依赖内置库函数,自己实现平方根的计算(精确估计)呢?我们来看两种方法。

一、牛顿-拉弗森法(Newton-Raphson Method)

这个方法被认为同时被艾萨克·牛顿和约瑟夫·拉弗森提出,所以被命名为牛顿-拉弗森法。

这个方法主要讲的是这个结论:如果存在一个k是多项式P的根的有效近似,那么k - p(k) / p’(k)就是一个更有效的近似值。其中p’是p的一次导数。

求解根号n可以转化为求多项式x ^ 2 - n的根的问题,该多项式的一次导数是2x. 因此,如果当前的猜测是k, 那么可以选择k - (k ^ 2 - n) / 2k 作为下一个猜测值,直到误差(k ^ 2 - n)的绝对值小于给定的值epsilon. 这种方法称为逐次逼近。

Python实现:

# 利用牛顿-拉弗森法寻找平方根
# 寻找x,满足x ^ 2 - k 在 (0, epsilon)范围内

def newton_raphson(k, epsilon):
    guess = k
    while abs(guess * guess - k) >= epsilon:
        guess = guess - (((guess * guess) - k) / (guess * 2))
    return guess


print(newton_raphson(2, 0.000000001))

二、二分查找法(Binary Search)

1.算法原理

如果x是大于1的数,则根号x一定位于0到x之间,此时我们用(暴力的)二分查找法求根号x的近似值,判定迭代结束的条件为abs(ans ^ 2 - x) < epsilon.

如果x是小于1大于0的数,则根号x位于0到1之间,此时我们在(0,1)区间内用二分查找法求解根号x的近似值,迭代结束的条件同上。

2.Python实现

注意由于没有事先判定x的范围,所以查找上限变成了max(1.0, x). 下限为0.

# 使用二分查找求近似平方根

def bi_search_root(x, epsilon):
    low = 0.0
    high = max(1.0, x)
    ans = (high + low) / 2.0
    while abs(ans ** 2 - x) >= epsilon:
        if ans ** 2 < x:
            low = ans
        else:
            high = ans
        ans = (high + low) / 2.0
    return ans


print(bi_search_root(2, 0.000000001))

三、两种算法的效率比较

从时间复杂度上来看,牛顿法优于二分查找法。
我们可以对之前的代码进行简单的修改,以直观地看出这一区别:
将牛顿-拉弗森法的代码修改为:

# 利用牛顿-拉弗森法寻找平方根
# 寻找x,满足x ^ 2 - k 在 (0, epsilon)内

def newton_raphson(k, epsilon):
    guess = k / 2.0
    times = 0
    while abs(guess * guess - k) >= epsilon:
        guess = guess - (((guess * guess) - k) / (guess * 2))
        times += 1
    return guess, times


print(newton_raphson(2, 0.000000001))

times变量用于记录迭代求解的总次数。这里和以下的二分查找法的epsilon参数均设置为0.000000001.
将二分查找法的代码修改为:

# 使用二分查找求近似平方根

def bi_search_root(x, epsilon):
    numGuesses = 0
    low = 0.0
    high = max(1.0, x)
    ans = (high + low) / 2.0
    while abs(ans ** 2 - x) >= epsilon:
        numGuesses += 1
        if ans ** 2 < x:
            low = ans
        else:
            high = ans
        ans = (high + low) / 2.0

    return ans, numGuesses


print(bi_search_root(2, 0.000000001))

numGuesses变量用于记录迭代求解的总次数。
运行结果:牛顿法只用了四次迭代就得到了满意的近似值,而二分查找法则需要29次才能得到类似的结果。

(1.4142135623746899, 4)
(1.4142135623842478, 29)

总结

本文介绍了两种自定义求解根号的方法(Python实现),分别是牛顿-拉弗森法和二分查找法。牛顿-拉弗森法的时间复杂度比简单二分查找要低。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不是AI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值