Javascript数学错误:不精确浮点

Javascript数学错误:不精确浮点,javascript,math,Javascript,Math,可能的重复项: 代码: 以上给出了1609.2的答案 var tax1= 14900*(10.8/100); alert(tax1); 以上给出的答案为1609.2000000000003 为什么??我想我可以把这些值加起来,但为什么会这样呢 更新: 找到了问题的临时解决方案 先乘: (14900*10.8)/100 = 1609.2 然而 (14898*10.8)/100 = 1608.9840000000002 为此,将10.8乘以系数(本例中为100)并调整分母: (14898*

可能的重复项:

代码:

以上给出了1609.2的答案

var tax1= 14900*(10.8/100);
alert(tax1);
以上给出的答案为1609.2000000000003

为什么??我想我可以把这些值加起来,但为什么会这样呢

更新: 找到了问题的临时解决方案

先乘:

(14900*10.8)/100 = 1609.2
然而

(14898*10.8)/100 = 1608.9840000000002
为此,将10.8乘以
系数(本例中为100)
并调整分母:

(14898*(10.8*100))/10000 = 1608.984
我想,如果一个人可以对额外的000进行预匹配,然后相应地调整因子,则可以避免浮动误差。 然而,最终的解决方案是a。

值是不精确的

这几乎就是问题的答案。精度是有限的,这意味着有些数字不能精确表示

有些语言在语言级别支持任意精度的数字类型/有理数/复数等,但不支持Javascript。C和Java都不是

IEEE 754标准浮点值不能准确表示,例如
0.1
。这就是为什么必须非常小心地使用美分等进行数值计算的原因。有时,解决方案是将以美分表示的值存储为整数,而不是以美元表示的浮点值


“浮点”概念,10进制模拟

查看浮点值为何不精确,请考虑下面的模拟:

  • 您只有足够的内存来记住5位数字
  • 您希望能够在尽可能大的范围内表示值
在表示整数时,可以表示
-99999
+99999
范围内的值。超出这些范围的值将要求您记住5位以上的数字,而这(在本例中)是您无法做到的

现在你可以考虑定点表示,比如“代码> abc”。现在,您可以表示范围在

-999.99
+999.99
之间的值,最多两位精度,例如
3.14
-456.78

现在考虑浮点版本。你足智多谋,想出了以下方案:

n=abc x 10
de

现在,您仍然只能记住5位数字
a
b
c
d
e
,但现在您可以表示更大范围的数字,甚至是非整数。例如:

123 x 10
0
=123.0

123 x 10
3
=123000.0

123x10
6
=123000000.0

123 x 10
-3
=0.123

123 x 10
-6
=0.000123

“浮点”这个名字就是这样产生的:在上面的例子中,小数点“四处浮动”

现在,您可以表示各种数字,但请注意,您不能表示
0.1234
。您也不能表示
123001.0
。事实上,有很多价值观是你无法表达的

这就是为什么浮点值是不精确的。它们可以表示范围很广的值,但由于内存有限,因此必须牺牲精度来获得大小


更多技术细节 abc
abc
称为系数/尾数。
de
是指数,也称为标度/特征。像往常一样,计算机使用基数2而不是10。除了记住“数字”(实际上是位),它还必须记住有效位和指数的符号

单精度浮点类型通常使用32位。双精度通常使用64位

另见
    • 此外

      让JavaScript计算数学优先级,没有理由使用括号:

      var tax1 = 14900 * 10.8 / 100
      1609.2
      

      这是魔法。请记住避免使用无用的括号。

      这种行为是浮点算术固有的。这就是为什么浮点运算不适合处理需要精确的货币问题


      存在一些库,例如,它们可以帮助您将舍入错误限制到您实际需要它们的位置(表示为文本)。这些库实际上并不处理浮点值,而是处理(整数值的)分数。所以不是0.25,而是1/4等等。

      浮点值可以有效地表示比整数值范围大得多的值。然而,这是有代价的:有些值不能精确表示(因为它们是二进制存储的),例如每负10次方(0.1、0.01等)

      如果想要精确的结果,请尽量不要使用浮点运算

      当然,有时你无法避免它们。在这种情况下,一些简单的准则可以帮助您最小化舍入错误:

    • 不要减去几乎相等的值。(0.1-0.0999)
    • 首先将最大值相加或相乘。(100*10)*0.1而不是100*(10*0.1)
    • 先乘后除。(14900*10.8)/100而不是14900*(10.8/100)
    • 如果精确值可用,则使用它们而不是计算它们以获得“更漂亮”的代码

    • 是javascript还是所有的浮点都不精确?@abel:任何称为
      float
      的东西都可能是浮点类型,任何浮点类型都非常不精确。谢谢,我们使用()实现了可读性我猜也是如此,我们不鼓励您使用可读的数学语句;)我完全不同意。可读性可能是一个严重的绊脚石,当然,当涉及到数学时,能够快速看到等式的意图可能是调试怪癖的关键表示该评论是在jestAs OP中作出的,并给出了一个示例:14898*10.8/100生成1608.9840000000002我在为发票系统使用浮动。@abel不这样做。在金钱问题上,人们是非常挑剔的,如果你报复的话,你很容易失去信任
      var tax1 = 14900 * 10.8 / 100
      1609.2