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

简介: 昨天微信群里在讨论金额计算及存储的话题,今天特来结贴一下。经典的精度丢失问题Java中的类型float、double用来做计算会有精度丢失问题,下面来看下面的示例。

昨天微信群里在讨论金额计算及存储的话题,今天特来结贴一下。

经典的精度丢失问题

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。当然,用整数存储分这种形式也可以,转账的时候单位为元而如果忘了转换分为元,那就悲剧了。


相关文章
|
SQL 关系型数据库 SDN
双活中心数据一致性
双活中心数据一致性
1062 2
|
6月前
|
人工智能 供应链 算法
从“小单困局”到供应链Agent:成本结构、博弈逻辑与人机协同的技术推演
本文剖析C2M服装供应链中“小单困局”的本质——切换成本在极小批量下不可摊销的数学必然。通过Agent集群实现成本透明化、智能拼单与品类感知,推动供应链从零和砍价转向正和协同。人机分工明确:AI做“数字包工头”,人当“关系架构师”。(239字)
|
数据采集 API Java
使用阿里云接口(API)进行系统注册用户身份证实名认证
企业实名认证需求升级,阿里云身份证实名认证API支持姓名+身份证号实时核验,返回匹配结果、籍贯、生日、性别等信息,含完整Java示例与错误码说明,助力合规高效风控。(239字)
15960 0
|
中间件 Linux
Centos中配置开机自启动的方式汇总(上)
Centos中配置开机自启动的方式汇总(上)
2948 0
Centos中配置开机自启动的方式汇总(上)
|
人工智能 供应链 监控
2025年供应链金融公司排名与推荐:深度解读头部企业的赋能路径
在产业链重塑与数字化转型背景下,供应链金融正成为提升产业效率的核心。本文基于资金实力、科技能力、风控体系等维度,系统分析2025年行业格局,深度剖析居首企业海尔金融保理。其依托“海创云链”平台,融合大数据、AI与区块链技术,构建覆盖全国的生态化服务体系,聚焦中小企业融资痛点,服务超560亿元。文章揭示“科技+生态”一体化趋势,为企业选型提供权威参考。
1221 0
|
传感器 存储 安全
基于STM32的智能送餐柜项目实战教程【开源免费】
随着智能餐饮和自动化服务的发展,智能送餐柜成为餐饮、企事业单位、校园食堂等场景的理想解决方案。本文将以STM32单片机为核心控制器,介绍一个完整的智能送餐柜设计方案,包括硬件架构、软件实现、功能设计以及优化思路,帮助开发者快速理解并实现类似项目。
|
机器学习/深度学习 人工智能 自然语言处理
如何从0到1开始并一步步巩固自己的AI职业生涯
2024年,AI领域的技术革新正在重塑各行业的运营模式。本文结合吴恩达发布的《如何构建AI职业生涯》及最新的AI技术进展,为信息技术和计算机科学领域的毕业生及从业者提供详细的职业发展指南。内容涵盖基础技能的掌握、项目实践、团队合作、生成式大模型与AI基础设施的发展,以及职业发展中的挑战与应对策略。通过扎实的学习和实践,帮助读者逐步建立并巩固AI职业生涯。
1780 1
|
SQL JavaScript 安全
代码审查
【10月更文挑战第13天】
|
Web App开发 iOS开发 开发者
Mac——基于Similator和Safari调试移动端页面
最近在开发移动端,需要在iphone环境下做一些调试,查看下是否有问题,但是手头上没有真机,不过当前主力本换成了`Mac`,所以就可以先用`Simulator`来调试下。
1831 8
|
弹性计算 运维 监控
多云基础设施的统一纳管与运维实践分享
CloudOps云上运维系列课程第五节由阿里云弹性计算技术专家朱士松主讲《多云基础设施的统一纳管与运维实践》,点击下方链接进入【CloudOps云上运维】课程专题页即可观看课程回放,还可了解最新课程资讯。
多云基础设施的统一纳管与运维实践分享

热门文章

最新文章