如何处理JavaScript中的浮点数精度?

Jur*_*uri 552 javascript floating-point

我有以下虚拟测试脚本:

function test() {
  var x = 0.1 * 0.2;
  document.write(x);
}
test();
Run Code Online (Sandbox Code Playgroud)

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

有没有人有一个很好的解决方案,以便在这种情况下,我得到正确的结果0.02?我知道有类似的功能toFixed或舍入将是另一种可能性,但我想真正打印整个数字没有任何切割和舍入.只是想知道你们其中一个人是否有一些漂亮,优雅的解决方案.

当然,否则我会转到大约10位左右.

Mic*_*rdt 444

浮点指南:

我该怎么做才能避免这个问题?

这取决于你正在做什么样的计算.

  • 如果你真的需要你的结果准确地加起来,特别是当你使用钱时:使用特殊的十进制数据类型.
  • 如果您只是不想看到所有这些额外的小数位:只需将结果格式化为显示它时固定的小数位数.
  • 如果您没有可用的十进制数据类型,则可以选择使用整数,例如完全以美分进行货币计算.但这是更多的工作,并有一些缺点.

请注意,第一点仅适用于您确实需要特定的精确十进制行为.大多数人并不需要这样,他们只是因为他们的程序无法正常使用1/10这样的数字而没有意识到如果1/3发生他们甚至不会眨眼同样的错误.

