面试题答案
一键面试浮点数精度问题原理
在JavaScript中,数字以IEEE 754标准的64位双精度格式存储。这种格式将数字分为符号位、指数位和尾数位。对于小数部分,由于二进制无法精确表示某些十进制小数(如0.1),会产生舍入误差。
例如,0.1的二进制表示是一个无限循环小数:0.0001100110011...,在64位双精度格式中存储时只能截取有限位,导致精度丢失。当进行0.1 + 0.2运算时,两个数在二进制表示下的精度丢失积累起来,使得结果与预期的0.3在二进制表示上存在差异,从而导致 0.1 + 0.2!== 0.3
。
精确加法函数
function add(a, b) {
// 计算两个数的小数部分的最大位数
const getDecimalLength = num => {
const match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
if (!match) { return 0; }
return Math.max(
0,
(match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0)
);
};
const decimalLengthA = getDecimalLength(a);
const decimalLengthB = getDecimalLength(b);
const maxDecimalLength = Math.max(decimalLengthA, decimalLengthB);
// 将两个数扩大为整数
const multiplier = Math.pow(10, maxDecimalLength);
const intA = Math.round(a * multiplier);
const intB = Math.round(b * multiplier);
// 处理边界情况,如接近Number.MIN_VALUE和Number.MAX_VALUE的数
if (intA === 0 && a!== 0) {
return b;
}
if (intB === 0 && b!== 0) {
return a;
}
if (intA + intB > Number.MAX_SAFE_INTEGER) {
throw new Error('数值过大,超出安全范围');
}
// 进行整数加法并转换回小数
return (intA + intB) / multiplier;
}