首页 > 解决方案 > 猫鼬。正确增量四舍五入到 2 位数

问题描述

猫鼬:v5.11.11,Nodejs:v12.18.3

const Schema = new Schema({ 
    total: {
        type: Number,
        set: v => Math.round(v * 100) / 100,
        default: 8.01,
    }
let myController = (id, addValue) => model.findByIdAndUpdate(id, { $inc: { total: addValue } })
myController(111, 0.29) 

我们在 db { total : 8.299999999999999 } 中得到一个值,而不是 8.30

标签: node.jsmongoosemongoose-schema

解决方案


对于解决方案,setter如果您使用 ,您将不会被触发findByIdAndUpdate,而是您需要查询对象,编辑它然后保存它。

以下是关于为什么 8.01 + 0.29 != 8.30 的解释。

JavaScript 数字始终存储为双精度浮点数,遵循国际 IEEE 754 标准。这就是为什么浮点运算并不总是 100% 准确的原因!

让我们深入研究一下。我们可以像这样将十进制数转换为二进制数:

// output: "1000.010011001100110011001100110011001100110011001101"
8.30.toString(2)

如您所见,总共有 52 个数字字符。

我们可以使用以下函数将二进制转换回十进制:

function transformIntegerPart(str) {
    let ret = 0;
    let len = str.length;
    str.split('').forEach((d, i) => {
        if (d === '1') ret += Math.pow(2, len - i - 1);
    });
    return ret;
}
function transformDecimalPart(str) {
    let ret = 0;
    str.split('').forEach((d, i) => {
        if (d === '1') ret += Math.pow(2, -1 - i);
    });
    return ret;
}

// for 8.30,
// real integer part is
transformIntegerPart('1000') // output: 8
// real decimal part is
transformDecimalPart('010011001100110011001100110011001100110011001101') // output: 0.3000000000000007 (not actually, javascript adjust this precision automatically)

// so, the real 8.30 in javascript is 8.3000000000000007...
8.30.toPrecision(20) // output: 8.3000000000000007105

现在,我们可以回答您的问题:

// output: "1000.0000001010001111010111000010100011110101110000101"
8.01.toString(2);
// output: "0.010010100011110101110000101000111101011100001010001111"
0.29.toString(2);

let integerPart = transformIntegerPart('1000') + transformIntegerPart('0');
console.log(integerPart); // output: 8

let decimalPart = transformDecimalPart('0000001010001111010111000010100011110101110000101') + transformDecimalPart('010010100011110101110000101000111101011100001010001111');
console.log(decimalPart); // output: 0.29999999999999977

// output: 8.299999999999999
console.log(integerPart + decimalPart);

推荐阅读