如果第一点确实适用于您,请使用BigDecimal for JavaScript,这根本不是优雅的,但实际上解决了问题,而不是提供不完美的解决方法.

  • 我注意到BigDecimal的死链接,在寻找镜像时,我找到了一个名为BigNumber的替代方案:http://jsfromhell.com/classes/bignumber (9认同)
  • 我今天了解到即使整数在javascript中也存在精度问题.考虑一下`console.log(9332654729891549)`实际打印`9332654729891548`(即关闭一个!) (9认同)
  • @mlathe:Doh ..`; P` ...在`2⁵²`=`4,503,599,627,370,496`和`2⁵³`=`9,007,199,254,740,992`之间,可表示的数字是*正好是整数*.对于下一个范围,从"2⁵³"到"2",所有内容都*乘以"2"*,因此可表示的数字是*偶数*,*等.*相反,对于之前的范围从`2⁵¹`到`2⁵²`,间距为'0.5`,*等.*这是由于简单地增加了64位浮点值的基数2 |二进制*指数*(这反过来解释了很少记录`toPrecision()`的"意外"行为,表示"0"和"1"之间的值. (9认同)
  • @Karl:十进制小数1/10不能表示为基数2中的有限二进制小数,这就是Javascript数.所以**实际上是完全相同的问题. (5认同)
  • @ bass-t:是的,但是浮点数可以精确地表示有效数字长度的整数,并且根据ECMA标准,它是64位浮点数.因此它可以精确地表示最多2 ^ 52的整数 (4认同)
  • @ Jus12:整数溢出导致环绕 - *真的*讨厌,如果它在生产中发生.并且您无法处理具有不同拆分的货币(一些具有1000个子单元而不是100个). (3认同)
  • @MichaelBorgwardt:实际上,最多2 ^ 53,因为前导'1'位没有明确表示. (3认同)
  • 在美分工作似乎是一个很好的快速解决方案,但事实上,它并不完美.我正在使用货币,例如,9830.45*100 = 983045.0000000001. (3认同)
  • 通过查看BigDecimal,发现[BigJS](https://github.com/MikeMcl/big.js) (2认同)
  • @MichaelBorgwardt,在需要向人类展示结果的那一刻,它变得**错误**,而不仅仅是“令人恼火”。 (2认同)
  • 我最近一直在使用[decimal.js](https://github.com/MikeMcl/decimal.js).在我看来,它是一个更好的BigNumber版本,具有非常好的文档和API. (2认同)

小智 113

我喜欢Pedro Ladaria的解决方案并使用类似的东西.

function strip(number) {
    return (parseFloat(number).toPrecision(12));
}
Run Code Online (Sandbox Code Playgroud)

与Pedros解决方案不同,这将向上舍入0.999 ...重复并且在最低有效数字上精确到正/负1.

注意:处理32位或64位浮点数时,应使用toPrecision(7)和toPrecision(15)以获得最佳结果.有关原因,请参阅此问题.

  • 你选12的原因是什么? (19认同)
  • `toPrecision`返回一个字符串而不是一个数字.这可能并不总是令人满意的. (13认同)
  • parseFloat(1.005).toPrecision(3)=> 1.00 (5认同)
  • @ user2428118所说的可能不够明显:`(9.99*5).toPrecision(2)`=**50**而不是**49.95**因为toPrecision计算整数,而不仅仅是小数.然后你可以使用`toPrecision(4)`,但是如果你的结果是> 100,那么你再次失去运气,因为它将允许前三个数字和一个小数,这样就可以移动点,并渲染更多或者更少的无法使用.我最终使用`toFixed(2)`代替 (5认同)
  • @ user2428118,我知道,我的意思是显示舍入误差,结果是1.00而不是1.01 (4认同)
  • 不要使用 .toPrecision,这确实是不好的做法!parseFloat(1.005).toPrecision(4) 返回 => '1.005' parseFloat(11.005).toPrecision(4) 返回 => '11.01' (3认同)
  • @Peter 小数点前的数字也被计算在内。 (2认同)
  • @aexl toFixed() 并不总是有效。例如 `Number((8.04 * 25).toFixed(16)) <- 200.99999999999997` 而 `Number((8.04 * 25).toPrecision(16)) <- 201` (2认同)

She*_*tJS 67

对于数学上的倾向:http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

建议的方法是使用校正因子(乘以10的适当幂,以便算术在整数之间发生).例如,在0.1 * 0.2校正因子为的情况下,10您正在执行计算:

> var x = 0.1
> var y = 0.2
> var cf = 10
> x * y
0.020000000000000004
> (x * cf) * (y * cf) / (cf * cf)
0.02
Run Code Online (Sandbox Code Playgroud)

一个(非常快)的解决方案看起来像:

var _cf = (function() {
  function _shift(x) {
    var parts = x.toString().split('.');
    return (parts.length < 2) ? 1 : Math.pow(10, parts[1].length);
  }
  return function() { 
    return Array.prototype.reduce.call(arguments, function (prev, next) { return prev === undefined || next === undefined ? undefined : Math.max(prev, _shift (next)); }, -Infinity);
  };
})();

Math.a = function () {
  var f = _cf.apply(null, arguments); if(f === undefined) return undefined;
  function cb(x, y, i, o) { return x + f * y; }
  return Array.prototype.reduce.call(arguments, cb, 0) / f;
};

Math.s = function (l,r) { var f = _cf(l,r); return (l * f - r * f) / f; };

Math.m = function () {
  var f = _cf.apply(null, arguments);
  function cb(x, y, i, o) { return (x*f) * (y*f) / (f * f); }
  return Array.prototype.reduce.call(arguments, cb, 1);
};

Math.d = function (l,r) { var f = _cf(l,r); return (l * f) / (r * f); };
Run Code Online (Sandbox Code Playgroud)

在这种情况下:

> Math.m(0.1, 0.2)
0.02
Run Code Online (Sandbox Code Playgroud)

我绝对推荐使用像SinfulJS这样的测试库

  • 非常快速的解决方案,他说...破解修复没有人说过. (3认同)
  • 不要使用上面的代码。如果它不起作用,这绝对不是一个“快速解决方案”。这是一个与数学相关的问题,因此需要准确性。 (3认同)
  • 我喜欢这种优雅的解决方法,但似乎并不完美:http://jsfiddle.net/Dm6F5/1/ Math.a(76.65, 38.45) 返回 115.10000000000002 (2认同)
  • Math.m(10,2332226616)正在给我"-19627406800",这是一个负值...我希望必须有一个上限 - 可能是导致这个问题.请建议 (2认同)
  • 这一切看起来都很棒,但似乎在某处有一两个错误。 (2认同)

Nat*_*ugg 42

你只是在进行乘法运算吗?如果是这样,那么你可以利用一个关于十进制算术的巧妙秘密.就是这样NumberOfDecimals(X) + NumberOfDecimals(Y) = ExpectedNumberOfDecimals.也就是说,如果我们有,0.123 * 0.12那么我们知道将有5个小数位,因为0.123有3个小数位并且0.12有两个.因此,如果JavaScript给了我们一个数字,0.014760000002我们可以安全地舍入到小数点后第五位而不用担心会失去精度.

  • ...以及如何获得*精确*小数位数. (6认同)
  • 0.5*0.2 = 0.10; 您仍然可以截断2位小数(或更少).但是,除了这个定律之外,永远不会有任何具有数学意义的数字. (6认同)
  • 你对此有引用吗?另请注意,除法也是如此. (3认同)
  • @NateZaugg你不能截断溢出的小数,你必须舍入金额,因为2090.5*8.61是17999.205但在浮动它是17999.204999999998 (3认同)
  • @Lostfields - 你是对的!我已经更新了我的答案. (3认同)
  • 格里芬:*a* 引文(更重要的是,一个易于理解的解释):https://www.mathsisfun.com/multiplying-decimals.html 和 http://www.math.com/school/subject1/lessons/ S1U1L5DP.html 本质上:“因为当你(我的加法:在纸上手动)乘法没有小数点时,你实际上是将小数点向右移动以使其不碍事(我的加法:对于*每个*数字)" 所以,# 为 x 移动 **plus** # 为 y 移动。 (2认同)

Dou*_*las 26

您正在寻找sprintfJavaScript 的实现,以便您可以以您期望的格式写出其中包含小错误的浮点数(因为它们以二进制格式存储).

试试javascript-sprintf,你会这样称呼它:

var yourString = sprintf("%.2f", yourNumber);
Run Code Online (Sandbox Code Playgroud)

将您的数字打印为带有两位小数的浮点数.

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

  • 我认为这是最干净的解决方案.除非你真的需要结果为0.02,否则小误差可以忽略不计.听起来重要的是你的数字*很好地显示*,而不是你有任意精度. (4认同)
  • 但是,这将再次返回与YourNumber.toFixed(2)完全相同的字符串. (4认同)
  • 对于显示,这确实是最佳选择,对于复杂的计算,请检查Borgwardt的答案. (2认同)

Ron*_*rby 19

我发现BigNumber.js符合我的需求.

用于任意精度十进制和非十进制算术的JavaScript库.

它具有良好的文档,作者非常勤奋地回应反馈.

该作者有2个其他类似的库:

Big.js

用于任意精度十进制算术的小型,快速JavaScript库.bignumber.js的小妹妹.

Decimal.js

JavaScript的任意精度Decimal类型.

这是使用BigNumber的一些代码:

$(function(){

  
  var product = BigNumber(.1).times(.2);  
  $('#product').text(product);

  var sum = BigNumber(.1).plus(.2);  
  $('#sum').text(sum);


});
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<!-- 1.4.1 is not the current version, but works for this example. -->
<script src="http://cdn.bootcss.com/bignumber.js/1.4.1/bignumber.min.js"></script>

.1 &times; .2 = <span id="product"></span><br>
.1 &plus; .2 = <span id="sum"></span><br>
Run Code Online (Sandbox Code Playgroud)

  • 我认为,使用库绝对是最佳选择。 (2认同)

sha*_*mas 15

var times = function (a, b) {
    return Math.round((a * b) * 100)/100;
};
Run Code Online (Sandbox Code Playgroud)

- -要么 - -

var fpFix = function (n) {
    return Math.round(n * 100)/100;
};

fpFix(0.1*0.2); // -> 0.02
Run Code Online (Sandbox Code Playgroud)

- -也 - -

var fpArithmetic = function (op, x, y) {
    var n = {
            '*': x * y,
            '-': x - y,
            '+': x + y,
            '/': x / y
        }[op];        

    return Math.round(n * 100)/100;
};
Run Code Online (Sandbox Code Playgroud)

---如---

fpArithmetic('*', 0.1, 0.2);
// 0.02

fpArithmetic('+', 0.1, 0.2);
// 0.3

fpArithmetic('-', 0.1, 0.2);
// -0.1

fpArithmetic('/', 0.2, 0.1);
// 2
Run Code Online (Sandbox Code Playgroud)

  • 我认为这会产生同样的问题.你返回一个浮点,所以很有可能返回值也是"不正确". (2认同)
  • 非常聪明和有用,+1。 (2认同)

Gab*_*iel 14

此函数将根据两个浮点数的乘法确定所需的精度,并以适当的精度返回结果.优雅虽然不是.

function multFloats(a,b){
  var atens = Math.pow(10,String(a).length - String(a).indexOf('.') - 1), 
      btens = Math.pow(10,String(b).length - String(b).indexOf('.') - 1); 
  return (a * atens) * (b * btens) / (atens * btens); 
}
Run Code Online (Sandbox Code Playgroud)


ZXX*_*ZXX 11

你只需要决定你实际想要多少个十进制数字 - 不能吃蛋糕也吃掉它:-)

数字误差随着每一次进一步的操作而累积,如果你不早点切断,它就会增长.呈现干净的结果的数值库在每一步都简单地切断了最后两位数字,数字协处理器也具有"正常"和"完整"长度,原因相同.Cuf-offs对于处理器来说很便宜,但对于脚本来说非常昂贵(乘法和分割以及使用pov(...)).好的数学库会提供楼层(x,n)来为你做截止.

所以至少你应该用pov(10,n)创建全局变量/常量 - 这意味着你决定了你需要的精度:-)那么:

