请教大家一个关于 Java 浮点精度的问题

2023-10-21 18:21:17 +08:00
 SlanWyf

在学习 easyExcel 的时候,发现一个浮点精度丢失的问题 如果属性为 double 类型。往 excel 中写入 19.8 ,excel 中显示的是 19.8 ,再读取,读取到的是 19.799999999999997 如果属性为 String 类型。往 excel 中写入 19.8 ,excel 中显示的是 19.799999999999997 ,再读取,读取到的是 19.799999999999997 ,但如果 excel 中本就是 19.8 ,那么读取到的也是 19.8

所以初步判断属性为 double ,写入不会错,读取会错;属性为 String ,读取不会错,写入会错

在网上只可以查到这是由于浮点精度问题,但不知为什么会造成读取与写入的不同,为什么要么写入错,要么读取错,而不是同时错,或同时不错。而且既然属性为 String 为什么还会有浮点精度问题

1737 次点击
所在节点    Java
9 条回复
ranaanna
2023-10-21 18:55:45 +08:00
浮点数是离散的,双精度浮点数的间隔是 10^n*2^(-52) = 2.22e(n-16),是不存在 19.8 这么精确的数的。OP 可以大概算一下双精度浮点数表示 19.8 的误差,已经小到亿亿分之几了吧。所以不明白为什么 OP 会认为读取出错。
至于为什么 String 还是被当作浮点数,没用过 easyExcel 不知道,这锅不应该 Java 来背
SlanWyf
2023-10-21 19:45:25 +08:00
@ranaanna 本人是个新人,对于这种原理方面的东西没有了解过。文中我可能没描述清楚,我所说的读取出错只是指,excel 中 19.8 的数字通过 easyExcel 读取到 java 中输出为 19.799999999999997 这种现象。并没有对这种现象尝试做出自己的见解。
512357301
2023-10-21 19:53:44 +08:00
换个思路,程序写入到 Excel 之后,就不再读取这个文件了。这样就没错了。
读取的话,只读取用户准备好的 Excel 表。
还有个办法就是不相信 Excel 的数据,所有的数据都做四舍五入处理(保留 4 位小数),或者用专门的 math 库来处理数据,避免精度问题。
ranaanna
2023-10-21 19:59:00 +08:00
@SlanWyf 这是正常现象,并没有出错
kanezeng
2023-10-21 20:21:19 +08:00
这个问题不是 Java 浮点精度问题,应该说是 EasyExcel 的问题? EasyExcel 就有过 Issue 吧。可以以 BigDecimal 去读数据,然后以 String 类型写数据。如果要用 String 读写,那就在字段上添加 @NumberFormat 注解
sumarker
2023-10-21 20:41:08 +08:00
1. 程序里十进制小数数转二进制存在精度损失的问题——这个可以很容易搜到具体情况
2. easyExcel 在做转换赋值的时候逻辑问题——需要查具体源码
3. excel 展示的时候,单元格类型问题——这个应该也很容易遇到
pengtdyd
2023-10-21 22:11:33 +08:00
详见 《 IEEE 754 》
Goooooos
2023-10-21 22:13:43 +08:00
这不是 java 的问题,这是计算机二进制表示浮点数的问题
night98
2023-10-22 00:49:27 +08:00
这种问题就两个方向,一个是写入之前的数据就已经出错了,一个是写入到 excel 里面没有设置单元格的数据格式导致的读取错误

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/984083

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX