前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >日常开发踩坑:你的数值计算真的如你所愿吗?

日常开发踩坑:你的数值计算真的如你所愿吗?

作者头像
浩说编程
发布2021-08-17 13:56:55
2080
发布2021-08-17 13:56:55
举报
文章被收录于专栏:Java经验之谈Java经验之谈

读者在日常业务开发中或多或少会涉及到一些数值计算逻辑,尤其是金融行业需要特别严谨,通常由数值引起的问题都是潜移默化的且难以发现,拿“数值偏差”来说,初期的微小偏差是很难察觉的,当这种偏差累积成量级的数值错误而引起生产事故则为时已晚。

本篇就针对这一部分踩过的坑为读者做科普和预警。

1

浮点数的精度偏差:1减0.8真的等于0.2吗?

测试一下:

代码语言:javascript
复制
System.out.println(1 - 0.8);

控制台输出:

代码语言:javascript
复制
0.19999999999999996

显然结果并非我们所想,原因是十进制数在计算机底层是以二进制数保存的(0、1),浮点数的精度偏差就产生于这个进制转换过程

既然浮点数会产生精度偏差,那么使用Java提供的精度运算类BigDecimal就能避免偏差吗?

尝试修改代码:

代码语言:javascript
复制
System.out.println(new BigDecimal(1).subtract(new BigDecimal(0.8)));

控制台输出:

代码语言:javascript
复制
0.1999999999999999555910790149937383830547332763671875

是否又出你所料,BigDecimal确实在精度上有所提升,不过并不是想要的正确结果,所以再次修改代码:

代码语言:javascript
复制
System.out.println(new BigDecimal("1").subtract(new BigDecimal("0.8")))

控制台输出:

代码语言:javascript
复制
0.2

脱坑指南一

想要避免浮点数运算的精度偏差,需使用java.math包下提供的精度运算类BigDecimal,且必须使用字符串类型参数初始化BigDecimal。

2

浮点数的判断:用equals判断真的奏效了吗?

对于浮点数的判断通常有两种情况:1、值相等,2、值相等且精度相等。下面用equals分别测试一下:

代码语言:javascript
复制
System.out.println(new BigDecimal("1.0").equals(new BigDecimal("1")))
System.out.println(new BigDecimal("1.0").equals(new BigDecimal("1.0")))

控制台输出:

代码语言:javascript
复制
false
true

结果很直观,对于浮点数来说,equals的判定条件是值相等且精度也要相等,否则无法奏效。

那么如果只想判断值是否相等应该怎么做呢?使用compareTo方法:

代码语言:javascript
复制
System.out.println(new BigDecimal("1.0").compareTo(new BigDecimal("1"))==0);

控制台输出:

代码语言:javascript
复制
true

脱坑指南二

想要仅对浮点数的值判等用compareTo方法,值+精度判等用equals方法。

3

数值溢出:运算时数值超过类型最大值不会报错吗?

通过代码测试一下,第二行数值溢出了,首先没有编译错误:

代码语言:javascript
复制
Integer integer = Integer.MAX_VALUE;
System.out.println(integer + 1);
System.out.println(integer + 1 == Integer.MIN_VALUE);

控制台输出,也没有任何异常:

代码语言:javascript
复制
-2147483648
true

所以内存溢出不会报错,数值将回到对应数据类型的最小值重新轮回。既然问题已经产生,应该如何解决呢?

脱坑指南三

Plan A:使用Math类提供的带有溢出异常捕获的运算方法xxExact

方法源码,对溢出主动捕获异常

Plan B:使用范围更大的数据类型BigInteger,可能有读者会问“如果这个类型也不够用溢出了呢”,只能说这样问下去的话问题永远也没有答案了。

4

总结:三个坑点

1、浮点数的精度偏差

方案: 使用BigDecimal做浮点数运算,且构造入参要使用字符串类型

2、浮点数的判等问题

方案:仅对浮点数的值判等用compareTo方法,值+精度判等用equals方法

3、隐性的数值溢出问题

方案1:使用Math类提供的带有溢出异常捕获的运算方法xxExact做数值运算

方案2:使用范围更大的数据类型BigInteger

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 浩说编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档