javascript - 我会导致浮点精度错误吗?
问题描述
我有一个简单(也许很天真)的问题 - 我正在尝试测试一个场景,并且想知道在将字符串解析为数字时是否可能导致浮点精度错误(是否存在会导致 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)
解决方案
将字符串中的十进制数转换为二进制浮点数是一项操作,它确实会产生“精度错误”。如果源数字不能以目标格式表示,则对其进行四舍五入。
在您展示的示例中,每个操作都有一个舍入错误,除了将源文本转换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 位的十进制数字的往返将始终产生原始数字(在格式的有限范围内)。
推荐阅读
- amazon-web-services - Terraform:为什么 AWS NAT 网关与仅出口 Internet 网关冲突
- c#-4.0 - 通过将这些 pdf 合并到 SSRS 报告来将上传的 pdf 文件添加到 SSRS 报告的正确方法是什么
- html - 我们如何称呼这个由三个水平点组成的小部件?
- azure - 无法使用 packer chef-client provisioner 从 chef-client 连接到 chef-server
- reactjs - 模拟搜索并选择一个选项 react-select
- php - 如何在 WordPress 中延迟第三方屏幕外图像
- java - 线程和同步
- c# - .NET5/Core 下的 Linux 进程输出重定向导致不正确/损坏的行为
- c# - 按我们想要的特定顺序对 DataTable 的行进行排序
- python - Pyspark 日期格式