我有以下虚拟测试脚本:

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

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

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

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


当前回答

如果不想每次都调用函数,可以创建一个类来处理转换。

class Decimal {
  constructor(value = 0, scale = 4) {
    this.intervalValue = value;
    this.scale = scale;
  }

  get value() {
    return this.intervalValue;
  }

  set value(value) {
    this.intervalValue = Decimal.toDecimal(value, this.scale);
  }

  static toDecimal(val, scale) {
    const factor = 10 ** scale;
    return Math.round(val * factor) / factor;
  }
}

用法:

const d = new Decimal(0, 4);
d.value = 0.1 + 0.2;              // 0.3
d.value = 0.3 - 0.2;              // 0.1
d.value = 0.1 + 0.2 - 0.3;        // 0
d.value = 5.551115123125783e-17;  // 0
d.value = 1 / 9;                  // 0.1111

当然,在处理十进制时,需要注意:

d.value = 1/3 + 1/3 + 1/3;   // 1
d.value -= 1/3;              // 0.6667
d.value -= 1/3;              // 0.3334
d.value -= 1/3;              // 0.0001

理想情况下,您希望使用高比例(如12),然后在需要呈现或存储时将其向下转换。就我个人而言,我曾尝试创建一个UInt8Array并试图创建一个精度值(很像SQL Decimal类型),但由于Javascript不允许重载运算符,所以如果不能使用基本的数学运算符(+,-,/,*),而是使用add()、substract()、mult()等函数,就会有点乏味。为了我的需要,这不值得。

但如果您确实需要这种精度,并且愿意忍受在数学中使用函数,那么我推荐decimal.js库。

其他回答

您不能用二进制浮点类型(这是ECMAScript用来表示浮点值的)精确地表示大多数小数。因此,除非您使用任意精度的算术类型或基于小数的浮点类型,否则没有一个优雅的解决方案。例如,Windows附带的计算器应用程序现在使用任意精度算法来解决这个问题。

0.6*3太棒了!)对我来说,这很好:

function dec( num )
{
    var p = 100;
    return Math.round( num * p ) / p;
}

非常简单))

试试我的千年算术库,你可以在这里看到。如果你想要更高版本,我可以给你买一个。

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

让我们以一种优雅的、可重用的方式来处理这个问题。通过在数字、公式或内置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

干杯

避免在使用整数的操作过程中处理浮点

正如迄今为止投票最多的答案所述,你可以使用整数,这意味着你所使用的每一个小数乘以10,然后将结果除以所使用的相同数字。

例如,如果使用2个小数,则在执行运算之前,将所有因子乘以100,然后将结果除以100。

下面是一个示例,Result1是通常的结果,Result2使用解决方案:

var Factor1=“1110.7”;var Factor2=“2220.2”;var Result1=数字(因子1)+数字(因子2);var Result2=((数量(因子1)*100)+(数量(系数2)*100))/100;var Result3=(Number(parseFloat(Number(Factor1))+parseFlat(Number(Factor2))).toPecision(2));document.write(“Result1:”+Result1+“<br>Result2:”+Result2+“<br>Result3:”+Result3);

第三个结果是显示改用parseFloat时发生的情况,这在我们的案例中产生了冲突。