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


617

我有以下虚拟测试脚本:

function test() {
  var x = 0.1 * 0.2;
  document.write(x);
}
test();

这将打印结果,0.020000000000000004而仅打印0.02(如果使用计算器)。据我了解,这是由于浮点乘法精度的错误。

有没有人有一个好的解决方案,这样在这种情况下我可以获得正确的结果0.02?我知道有类似的函数,toFixed或者四舍五入是另一种可能性,但是我真的想在不进行任何四舍五入的情况下打印出完整的数字。只是想知道你们中的一个人是否有一些不错的,优雅的解决方案。

当然,否则我将四舍五入到十位数左右。


118
实际上,该错误是因为无法映射0.1到有限的二进制浮点数。
亚伦·迪古拉09年

10
大多数分数不能精确转换为小数。一个很好的解释在这里:docs.python.org/release/2.5.1/tut/node16.html
Nate Zaugg


53
@SalmanA:您的JavaScript运行时对您隐藏了这个问题,并不意味着我错了。
亚伦·迪古拉

5
与Aaron不同,有一些方法可以完全完美地用二进制代码编码0.1。但是IEEE 754不一定对此进行定义。想象一下一种表示形式,您将一方面用二进制编码整数部分,另一方面用小数部分编码(最多n个小数),也用二进制编码,就像普通的整数> 0,最后是小数点的位置。好吧,您将完美地表示0.1,没有错误。顺便说一句,由于JS内部使用了有限数量的小数,因此他们的开发人员也可能对胆量进行了编码,以免在最后的小数上犯该错误。
法比恩·哈达迪

Answers:


469

浮点指南

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

这取决于您正在执行哪种计算。

  • 如果您确实需要精确地将结果相加,尤其是在使用金钱时,请使用特殊的十进制数据类型。
  • 如果您只是不想看到所有这些多余的小数位:只需在显示结果时将结果的格式四舍五入为固定的小数位数即可。
  • 如果没有可用的十进制数据类型,则替代方法是使用整数,例如,完全用美分进行货币计算。但这是更多的工作,并且有一些缺点。

请注意,只有在您确实需要特定的精确十进制行为时,第一点才适用。大多数人并不需要它们,只是因为他们的程序无法正确处理1/10之类的数字而感到恼火,却没有意识到如果发生1/3,即使出现相同的错误也不会眨眼。

如果第一点确实适用于您,请对JavaScript使用BigDecimal,这一点都不优雅,但实际上可以解决问题,而不是提供不完善的解决方法。


11
我注意到您的BigDecimal链接已死,并且在寻找镜像时,我发现了一个名为BigNumber的备用链接:jsfromhell.com/classes/bignumber
Jacksonkr 2011年

4
@ bass-t:是的,但是浮点数可以精确地表示直至有效位数长度的整数,并且根据ECMA标准,它是64位浮点数。因此它可以精确地表示最大为2 ^ 52的整数
Michael Borgwardt 2012年

5
@Karl:十进制小数1/10不能表示为以2为底的有限二进制分数,这就是Javascript数字。因此,实际上这完全相同的问题。
Michael Borgwardt 2014年

