leetcode 69 牛顿法实现double sqrt(double x)函数

实现sqrt()开平方,要能处理精确的小数,类似leetcode 69,leetcode-cn没有找到浮点型的题。但是解法能通用。

直觉解释牛顿法:

利用导数和变化趋势,寻找方程y=f(x)的根。

虽然示意图烂大街了,还是坚持自己画一个:

黑色曲线为要拟合方程y=f(x)

红色直线为切线y-y0=y0'*(x-x0)

绿色直线为前一步找到的切线根再做垂线回到曲线一点(x,f(x))

 迭代过程:从点A画切线,找到切线根B(xb,0),然后找到点C(xb,f(xb)),再从C做切线,找到切线根D,如此往复。

如图:E低于X轴,没关系,找的是根,向上找到G,假设这个时候G和垂线距离极小(偷懒),迭代结束,找到目标f(x)=0的x。

牛顿法迭代公式:

充分条件

既然方法简单粗暴,就肯定有缺点,不是对任何函数和任何起点都有效,这里不举复杂例子,以一个变种的y=x^2+b举例,牛顿法会导致反复横跳,不能收敛。

这里不需要知道牛顿法的全部支持和不支持的起点和曲线,只需要知道是否能支持sqrt曲线

sqrt:y=x^(1/2)大概是这样

 sqrt-N大概这样

貌似可以收敛,但是我发现了一点问题:牛顿法的目标到底是谁?我要实现sqrt(),可是我并不是要用sqrt(),sqrt()不是已知功能,是要实现的功能。

基于sqrt()大概能实现什么功能,如果sqrt(x)=N,通过不断迭代找到的x(下标n+1)其实是N^2。给定一个N,得到了一个N^2,显然,这不是sqrt(),是pow2()

所以,要找到sqrt(N),公式应该是

f(x)=x*x-N,求f(x)的根,迭代出来满足这个条件的x(下标n+1),其实就是N的开方。

 f(x)有两个根,这里我们只要找到右边的根就可以。sqrt输入输出只能是非负数。

根据“牛顿法迭代过程是做切线找根再做切线找根的过程”这一事实,x(下标n+1)的通用方程是

 放到sqrt()实现的例子中

 

 迭代过程伪代码

while(循环不终止)

    x=0.5*(x+N/x)

浮点数 终止条件,精度随意

(abs(x*x-N)-0<1e-6)

 结合起来

double sqrt(double N){
    double x=N;

    while(!(abs(x*x-N)-0<1e-6))
        x=0.5*(x+N/x);

    return x;
}

(出于习惯用N表示常量,而不是用x表示输入,因为在优化过程中N是常量)

代码更新:

int sqrt(int x)
{
    // 避免除零错误,单独处理 x = 0 的情况
    if (x == 0)
        return x;
    int t = x / 2 + 1;
    while (t > x / t)
        t = (t + x / t) / 2;
    return t;
}

https://github.com/huqinwei/leetcode_practice/blob/main/leetcode_practice/Solution_0xx.h

扩展:可以出现更多类似此题,但是一定要确认是否满足充分条件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值