Math.floor(x*PREC_LIM)/PREC_LIM  // floor - you are cutting off, not rounding
Run Code Online (Sandbox Code Playgroud)

你也可以继续做数学并且只在最后切断 - 假设你只是显示而不是if-s结果.如果你能做到这一点,那么.toFixed(...)可能会更有效率.

如果你正在进行if-s /比较并且不想切割那么你还需要一个小常量,通常称为eps,它比最大预期误差高一位小数.假设您的截止时间是最后两位小数 - 那么您的eps在最后一位(第三位最低位)的第3位有1,您可以用它来比较结果是否在预期的eps范围内(0.02 -eps <0.1)*0.2 <0.02 + eps).


Hel*_*ace 11

令人惊讶的是,此功能尚未发布,尽管其他功能也有类似的变化.它来自Math.round()的MDN Web文档.它简洁,允许不同的精度.

function precisionRound(number, precision) {
  var factor = Math.pow(10, precision);
  return Math.round(number * factor) / factor;
}
Run Code Online (Sandbox Code Playgroud)

console.log(precisionRound(1234.5678,1)); //预期产量:1234.6

console.log(precisionRound(1234.5678,-1)); //预期产量:1230

var inp = document.querySelectorAll('input');
var btn = document.querySelector('button');

btn.onclick = function(){
  inp[2].value = precisionRound( parseFloat(inp[0].value) * parseFloat(inp[1].value) , 5 );
};