12
我今天了解到,即使整数在javascript中也存在精度问题。考虑console.log(9332654729891549)实际打印9332654729891548(即

12
@mlathe:Doh ;P.....在2⁵²= 4,503,599,627,370,4962⁵³=之间9,007,199,254,740,992,可表示的数字恰好是整数。在接下来的范围内,从2⁵³2⁵⁴,一切都乘以2的,所以表示的数字是甚至是那些等等。相反,对于先前的范围2⁵¹2⁵²,间距0.5等等。这是由于单纯增加|减少基地| / 64位浮点值中的基数2 |二进制指数(这反过来解释了和toPrecision()之间的值很少记录的“意外”行为)。01
GitaarLAB '16

125

我喜欢Pedro Ladaria的解决方案,并使用类似的方法。

function strip(number) {
    return (parseFloat(number).toPrecision(12));
}

与Pedros解决方案不同,此方法将舍入为0.999 ...重复,并且精确到最低有效数字的正负一一。

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


21
为何选择12个原因?
qwertymk

17
toPrecision返回字符串而不是数字。这可能并不总是令人满意的。
SStanley '16

7
parseFloat(1.005).toPrecision(3)=> 1.00-
彼得

5
@ user2428118,我知道,我的意思是显示舍入错误,结果是1.00而不是1.01
Peter

9
@ user2428118所说的内容可能不够明显:(9.99*5).toPrecision(2)= 50而不是49.95,因为toPrecision会计算整数,而不仅仅是小数。然后toPrecision(4),您可以使用,但是如果结果大于100,则您再一次不走运,因为它将允许前三个数字和一个十进制数,以这种方式移动点,并使其或多或少变得不可用。我最终toFixed(2)改用了
aexl

79

对于数学倾向: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

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

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

在这种情况下:

> Math.m(0.1, 0.2)
0.02

我绝对建议使用经过测试的库,例如SinfulJS


1
Il喜欢这种优雅的解决方法,但似乎并不完美:jsfiddle.net/Dm6F5/1 Math.a(76.65,38.45)返回115.10000000000002
nicolallias 2014年

3
Math.m(10,2332226616)给我“ -19627406800”,这是一个负值...我希望必须有一个上限-可能是引起此问题的原因。请建议
Shiva Komuravelly 2014年

1
这一切看起来不错,但似乎某个地方有一个或两个错误。
MrYellow'3

5
他说,很快就解决了。。。
Cozzbie 2015年

2
不要使用上面的代码。如果它不起作用,那绝对不是一个“快速解决方案”。这是一个与数学有关的问题,因此需要准确性。
德雷奈

49

您仅执行乘法吗?如果是这样,那么您可以利用有关十进制算术的巧妙秘密。就是那个NumberOfDecimals(X) + NumberOfDecimals(Y) = ExpectedNumberOfDecimals。就是说,如果有的0.123 * 0.12话,我们知道会有5个小数位,因为0.123有3个小数位和0.122 个小数位。因此,如果JavaScript给我们一个像0.014760000002我们可以安全舍入到小数点后第五位的数字,而不必担心失去精度。


6
...以及如何获得精确的小数位数。
line-o

7
0.5 * 0.2 = 0.10; 您仍然可以截断2个小数位(或更少)。但是,除此定律外,再没有其他任何数学意义的数字了。
Nate Zaugg 2014年

3
你为此被引用吗?还要注意,除法并非如此。
格里芬2015年

3
@NateZaugg您不能截断溢出的小数,必须四舍五入,因为2090.5 * 8.61是17999.205,但在浮动中是17999.204999999998
Lostfields

3
@Lostfields-你是对的!我已经更新了答案。
内特·扎格

29

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

尝试javascript-sprintf,您将这样称呼它:

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

以小数点后两位小数的形式打印您的数字。

如果您不想仅出于浮点舍入到给定精度的目的而添加更多文件,也可以将 Number.toFixed()用于显示目的。


4
我认为这是最干净的解决方案。除非您确实真正需要将结果设为0.02,否则小错误可以忽略不计。听起来很重要的一点是,数字要显示得很好,而不是任意精度。
长欧阳

2
对于显示,这确实是最好的选择,对于复杂的计算,请查看Borgwardt的答案。
不可用

4
但是再一次,它将返回与yourNumber.toFixed(2)完全相同的字符串。
罗伯特2010年

27

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

一个JavaScript库,用于任意精度的十进制和非十进制算术。

它具有良好的文档,作者非常努力地回应反馈。

同一位作者有2个其他类似的库:

Big.js

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

Decimal.js

JavaScript的任意精度的十进制类型。

这是一些使用BigNumber的代码:

$(function(){

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

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


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


3
我认为,使用库绝对是最佳选择。
安东尼

1
从此链接github.com/MikeMcl/big.js/issues/45 bignumber.js->金融十进制.js->科学big.js-> ???
VEE

20
var times = function (a, b) {
    return Math.round((a * b) * 100)/100;
};

- -要么 - -

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

fpFix(0.1*0.2); // -> 0.02

- -也 - -

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

    return Math.round(n * 100)/100;
};

---如-

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

4
我认为结果将带来同样的问题。您返回一个浮点数,因此返回值很有可能也是“不正确的”。
Gertjan

1
+1非常聪明和有用。
Jonatas Walker

18

此函数将通过两个浮点数的乘积确定所需的精度,并以适当的精度返回结果。优雅,虽然不是。

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

真是的 是的,让我们将数字转换为字符串以进行浮点数学运算,并且还建议将其作为答案。
安德鲁

16

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

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

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;
}
button{
display: block;
}
<input type='text' value='0.1'>
<input type='text' value='0.2'>
<button>Get Product</button>
<input type='text'>

更新:Aug / 20/2019刚刚注意到此错误。我相信这是由于Math.round()的浮点精度错误引起的。

precisionRound(1.005, 2) // produces 1, incorrect, should be 1.01

这些条件正常工作:

precisionRound(0.005, 2) // produces 0.01
precisionRound(1.0005, 3) // produces 1.001
precisionRound(1234.5, 0) // produces 1235
precisionRound(1234.5, -1) // produces 1230

固定:

function precisionRoundMod(number, precision) {
  var factor = Math.pow(10, precision);
  var n = precision < 0 ? number : 0.01 / factor + number;
  return Math.round( n * factor) / factor;
}

四舍五入时,这只会在右边添加一个数字。MDN更新了Math.round页面,因此也许有人可以提供更好的解决方案。


错误的答案。10.2将始终返回10.19。jsbin.com/tozogiwide/edit?html,js,console,output
Žilvinas

@Žilvinas您发布的JSBin链接未使用上面列出的MDN函数。我认为您的评论是针对错误的人的。
HelloWorldPeace

13

您只需要确定自己实际需要多少个小数位-不能再吃蛋糕了:-)

