博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
经典的精度丢失问题
阅读量:6656 次
发布时间:2019-06-25

本文共 1528 字,大约阅读时间需要 5 分钟。

Java中的类型float、double用来做计算会有精度丢失问题,下面来看下面的示例。

  1. public static void main(String[] args) {

  2.    test1();

  3.    test2();

  4. }

  5.  

  6. private static void test1() {

  7.    double totalAmount = 0.09;

  8.    double feeAmount = 0.02;

  9.    double tradeAmount = totalAmount - feeAmount;

  10.    System.out.println(tradeAmount);

  11. }

上面的程序输出结果是多少?

0.07?非也!

正确的结果是:

  1. 0.06999999999999999

为什么是这样?

浮点数可能丢失精度,浮点十进制数通常没有完全相同的二进制的表示形式,这是CPU所采用的浮点数据表示形式的副作用。为此,可能会有一些精度丢失,并且一些浮点运算可能会产生未知的结果。

浮点运算很少是精确的,只要是超过精度能表示的范围就会产生误差。所以,在使用float、double作精确运算的时候一定要特别小心,除非能容忍精度丢失,不然产生的误差也是会造成双方对账不一致的结果。

怎么解决

在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal。

BigDecimal适合更精度的运算,也提供了丰富的操作符类型,小数位控制,四舍五入规则等。

不过,使用BigDecimal不当也有精度丢失的情况,如double的构造方法:

  1. BigDecimal(double val)

再来看这个示例:

  1. private static void test2() {

  2.    double totalAmount = 0.09;

  3.    double feeAmount = 0.02;

  4.    BigDecimal tradeAmount = new BigDecimal(totalAmount).subtract(new BigDecimal(feeAmount));

  5.    System.out.println(tradeAmount);

  6. }

输出:

  1. 0.0699999999999999962529972918900966760702431201934814453125

这个精度就更恐怖了。。

所以,一定要使用String的构造方法:

  1. BigDecimal(String val)

  1. private static void test3() {

  2.    double totalAmount = 0.09;

  3.    double feeAmount = 0.02;

  4.    BigDecimal tradeAmount = new BigDecimal(String.valueOf(totalAmount))

  5.            .subtract(new BigDecimal(String.valueOf(feeAmount)));

  6.    System.out.println(tradeAmount);

  7. }

总结

  • 金额运算尽量使用BigDecimal(String val)进行运算。

  • 数据库存储金额,一般有整型和浮点型两种存储方式。如果是有汇率转换的,建议使用浮点数decimal进行存储,可以灵活的控制精度,decimal直接对应java类型BigDecimal。当然,用整数存储分这种形式也可以,转账的时候单位为元而如果忘了转换分为元,那就悲剧了。

转载于:https://www.cnblogs.com/chinaifae/p/10640890.html

你可能感兴趣的文章
Expert 诊断优化系列-------------针对重点语句调索引
查看>>
【产品设计】设计中的文档管理
查看>>
nyoj 504 课程设计
查看>>
读《认知三部曲》
查看>>
继承和多态的那些事
查看>>
android中SimpleCursorAdapter _id错误的问题
查看>>
爬虫连接mongodb、多线程多进程的使用
查看>>
R语言 数据集
查看>>
c# e语言 字节集 表示方式
查看>>
MySql 初次安装登陆
查看>>
私服的问题
查看>>
图像处理之图像格式变换和色彩增强---rgb2hsi2hsv 色彩增强
查看>>
图像处理之二维码生成-qr
查看>>
spark 特征选择之FeatureSelectors DataFrame[vector] 转 DataFrame[Row]
查看>>
PAT 1067. Sort with Swap(0,*)
查看>>
最长回文子字符串的长度
查看>>
8个开发必备的PHP功能(转)
查看>>
Linux Socket编程学习
查看>>
二级域名怎么做优化
查看>>
MIME类型大全
查看>>