我有以下虚拟测试脚本:

函数测试(){变量x=0.1*0.2;document.write(x);}测试();

这将打印结果0.020000000000000004,而它应该只打印0.02(如果您使用计算器)。据我所知,这是由于浮点乘法精度的错误。

有没有人有一个好的解决方案,在这种情况下,我得到了正确的结果0.02?我知道还有一些函数,比如toFixed或舍入,这是另一种可能,但我真的希望在不进行任何切割和舍入的情况下打印整个数字。我只是想知道你们中的一个人是否有一些好的、优雅的解决方案。

当然,否则我会舍入到10位数左右。


当前回答

您正在寻找JavaScript的sprintf实现,这样您就可以以期望的格式写出带有小错误的浮点数(因为它们是以二进制格式存储的)。

试试javascript sprintf,你可以这样称呼它:

var yourString = sprintf("%.2f", yourNumber);

将数字打印为带有两个小数点的浮点数。

如果您不希望仅为浮点舍入到给定精度而包含更多文件,也可以使用Number.toFixed()进行显示。

其他回答

我不太擅长编程,但对这个主题很感兴趣,所以我试图了解如何在不使用任何库或脚本的情况下解决这个问题

我在草稿栏上写的

var toAlgebraic = function(f1, f2) {
    let f1_base = Math.pow(10, f1.split('.')[1].length);
    let f2_base = Math.pow(10, f2.split('.')[1].length);
    f1 = parseInt(f1.replace('.', ''));
    f2 = parseInt(f2.replace('.', ''));

    let dif, base;
    if (f1_base > f2_base) {
        dif = f1_base / f2_base;
        base = f1_base;
        f2 = f2 * dif;
    } else {
        dif = f2_base / f1_base;
        base = f2_base;
        f1 = f1 * dif;
    }

    return (f1 * f2) / base;
};

console.log(0.1 * 0.2);
console.log(toAlgebraic("0.1", "0.2"));

您可能需要重构此代码,因为我不擅长编程:)

你是对的,原因是浮点数的精度有限。将有理数存储为两个整数的除法,在大多数情况下,您可以存储数字而不损失任何精度。在打印时,您可能希望将结果显示为分数。有了我提出的表示法,它就变得微不足道了。

当然,这对非理性数字没有太大帮助。但您可能希望优化您的计算,使其产生的问题最少(例如,检测sqrt(3)^2等情况)。

我喜欢带有修正系数的方法,这里是我对ES6和ES5标准的简短决定。与toFixed方法相比,它的优势在于,如果我们想舍入到数百,它不会在数字末尾留下不必要的零,但结果数字是第十个数字:

ES6变体:

// .1 + .2
((a,b,crr) => (a*crr + b*crr)/crr)(.1,.2,100/*correction factor*/);//0.3
// .1 * .2
((a,b,crr) => a*crr*b/crr)(.1,.2,100);//0.02

ES5变体:

// .1 + .2
(function(a,b,crr){ return (a*crr + b*crr)/crr; })(.1,.2,100/*correction factor*/);//0.3
// .1 * .2
(function(a,b,crr){ return a*crr*b/crr; })(.1,.2,100);//0.02

优雅、可预测、可重复使用

让我们以一种优雅的、可重用的方式来处理这个问题。通过在数字、公式或内置Math函数的末尾添加.dedecimal,以下七行将允许您访问任意数字所需的浮点精度。

//首先扩展本机Number对象以处理精度。这将填充//所有数学运算的功能。Object.defineProperty(Number.prototype,“decimal”{get:函数decimal(){Number.precision=数字中的“精度”?数字精度:3;var f=数学.pow(10,数字精度);return Math.round(this*f)/f;}});//现在让我们来看看它是如何通过调整我们的全球精度水平和//检查我们的结果。console.log(“'1/3+1/3+1/3=1'对吗?”);console.log((0.3333+0.3333+0.3333).decimal==1);//真的console.log(0.3333.decimal);//0.333-一个原始的4位小数,修剪为3。。。数字精度=3;console.log(“精度:3”);console.log((0.8+0.2).dedecimal);//1.console.log((0.08+0.02).decimal);//0.1控制台日志((0.008+0.002)十进制);//0.01console.log((0.0008+0.0002).decimal);//0.001数字精度=2;console.log(“精度:2”);console.log((0.8+0.2).dedecimal);//1.console.log((0.08+0.02).decimal);//0.1控制台日志((0.008+0.002)十进制);//0.01console.log((0.0008+0.0002).decimal);//0数字精度=1;console.log(“精度:1”);console.log((0.8+0.2).dedecimal);//1.console.log((0.08+0.02).decimal);//0.1控制台日志((0.008+0.002)十进制);//0console.log((0.0008+0.0002).decimal);//0数字精度=0;console.log(“精度:0”);console.log((0.8+0.2).dedecimal);//1.console.log((0.08+0.02).decimal);//0控制台日志((0.008+0.002)十进制);//0console.log((0.0008+0.0002).decimal);//0

干杯

我的回答可能会迟到,但我的解决方案是:

函数浮点(方程式,精度=9){return Math.floor(公式*(10**精度))/(10**精确度);}console.log(浮点(0.1*0.2));//=>0.02console.log(浮点(0.2+0.4));//=>0.6console.log(浮点(1/3));//=>0.333333333console.log(浮点(1/3,2));//=>0.33