每次执行进一步的操作时,都会累积数值误差,如果您不尽早将其切断,它将不断增加。数字库显示的结果看上去很干净,每一步都将最后两位数字截断,数字协处理器出于相同的原因也具有“正常”和“完全”长度。Cuf-off对处理器来说很便宜,但是对您而言,在脚本中非常昂贵(乘法,除法和使用pov(...))。好的数学库会提供floor(x,n)为您做截止。

因此,至少您应该使用pov(10,n)来使全局变量/常量成为常数-这意味着您决定了所需的精度:-)然后执行:

Math.floor(x*PREC_LIM)/PREC_LIM  // floor - you are cutting off, not rounding

您还可以继续进行数学运算,并且仅在最后进行截断-假设您仅显示结果而不执行if-s。如果可以这样做,那么.toFixed(...)可能会更有效率。

如果您要进行if-s /比较,并且不希望减少,那么还需要一个小的常量,通常称为eps,该常量比最大期望误差高一个小数位。假设您的截止数是最后两位小数-那么您的eps在最后一位的第三位(最低有效位第三),您可以使用它来比较结果是否在预期的eps范围内(0.02 -eps <0.1 * 0.2 <0.02 + eps)。


您也可以添加0.5来进行穷人的四舍五入:Math.floor(x * PREC_LIM + 0.5)/ PREC_LIM
cmroanirgo 2012年

不过请注意,例如Math.floor(-2.1)is -3。因此,也许使用例如Math[x<0?'ceil':'floor'](x*PREC_LIM)/PREC_LIM
MikeM

为什么要floor代替round
2015年

12

您可以使用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;

11

phpjs.org上的round()函数运行良好:http://phpjs.org/functions/round

num = .01 + .06;  // yields 0.0699999999999
rnum = round(num,12); // yields 0.07

2
@jrg按照惯例,以“ 5”结尾的数字会四舍五入到最接近的偶数(因为始终四舍五入会给您的结果带来偏差)。因此,将四舍五入到小数点后两位的4.725应该确实是4.72。
Mark A. Durham

9

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

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

非常非常简单))


可以用类似的东西工作8.22e-8 * 1.3吗?
保罗·卡尔顿

0.6 x 3 = 1.8,您将结果赋予2的代码...不好。
6

@Zyo在这种情况下返回1.8。您是如何运行的?
德莱奈

有趣。您可以在其中交换乘法和除法运算符,它也可以工作。
安德鲁

9

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

0.1 + 0.2 === 0.3 // which returns false

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

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

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


在我的情况下,Number.EPSILON太小,导致例如0.9 !== 0.8999999761581421
Tom

8

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

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

如果要处理浮点数,总是会产生较小的舍入误差,因此,您还必须始终将显示的结果舍入到合理的值。作为回报,您将获得非常非常快速且功能强大的算法,因为所有计算都在处理器的本机二进制文件中。

大多数情况下,解决方案不是切换到定点算法,主要是因为它速度慢得多,而且99%的时间中您根本不需要精度。如果您要处理的确需要这种级别的准确性(例如金融交易),则Javascript可能不是最佳的使用工具(因为您要强制使用定点类型,因此静态语言可能会更好) )。

您正在寻找一种优雅的解决方案,那么恐怕就是这样:浮点数很快,但是舍入误差很小-在显示结果时总是舍入到合理的值。


8

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

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


7

问题

浮点不能完全存储所有十进制值。因此,当使用浮点格式时,在输入值上将始终存在舍入误差。输入上的错误当然会导致输出上的错误。如果是离散函数或运算符,则在函数或运算符离散点附近的输出上可能会有很大差异。

浮点值的输入和输出

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

  • 将输入取整到期望的精度,或者确保不能以更高的精度输入任何值。
  • 在对输出进行四舍五入/格式化之前,将一个较小的值添加到输出中,该值小于或等于所需精度的1/4,并且大于由输入和计算过程中的舍入误差引起的最大预期误差。如果不可能,则所用数据类型的精度的组合不足以为计算提供所需的输出精度。

