MST

星途 面试题库

面试题:JavaScript 算术表达式边界处理与精度问题

已知JavaScript在处理浮点数时存在精度问题,例如 `0.1 + 0.2!== 0.3`。请阐述这背后的原理,并编写一个函数来精确地处理两个浮点数的加法(考虑边界情况,如接近Number.MIN_VALUE和Number.MAX_VALUE的数)。
28.3万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

浮点数精度问题原理

在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;
}