平方根函数实现
手写 sqrt 函数,使用二分查找和牛顿迭代法
问题
不使用内置的 Math.sqrt(),实现一个计算平方根的函数。
解答
方法一:二分查找
/**
* 二分查找法求平方根
* @param {number} x - 非负数
* @param {number} precision - 精度,默认 1e-7
* @returns {number} 平方根
*/
function sqrt(x, precision = 1e-7) {
// 处理边界情况
if (x < 0) return NaN;
if (x === 0 || x === 1) return x;
let left = 0;
let right = x < 1 ? 1 : x; // x < 1 时,sqrt(x) > x
while (right - left > precision) {
const mid = (left + right) / 2;
const square = mid * mid;
if (square === x) {
return mid;
} else if (square < x) {
left = mid;
} else {
right = mid;
}
}
return (left + right) / 2;
}
// 测试
console.log(sqrt(4)); // 2
console.log(sqrt(2)); // 1.4142135...
console.log(sqrt(0.25)); // 0.5
方法二:牛顿迭代法
/**
* 牛顿迭代法求平方根
* 原理:求 f(x) = x² - n = 0 的根
* 迭代公式:x_{n+1} = x_n - f(x_n) / f'(x_n) = (x_n + n / x_n) / 2
*/
function sqrtNewton(x, precision = 1e-7) {
if (x < 0) return NaN;
if (x === 0) return 0;
let guess = x;
// 迭代直到收敛
while (Math.abs(guess * guess - x) > precision) {
guess = (guess + x / guess) / 2;
}
return guess;
}
// 测试
console.log(sqrtNewton(4)); // 2
console.log(sqrtNewton(2)); // 1.4142135...
console.log(sqrtNewton(9)); // 3
方法三:整数平方根(LeetCode 69)
/**
* 求整数平方根,只返回整数部分
* @param {number} x - 非负整数
* @returns {number} 平方根的整数部分
*/
function mySqrt(x) {
if (x < 2) return x;
let left = 1;
let right = Math.floor(x / 2);
while (left <= right) {
const mid = Math.floor((left + right) / 2);
const square = mid * mid;
if (square === x) {
return mid;
} else if (square < x) {
left = mid + 1;
} else {
right = mid - 1;
}
}
// 返回 right,因为循环结束时 right < left
// right 是最大的满足 right² <= x 的整数
return right;
}
// 测试
console.log(mySqrt(4)); // 2
console.log(mySqrt(8)); // 2 (实际是 2.828...)
console.log(mySqrt(16)); // 4
关键点
- 二分查找:在
[0, x]范围内查找,注意x < 1时上界应为 1 - 牛顿迭代:公式
guess = (guess + x / guess) / 2,收敛速度快 - 精度控制:浮点数比较要设置精度阈值,不能直接用
=== - 边界处理:负数返回 NaN,0 和 1 直接返回
- 整数版本:循环结束后返回
right,它是满足条件的最大整数
目录