这是2019/09/06的一篇笔记,现在补上。这是《算法》第四版中提到的,如何实现sqrt(x),当时和文德在实验室里面一起研究了一下。今天深信服笔试又遇到了简单版的题目。
整数型
放在以前,只能求整数的平方根:
1 | public int sqrt(int n){ |
至于深信服也是简化到int,笔试嘛…我直接
return (int)Math.sqrt(n);
测试用例当然是100%,能不能拿到分我就不知道了,笔试嘛谁管这个,他也没说不能用,时间重要哈
小数型-牛顿迭代法
再来说一下正经的sqrt实现,也就是如果是小数,你就不知道每次迭代加多少了,0.01?还是0.001?都不够精确。书中提到了牛顿迭代法:
假设要求√2的值,那么构造f(x) = x² - 2, 当y=0时,与x轴的交点就是√2(红点)
随机取一点p,求得f(p),斜率为2p
点斜式构造(y – y0) = k(x – x0)得 y – f(p) = 2p(x - p)
令y = 0,求得直线与y轴交点处x的值x = p – f(p)/2p
这一点会比(4, 0)更接近红点,于是取p = 这一点并重复上述步骤,慢慢逼近红点处x的值
将f(p)化开来:x = p – (p² - 2)/2p
一般化,若p为x上任意一点,x则为下一个靠近点
即next_x = x – (x² - 2) / 2x,化简得next_x = (x + 2/x) / 2
在代码中则直接都表示为x,即x = (x + 2/x) / 2
再一般化,求根号c的值:x = (x + c/x) / 2
逼近个7 8次就已经很接近√2了
Java实现
逼近个7 8次这个说法太宽泛了,可以设置一个能接受的误差程度,比如err = 1e-15
1 | public double sqrt(double c){ |
ps:这是什么?当时看这个的时候我忽然发现,这不就类似bp神经网络的梯度下降嘛!!!!神经网络的那些听起来高大上的反向传播,梯度下降。不就正是和这个一样求导逼近的思想吗,还不如从这个牛顿迭代法开始讲解呢,更加直观。