自己实现一个Math.sqrt()

Math.sqrt()

JavaScript中存在一个Math.sqrt()函数,可以传入一个数字,返回这个数字的开平方根的结果。

自己写一个mySqrt()

我们可以自己模拟实现一个和Math.sqrt()类似功能的函数,这里我们只探讨两种方法(思想)来解决这个问题,一是二分法,二是牛顿迭代法,而至于更底层性能相对更好的方法,这里不做讨论。

二分法

给定一个数字n,我们可以取它的中间数mid,假设mid就是这个数字n开方的结果,用中间数mid进行平方,如果结果大于这个数字n,则说明数字n开方的结果应该比mid要小,即它位于mid的左侧区间,再取这个左侧区间的中间数,直到上一次取的mid和当前次区间取得的mid的间隔达到精度时,则返回结果;反之亦然。

例如:给定一个数字16,取它的中间数也就是8,8的平方是64,比16要大,所以下次我们取区间[0, 8]的中间数也就是4,4的平方是16,正好相等,所以返回结果。

function mySqrt(n) {
  if (n < 0) {
    return NaN;
  }
  if (n === 0) {
     return 0; 
   }
  let low = 0;
  let high = n;
  let prevMid;
  let mid = (low + high) / 2;
  do {
    if (mid * mid > n) {
      high = mid;  
    } else {
      low = mid;
    }
    // 记录上一次取的中间数
    prevMid = mid;
    // 记录当前的中间数
    mid = (low + high) / 2;
  } while (Math.abs(prevMid - mid) > 1e-15);// 对两次的中间数进行对比 如果间隔小于等于精准区间时则说明达到了所需要的精准度 则退出循环
  return parseFloat(mid.toFixed(15));
}

牛顿迭代法

具体步骤如下:

求出根号a的近似值:首先随便猜一个近似值x,然后不断令x等于x和a/x的平均数,迭代个六七次后x的值就已经相当精确了。
例如,我想求根号2等于多少。假如我猜测的结果为4,虽然错的离谱,但你可以看到使用牛顿迭代法后这个值很快就趋近于根号2了:
( 4 + 2/4 ) / 2 = 2.25
( 2.25 + 2/2.25 ) / 2 = 1.56944..
( 1.56944..+ 2/1.56944..) / 2 = 1.42189..
( 1.42189..+ 2/1.42189..) / 2 = 1.41423..
….

具体思想可以自行搜索。简而言之,如下图

a.jpeg

x^2 = a的解,也就是函数f(x) = x^2 – a与x轴的交点。可以在x轴上先任选一点x0,则点(x0, f(x0))在f(x)上的切线,与x轴的交点为x1,它们满足切线的方程:f(x0)=(x0-x1)f’(x0),可得x1更接近最终的结果,解方程得到:
x1 = (x0 + (a/x0))/2
以x1为新的x0,按照切线的方法依次迭代下去,最终求得符合精确度要求的结果值。它的实现代码如下:

// 用牛顿迭代法实现Math.sqrt()
function mySqrtByNewton(n) {
    if (n < 0) {
      return NaN;
    }
    if (n === 0) {
      return 0;  
    }
    var val = n;//最终
    var preVal;//保存上一个计算的值
    do {
        preVal = val;
        val =(val + n / val) / 2;
    } while (Math.abs(val-preVal) > 1e-15);
    return +val.toFixed(15);
}

你可能感兴趣的:(自己实现一个Math.sqrt())