首页 > 解决方案 > 我会导致浮点精度错误吗?

问题描述

我有一个简单(也许很天真)的问题 - 我正在尝试测试一个场景,并且想知道在将字符串解析为数字时是否可能导致浮点精度错误(是否存在会导致 FPPE 的幻数? )。

例如

parseFloat("4.015") // = 4.0149999999999994
const foo = 4.015 // = 4.0149999999999994

或者,是否仅可能由于操作而产生浮点精度错误?

console.log(4.015)
console.log(parseFloat("4.015"))
console.log(4.015 * 100)

标签: javascriptfloating-point

解决方案


将字符串中的十进制数转换为二进制浮点数是一项操作,它确实会产生“精度错误”。如果源数字不能以目标格式表示,则对其进行四舍五入。

在您展示的示例中,每个操作都有一个舍入错误,除了将源文本转换100为数字 100。

console.log(4.015)中,十进制数字“4.015”代表数字 4.015。当它转换为 JavaScript 使用的 IEEE-754 64 位二进制浮点时,结果为 4.01499999999999968025576890795491635799407958984375。(它有很多数字,但它实际上在内部以相当于 4520488125973135 乘以 2 −50的形式表示。)然后,为了将它打印到控制台,它从二进制浮点转换为十进制。在进行转换时,JavaScript 使用足够的十进制数字来唯一地将值与可以用二进制浮点表示的相邻值区分开来。结果是字符串“4.015”。因此二进制浮点值已四舍五入为不同的十进制值 - 生成与原始字符串相同的字符串。所以,在console.log(4.015),其实有两个转换操作,都存在舍入误差,软件的行为隐藏了舍入误差。

console.log(parseFloat("4.015"))中,发生了同样的事情,除了第一次转换是在parseFloat调用时完成的,而不是4.015在源代码中解释的时候。

console.log(4.015 * 100)中,有四次运算和三个舍入误差:

  • 4.015转换为二进制浮点数,具有上述舍入误差。
  • 100转换为二进制浮点数,并且没有舍入误差,因为 100 可以用二进制浮点数表示。
  • 两个二进制浮点数相乘,有舍入误差,产生 401.49999999999994315658113919198513031005859375。
  • 该结果将转换为十进制字符串。结果是“401.49999999999994”,因为我们需要很多数字来将其与两个相邻的可表示值 401.4999999999998863131622783839702606201171875 和 401.5 区分开来。

总之:

  • 每个操作,包括二进制和十进制之间的转换,都可能会出现舍入误差。
  • 默认的 JavaScript 格式会隐藏一些舍入错误;来自小于 16 位的十进制数字的往返将始终产生原始数字(在格式的有限范围内)。

推荐阅读