//MDN function
function precisionRound(number, precision) {
  var factor = Math.pow(10, precision);
  return Math.round(number * factor) / factor;
}
Run Code Online (Sandbox Code Playgroud)
button{
display: block;
}
Run Code Online (Sandbox Code Playgroud)
<input type='text' value='0.1'>
<input type='text' value='0.2'>
<button>Get Product</button>
<input type='text'>
Run Code Online (Sandbox Code Playgroud)


小智 9

phpjs.org中的round()函数效果很好:http://phpjs.org/functions/round

num = .01 + .06;  // yields 0.0699999999999
rnum = round(num,12); // yields 0.07
Run Code Online (Sandbox Code Playgroud)

  • @jrg 按照惯例,以“5”结尾的数字会四舍五入到最接近的偶数(因为总是向上或向下四舍五入会给您的结果带来偏差)。因此,四舍五入到小数点后两位的 4.725 确实应该是 4.72。 (2认同)

Pet*_*ter 8

不优雅,但可以完成工作(删除尾随零)

var num = 0.1*0.2;
alert(parseFloat(num.toFixed(10))); // shows 0.02
Run Code Online (Sandbox Code Playgroud)

  • toFixed 并不总是有效:http://stackoverflow.com/questions/661562/how-to-format-a-float-in-javascript/661757#661757 (8认同)

Sim*_*mon 8

我解决这个问题的方法是首先将两个数字都设为整数,执行表达式,然后将结果相除以取回小数位:

