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

作者 | 浩说编程
来源 | 公众号:浩说编程
[ 大厂技术资源 | 研发必备安装包 | 限时免费获取 ]

在这里插入图片描述

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

 

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

测试一下:

System.out.println(1 - 0.8);

控制台输出:

0.19999999999999996

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

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

尝试修改代码:

System.out.println(new BigDecimal(1).subtract(new BigDecimal(0.8)));

控制台输出:

0.1999999999999999555910790149937383830547332763671875

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

System.out.println(new BigDecimal("1").subtract(new BigDecimal("0.8")))

控制台输出:

0.2

脱坑指南一

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

码文不易
你的关注是浩说编程持续更新的动力
浩说会做的更好

 

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

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

System.out.println(new BigDecimal("1.0").equals(new BigDecimal("1")))
System.out.println(new BigDecimal("1.0").equals(new BigDecimal("1.0")))

控制台输出:

false
true

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

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

System.out.println(new BigDecimal("1.0").compareTo(new BigDecimal("1"))==0);

控制台输出:

true

脱坑指南二

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

 

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

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

Integer integer = Integer.MAX_VALUE;
System.out.println(integer + 1);
System.out.println(integer + 1 == Integer.MIN_VALUE);

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

-2147483648
true

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

脱坑指南三

Plan A:使用Math类提供的带有溢出异常捕获的运算方法xxExact
(方法源码,对溢出主动捕获异常)
图片

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

 

总结:三个坑点

1、浮点数的精度偏差

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

2、浮点数的判等问题

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

3、隐性的数值溢出问题

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

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

图片

以上就是本篇的内容,希望读者通过上面的内容提高对数值运算逻辑的警惕性,防止发生类似的问题。浩说编程致力于为读者解惑,欢迎私信交流,关注我,你会学到更多

作者 | 浩说编程
来源 | 公众号:浩说编程
[ 大厂技术资源 | 研发必备安装包 | 限时免费获取 ]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值