通常不会完成这两项操作,并且在大多数情况下,由于不执行操作而导致的差异太小,以至于对于大多数用户而言都不重要,但是我已经有一个项目,如果不进行这些更正,用户将不会接受输出。

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

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

最好避免出现问题

通过将数据类型(整数或定点格式)用于此类计算(通常可以存储预期的输入而不会舍入错误),通常可以更有效地避免这些问题。一个例子是,永远不要将浮点值用于财务计算。


4

看一下定点算法。如果您要操作的数字范围较小(例如,货币),则可能会解决您的问题。我会将其四舍五入为几个十进制值,这是最简单的解决方案。


5
问题不是浮点数与固定点,而是二进制数与十进制。
Michael Borgwardt

4

尝试一下我的Chiliadic算术库,您可以在这里看到。如果您想要更高的版本,我可以帮助您。



4

在此处输入图片说明

    You can use library https://github.com/MikeMcl/decimal.js/. 
    it will   help  lot to give proper solution. 
    javascript console output 95 *722228.630 /100 = 686117.1984999999
    decimal library implementation 
    var firstNumber = new Decimal(95);
    var secondNumber = new Decimal(722228.630);
    var thirdNumber = new Decimal(100);
    var partialOutput = firstNumber.times(secondNumber);
    console.log(partialOutput);
    var output = new Decimal(partialOutput).div(thirdNumber);
    alert(output.valueOf());
    console.log(output.valueOf())== 686117.1985

3

没错,原因是浮点数的精度有限。将有理数存储为两个整数的除法,在大多数情况下,您将能够存储数字而不会造成任何精度损失。在打印时,您可能希望将结果显示为分数。通过我提出的代表性,它变得微不足道。

当然,这对于无理数不会有太大帮助。但是,您可能希望以它们引起最少问题的方式来优化计算(例如,检测诸如的情况)sqrt(3)^2)


没错,原因是浮点数的精度有限<pedant>实际上,OP将其归结为不精确的浮点运算,这是错误的</pedant>
有意思,2010年

3

我在mod 3上遇到了一个令人讨厌的舍入错误问题。有时,当我得到0时,我会得到.000 ... 01。这很容易处理,只需测试<= .01。但是有时候我会得到2.99999999999998。哎哟!

BigNumbers解决了这个问题,但引入了另一个具有讽刺意味的问题。尝试将8.5加载到BigNumbers中时,我被告知实际上是8.4999…,并且有15位以上的有效数字。这意味着BigNumbers无法接受它(我相信我提到这个问题有些具有讽刺意味)。

解决讽刺问题的简单方法:

x = Math.round(x*100);
// I only need 2 decimal places, if i needed 3 I would use 1,000, etc.
x = x / 100;
xB = new BigNumber(x);

2

使用编号(1.234443).toFixed(2); 它将打印1.23

function test(){
    var x = 0.1 * 0.2;
    document.write(Number(x).toFixed(2));
}
test();

2

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

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

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

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

链接到详细比较


2

优雅,可预测和可重复使用

让我们以一种可重用的优雅方式来解决这个问题。下面的七行代码使您只需.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

干杯!


2
如果您选择不赞成投票,请至少提供一个理由。
伯内斯托

1

采用

var x = 0.1*0.2;
 x =Math.round(x*Math.pow(10,2))/Math.pow(10,2);

4
嗯...但是请注意,这总是四舍五入到小数点后两位。那当然是一个选择,但是计算0.55 * 0.55怎么办(因为我事先不知道确切的数字。那将是0.3而不是0.3025。我当然可以使用Math.round(x*Math.pow(10,4))/Math.pow(10,4);。四舍五入总是一个选择,但是我只是想知道是否有更好的解决方案
Juri



1

这对我有用:

function round_up( value, precision ) { 
    var pow = Math.pow ( 10, precision ); 
    return ( Math.ceil ( pow * value ) + Math.ceil ( pow * value - Math.ceil ( pow * value ) ) ) / pow; 
}

round_up(341.536, 2); // 341.54

1
不幸的是,round_up(4.15,2)=> 4.16。
jrg 2014年

1

使用以下功能输出:

var toFixedCurrency = function(num){
    var num = (num).toString();
    var one = new RegExp(/\.\d{1}$/).test(num);
    var two = new RegExp(/\.\d{2,}/).test(num);
    var result = null;

    if(one){ result = num.replace(/\.(\d{1})$/, '.$10');
    } else if(two){ result = num.replace(/\.(\d{2})\d*/, '.$1');
    } else { result = num*100; }

    return result;
}

function test(){
    var x = 0.1 * 0.2;
    document.write(toFixedCurrency(x));
}

test();

注意输出toFixedCurrency(x)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.