function evalMathematicalExpression(a, b, op) {
    const smallest = String(a < b ? a : b);
    const factor = smallest.length - smallest.indexOf('.');

    for (let i = 0; i < factor; i++) {
        b *= 10;
        a *= 10;
    }

    a = Math.round(a);
    b = Math.round(b);
    const m = 10 ** factor;
    switch (op) {
        case '+':
            return (a + b) / m;
        case '-':
            return (a - b) / m;
        case '*':
            return (a * b) / (m ** 2);
        case '/':
            return a / b;
    }

    throw `Unknown operator ${op}`;
}
Run Code Online (Sandbox Code Playgroud)

多项操作的结果(排除的数字是来自 的结果eval):

0.1 + 0.002   = 0.102 (0.10200000000000001)
53 + 1000     = 1053 (1053)
0.1 - 0.3     = -0.2 (-0.19999999999999998)
53 - -1000    = 1053 (1053)
0.3 * 0.0003  = 0.00009 (0.00008999999999999999)
100 * 25      = 2500 (2500)
0.9 / 0.03    = 30 (30.000000000000004)
100 / 50      = 2 (2)
Run Code Online (Sandbox Code Playgroud)


use*_*632 7

请注意,对于一般用途,此行为可能是可以接受的。
比较那些浮点值以确定适当的操作时会出现问题。
随着ES6的到来,Number.EPSILON定义了一个新的常量来确定可接受的误差范围:
因此,而不是像这样执行比较

0.1 + 0.2 === 0.3 // which returns false
Run Code Online (Sandbox Code Playgroud)

您可以定义一个自定义比较功能,如下所示:

function epsEqu(x, y) {
    return Math.abs(x - y) < Number.EPSILON;
}
console.log(epsEqu(0.1+0.2, 0.3)); // true
Run Code Online (Sandbox Code Playgroud)

资料来源:http : //2ality.com/2015/04/numbers-math-es6.html#numberepsilon


Eri*_*sta 7

decimal.jsbig.jsbignumber.js可用于避免 Javascript 中的浮点操作问题:

0.1 * 0.2                                // 0.020000000000000004
x = new Decimal(0.1)
y = x.times(0.2)                          // '0.2'
x.times(0.2).equals(0.2)                  // true
Run Code Online (Sandbox Code Playgroud)

big.js:极简主义;便于使用; 以小数位指定的精度;精度仅适用于除法。

bignumber.js:基数 2-64;配置选项;南;无限; 以小数位指定的精度;精度仅适用于除法;基本前缀。

decimal.js:以 2-64 为基数;配置选项;南;无限; 非整数幂、exp、ln、log;以有效数字指定的精度;始终应用精度;随机数。

详细比较的链接


Kei*_*ith 6

您获得的结果在不同语言,处理器和操作系统中的浮点实现之间是正确且相当一致的 - 唯一改变的是浮点实际上是双倍(或更高)时的不准确程度.

二进制浮点数为0.1就像十进制的1/3(即0.3333333333333 ......永远),没有准确的方法来处理它.

如果你正在处理浮点数总是期望小的舍入误差,所以你也总是必须将显示的结果舍入到合理的位置.作为回报,您将获得非常快速和强大的算术,因为所有计算都在处理器的本机二进制中.

大多数情况下,解决方案不是切换到定点运算,主要是因为它更慢,99%的时间你不需要精度.如果你正在处理需要那种准确度的东西(比如金融交易),那么Javascript可能不是最好的工具(因为你想强制执行定点类型,静态语言可能更好) ).

你正在寻找优雅的解决方案然后我担心这就是它:浮动很快但是有小的舍入错误 - 在显示结果时总是圆润到合理的东西.


Ger*_*jan 6

为避免这种情况,您应该使用整数值而不是浮点数.因此,当您希望2个位置精度使用值*100时,3个位置使用1000.显示时使用格式化程序放入分隔符.

许多系统以这种方式省略了使用小数.这就是为什么许多系统使用美分(作为整数)而不是美元/欧元(作为浮点数)的原因.


Оле*_*ьев 6

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

function dec( num )
{
    var p = 100;
    return Math.round( num * p ) / p;
}
Run Code Online (Sandbox Code Playgroud)

非常非常简单))


Sof*_*ddy 6

