Javascript数学错误:不精确的浮点数

IT技术 javascript math
2021-03-18 13:39:26

可能的重复:
JavaScript 的数学有问题吗?
浮点数是如何存储的?什么时候重要?

代码:

var tax= 14900*(0.108);
alert(tax);

以上给出了1609.2的答案

var tax1= 14900*(10.8/100);
alert(tax1);

以上给出了1609.200000000003的答案

为什么?我想我可以四舍五入这些值,但为什么会发生这种情况?

更新: 为该问题找到了临时解决方案。

先乘:

(14900*10.8)/100 = 1609.2

然而

(14898*10.8)/100 = 1608.9840000000002

为此,将 10.8 乘以 afactor(100 in this case)并调整分母:

(14898*(10.8*100))/10000 = 1608.984

我想如果可以对额外的 000 进行 preg_match,然后相应地调整因子,则可以避免浮点错误。然而,最终的解决方案将是一个数学库

4个回答

浮点值不准确。

这几乎就是问题的答案。存在有限精度,这意味着某些数字无法准确表示。

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

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


“浮点”概念,以 10 为底的模拟

要了解为什么浮点值不精确,请考虑以下模拟:

  • 你只有足够的记忆力来记住 5 位数字
  • 您希望能够在尽可能广泛的范围内表示值

在代表整数,你可以在该范围内代表的数值-99999+99999超出这些范围的值需要您记住 5 位以上的数字,这(就本示例而言)您无法做到。

现在您可以考虑定点表示,例如abc.de现在,您可以在范围代表值-999.99,以+999.99高达2个位数的精度,例如3.14-456.78等等。

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

n = abc x 10de

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

123 x 100 = 123.0

123 x 103 = 123,000.0

123 x 106 = 123,000,000.0

123 x 10-3 = 0.123

123 x 10-6 = 0.000123

这就是“浮点”这个名字的由来:上面例子中的小数点“四处浮动”。

现在您可以表示范围广泛的数字,但请注意,您不能表示0.1234. 你也不能代表123,001.0事实上,有很多value是你无法代表的。

这几乎就是浮点值不精确的原因。它们可以表示范围很广的值,但由于您仅限于固定数量的内存,您必须牺牲精度以换取数量级。


更多技术

abc被称为有效数,又名系数/尾数de指数,又名规模/特性像往常一样,计算机使用基数 2 而不是 10。除了记住“数字”(位,真的),它还必须记住有效数和指数的符号。

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

也可以看看

它只是 javascript 还是所有的浮点数都不准确?
2021-05-12 13:39:26
@abel:任何被调用的东西float都可能是浮点类型,任何浮点类型都非常不准确。
2021-05-15 13:39:26

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

存在的库,例如这一次,它可以帮助您限制舍入误差的地方有实际需要(代表作为文本)点。这些库并不真正处理浮点值,而是处理分数(整数值)。所以不是 0.25,而是 1/4 等等。

@abel 不要。在金钱方面,人们非常挑剔,如果您得到的金额略有不同,您很容易失去信任。这是 Java 上存在 BigInteger 等的原因之一,数据库具有 Decimal(无损)数据类型,而且 javascript 也有一些库来处理它。处理这些数据类型往往很糟糕(比浮点数更多的工作:)但它是值得的。
2021-04-25 13:39:26
我在发票系统中使用浮动。
2021-04-29 13:39:26
2021-04-30 13:39:26

浮点值可用于有效表示比整数值大得多的范围内的值。然而,它是有代价的:有些值无法准确表示(因为它们是二进制存储的)例如(0.1、0.01 等)的每一个 10 的负幂

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

当然,有时您无法避免它们。在这种情况下,一些简单的指南可以帮助您最大限度地减少舍入误差:

  1. 不要减去几乎相等的值。(0.1-0.0999)
  2. 首先添加或乘以最大值。(100*10)* 0.1 而不是 100*(10*0.1)
  3. 先乘,后除。(14900*10.8)/100 而不是 14900*(10.8/100)
  4. 如果有确切的值,请使用它们而不是计算它们来获得“更漂亮”的代码

还,

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

var tax1 = 14900 * 10.8 / 100
1609.2

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

正如 OP 给你一个例子: 14898*10.8/100 产生 1608.9840000000002
2021-04-20 13:39:26
;) 表示评论是开玩笑的
2021-04-24 13:39:26
我完全不同意。可读性可能是一个严重的绊脚石,当然在数学方面,能够快速看到方程的意图对于调试怪癖至关重要。
2021-05-14 13:39:26
我猜也是一样,不鼓励你有可读的数学语句;)
2021-05-19 13:39:26
谢谢,正在使用 () 来提高可读性
2021-05-20 13:39:26