转载自 金融系统中正确的金额计算及存储方式

经典的精度丢失问题

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

public static void main(String[] args) {test1();test2();
}

private static void test1() {double totalAmount = 0.09;double feeAmount = 0.02;double tradeAmount = totalAmount - feeAmount;System.out.println(tradeAmount);
}

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

0.07?非也!

正确的结果是:

0.06999999999999999

为什么是这样?

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

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

怎么解决

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

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

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

BigDecimal(double val)

再来看这个示例:

private static void test2() {double totalAmount = 0.09;double feeAmount = 0.02;BigDecimal tradeAmount = new BigDecimal(totalAmount).subtract(new BigDecimal(feeAmount));System.out.println(tradeAmount);
}

输出:

0.0699999999999999962529972918900966760702431201934814453125

这个精度就更恐怖了。。

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

BigDecimal(String val)
private static void test3() {double totalAmount = 0.09;double feeAmount = 0.02;BigDecimal tradeAmount = new BigDecimal(String.valueOf(totalAmount)).subtract(new BigDecimal(String.valueOf(feeAmount)));System.out.println(tradeAmount);
}

总结

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

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

金融系统中正确的金额计算及存储方式相关推荐

  1. 史海峰:构建产业互联网金融系统的正确姿势

    史海峰 IT民工闲话 读完需要 12 分钟 速读仅需 5 分钟 引言 互联网下半场从 ToC 进入 ToB 阶段,玩法不再是烧钱拉流量转化变现,而是深入产业核心领域,通过技术提升生态链整合能力,优化生 ...

  2. 金融系统中PBOC/EMV的TLV的算法实现(含C++/C#)

    金融系统中PBOC/EMV的TLV的算法实现(含C++/C#) TLV即Tag-Length-Value,常在IC卡与POS终端设备中通过这样的一个应用通信协议进行数据交换.在金融系统以及认证中,PB ...

  3. 金融系统中加密机的简介

    金融系统中加密机的简介 加密机是一台大小和台式PC机箱差不多大小的一台设备,价格较贵,约6-8万/台,在银行.银联.第三方支付等金融机构广泛使用,主要用来加解密银行卡密码,计算交易MAC,保证交易中敏 ...

  4. 【genius_platform软件平台开发】第七十九讲:Linux系统中可执行程序后台运行的几种方式

    [genius_platform软件平台开发]第七十九讲:Linux系统中可执行程序后台运行的几种方式 1. 问题描述 2. & 符号 3. nohup指令 4. ctrl + z.jobs. ...

  5. windows系统中查看linux分区的三种方式

    双系统中windows查看linux分区的三种方式 一.这个算是大家早有耳闻的啦,就是使用Explore2fs这个工具,可以去 http://www.chrysocome.net/explore2fs ...

  6. win 读 linux分区,windows系统中查看linux分区的三种方式

    双系统中windows查看linux分区的三种方式 一.这个算是大家早有耳闻的啦,就是使用Explore2fs这个工具,可以去 官方网站下载,这个工具用法简单就不多说了,如图所示: 二.使用一个叫磁盘 ...

  7. 高NA镜头系统中的高级PSF计算

    摘要 众所周知,光的矢量性质在高NA聚焦情况下起着不可忽略的作用. 在此示例中,展示了通过高NA非球面透镜聚焦线性偏振高斯光束的案例,并显示了焦平面中的非对称PSF现象. 通过检查焦平面中的电磁场分量 ...

  8. linux系统中开机自启的三种方式

    有时候我们需要Linux系统在开机的时候自动加载某些脚本或系统服务 主要用三种方式进行这一操作: ln -s 在/etc/rc.d/rc*.d目录中建立/etc/init.d/服务的软链接(*代表0- ...

  9. window系统中打开命令行的四种方式

    方法1:cmd窗口(window+R, --->运行-->录入cmd,回车) 方法2:在资源管理器中,打开任意目录,直接在地址栏中写入 cmd,并回车 方法3:powershell(win ...

最新文章

  1. python中的点表示什么_Python里面这些点,新手看完之后完全不知道这些点
  2. 在qemu模拟的aarch32上使用kgtp
  3. 利用事件冒泡和阻止事件冒泡的例子
  4. boost::mpl::times相关的测试程序
  5. 2020厦门大学845数据结构考研考试范围(大纲)和参考书目
  6. 【BZOJ2054】疯狂的馒头(并查集)
  7. 最优化学习笔记(三)——梯度下降法
  8. svg标签的CSS3动画特效 - 经典特效2
  9. socket php验证客户端验证,用Socket发送电子邮件(利用需要验证的SMTP服务器)
  10. 远程键盘 App 被曝漏洞,成 Intel 弃子!
  11. mapxtreme is still in evalutation!
  12. Linux 运维工程师学习成长路线上要经历哪四个阶段?
  13. 09-TensorFlow 基于WDCNN的轴承故障诊断
  14. itx机箱尺寸_itx主机还需要显卡吗?极限尺寸s18 itx机箱装机示范
  15. Xunsearch体验Demo
  16. EfficientNet 简介
  17. [bzoj2563] 阿狸和桃子的游戏 贪心
  18. 开源好项目|码市 AndroidiOS App 源码开源
  19. Android 网络检测
  20. Java异常处理——日志打印

热门文章

  1. [EDA] 给出一个双进程状态机,请把它改为单进程状态机。
  2. 莫比乌斯反演/容斥 +2020ICPC 江西省大学生程序设计竞赛 A Simple Math Problem
  3. Eight HDU - 1043(八数码+搜索)
  4. java 持续交付_【Java架构:持续交付】一篇文章搞掂:Jenkins
  5. apache poi斜边框线_如何使用Apache POI在Excel单元格内画斜线(Java)
  6. 数据结构---BF字符串模式匹配
  7. Problem M. Mediocre String Problem(Z 函数 + PAM)
  8. hdu 5023 线段树染色问题
  9. CF773E Blog Post Rating(推导min的通项/线段树)
  10. ARC068C - Snuke Line