您可以使用parseFloat(),toFixed()如果您想绕过此问题进行小型操作:

a = 0.1;
b = 0.2;

a + b = 0.30000000000000004;

c = parseFloat((a+b).toFixed(2));

c = 0.3;

a = 0.3;
b = 0.2;

a - b = 0.09999999999999998;

c = parseFloat((a-b).toFixed(2));

c = 0.1;
Run Code Online (Sandbox Code Playgroud)


Ste*_*ers 6

问题

浮点不能精确存储所有十进制值.因此,当使用浮点格式时,输入值将始终存在舍入误差.输入上的错误当然会导致输出错误.在离散函数或运算符的情况下,函数或运算符离散的点周围的输出可能存在很大差异.

浮点值的输入和输出

因此,在使用浮点变量时,您应该始终注意这一点.并且在显示之前,您应该始终对浮点数计算所需的输出进行格式化/调节.
当仅使用连续函数和运算符时,通常会舍入到所需的精度(不截断).用于将浮点数转换为字符串的标准格式设置功能通常会为您执行此操作.
由于舍入会增加一个错误,导致总误差超过所需精度的一半,因此应根据输入的预期精度和所需的输出精度来校正输出.你应该

  • 将输入舍入到预期精度或确保不能以更高精度输入值.
  • 在舍入/格式化之前向输出添加一个小值,该值小于或等于所需精度的1/4,并且大于输入和计算期间的舍入误差引起的最大预期误差.如果不可能,则使用的数据类型的精度组合不足以为计算提供所需的输出精度.

这两件事通常都没有完成,在大多数情况下,由于没有这样做而导致的差异太小而不适合大多数用户,但我已经有了一个项目,如果没有这些更正,用户就不会接受输出.

离散函数或运算符(如modula)

当涉及离散运算符或函数时,可能需要额外的更正以确保输出符合预期.在舍入之前舍入并添加小的修正不能解决问题.
可能需要在应用离散函数或运算符后立即对中间计算结果进行特殊检查/校正.对于特定情况(modula运算符),请参阅我的问题答案:为什么模运算符在javascript中返回小数?

更好地避免出现问题

通过使用数据类型(整数或定点格式)进行这样的计算来避免这些问题通常更有效,这样可以存储预期的输入而不会出现舍入错误.例如,您不应该使用浮点值进行财务计算.


Ber*_*sto 6

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

让我们以一种优雅的可重用的方式来处理这个问题。.decimal接下来的七行将让您只需附加到数字、公式或内置函数的末尾即可访问任何数字所需的浮点精度Math

// First extend the native Number object to handle precision. This populates
// the functionality to all math operations.

Object.defineProperty(Number.prototype, "decimal", {
  get: function decimal() {
    Number.precision = "precision" in Number ? Number.precision : 3;
    var f = Math.pow(10, Number.precision);
    return Math.round( this * f ) / f;
  }
});


// Now lets see how it works by adjusting our global precision level and
// checking our results.

console.log("'1/3 + 1/3 + 1/3 = 1' Right?");
console.log((0.3333 + 0.3333 + 0.3333).decimal == 1); // true

console.log(0.3333.decimal); // 0.333 - A raw 4 digit decimal, trimmed to 3...

Number.precision = 3;
console.log("Precision: 3");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0.01
console.log((0.0008 + 0.0002).decimal); // 0.001

Number.precision = 2;
console.log("Precision: 2");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0.01
console.log((0.0008 + 0.0002).decimal); // 0

Number.precision = 1;
console.log("Precision: 1");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0
console.log((0.0008 + 0.0002).decimal); // 0

Number.precision = 0;
console.log("Precision: 0");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0
console.log((0.008 + 0.002).decimal); // 0
console.log((0.0008 + 0.0002).decimal); // 0
Run Code Online (Sandbox Code Playgroud)

  • 如果您选择投反对票,至少要提供一个理由。 (6认同)
  • 我没有投反对票,但是虽然这很优雅且可重用,但 JavaScript 原始类型对象的猴子补丁不太可能是可预测的。[这些](https://en.wikipedia.org/wiki/Monkey_patch#Pitfalls)中的一些担忧似乎是适用的。 (5认同)

MSN*_*MSN 5

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