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

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

经典的精度丢失问题

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


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/330731.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JSTL标签库

1.JSTL介绍 JSTL(Java Server Pages Standarded Tag Library) : JSP标准标签库。主要提供给开发人员一个标准通用的标签库。 开发人员可以利用这些标签取代JSP页面上的Java 代码,从而提高程- 序的可读性,降低程序的维护难度 组成部分如下: …

缓存雪崩,缓存穿透,缓存预热,缓存热备都是什么鬼?

转载自 缓存雪崩,缓存穿透,缓存预热,缓存热备都是什么鬼?缓存雪崩,缓存穿透,缓存预热,缓存热备是在做缓存设计或者缓存应用时经常遇到的概念,也是缓存应用过程中必须熟知及知道 的东…

Multi-catch parameters are not allowed for source level below 1.7 解决方法

转自: https://stackoverflow.com/questions/21778922/eclipse-false-error-with-jdk7 You can solve this by setting up correct JRE environment in Eclipse as below. Go to Project > Properties > Java Build Path Click on Libraries Select JRE Syste…

使用Eclipse构建Maven项目 (step-by-step)

转自: http://blog.csdn.net/qjyong/article/details/9098213 Maven这个个项目管理和构建自动化工具,越来越多的开发人员使用它来管理项目中的jar包。本文仅对Eclipse中如何安装、配置和使用Maven进行了介绍。完全step by step。 如果觉得本文对你有用&a…

字符串substring方法在jkd6,7,8中的差异

转载自 注意:字符串substring方法在jkd6,7,8中的差异 标题中的substring方法指的是字符串的substring(int beginIndex, int endIndex)方法,这个方法在jdk6,7是有差异的。 substring有什么用? substring返回的是字符串索引位置beginIndex开始&…

过滤器五种拦截行为

1.问题:如何使过滤器拦截转发的请求和响应? Filter 过滤器默认拦截的是客户端发送过来的请求,但是在实际开发中,我们还有请求转发,以及由服务器触发调用的全局错误页面。默认情况下过滤器是不参与过滤的,要…

redis的主从数据库复制功能

【0】开场白: redis提供了复制功能, 实现当一台数据库中的数据更新后, 自动将更新的数据同步到其他数据库上; 这样即使一条server 发生故障,其他服务器仍然可以继续提供服务;(为数据生成多个副本…

轻松几步搞定SSH连接Git配置

转载自 轻松几步搞定SSH连接Git配置 如果使用ssh的方式管理,需要配置ssh key. 1、打开git bash命令窗口 2、生成ssh key ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" your_emailexample.com为github上你注册的email地址。 如下面完整创建过程…

redis哨兵

【0】redis的主从数据库实现, 参见: redis的主从数据库复制功能 1)redis的主从数据库的作用: 在一主多从的redis系统中, 从数据库起到了 数据冗余备份和读写分离的作用; 2)redis2.8提供的哨兵…

Git安装及配置5分钟快速教程

转载自 Git安装及配置5分钟快速教程 Git是什么 Git是一款免费、开源的分布式版本控制系统,可以有效、高速的处理从很小到非常大的项目版本管理。 与常用的版本控制工具CVS、Subversion等不同的是它采用了分布式版本库的方式,不必服务器端软件支持&#x…

MySQL基础---增删改查语法

一、DDL-数据定义语言,操作数据库(CRUD)和表(CRUD) 1 创建数据库(指定字符集) create database 数据库名称 character set utf8; 数据库和表修改都是 Alter 查看都是show 删除都是drop2 创建表 create table 表名称(字段名 数据类型,字段名 数据类型,... ...字…

理解水平扩展和垂直扩展

转自: http://yunjiechao-163-com.iteye.com/blog/2126981 当一个开发人员提升计算机系统负荷时,通常会考虑两种方式垂直扩展和水平扩展。选用哪种策略主要依赖于要解决的问题 以及系统资源的限制。在这篇文章中我们将讲述这两种策略并讨论每种策越的…

JavaWeb核心常用API一览

1.核心知识点 2.常用API

Java中的宏变量,宏替换详解。

转载自 Java中的宏变量,宏替换详解。群友在微信群讨论的一个话题,有点意思,特拿出来分享一下。输出true false来看下面这段程序,和群友分享的大致一样。 public static void main(String[] args) {String hw "hello world&q…

eclipse如何设置js源文件编码

window -> preferences -> 输入 content type -> 然后在右侧栏点击 javascript source file, 然后default encoding 输入 gbk(或者其他编码格式), 点击 update , 然后可以看见文件编码已经改变, 最…

SQL编程---存储过程和存储函数

1.基本概念 存储过程和函数是事先经过编译并存储在数据库中的一段 SQL 语句的集合。 2.存储过程和函数的好处 提高代码的复用性。减少数据在数据库和应用服务器之间的传输&#xff0c;提高效率。减少代码层面的业务处理。 3.创建和调用存储过程 <1>创建存储过程 创…

jvm 启动参数设置

-Xms256m -Xmx256m -XX:MaxPermSize64m 如果 jvm 启动失败&#xff0c; 说堆内存不够&#xff0c; 需要调小 初始堆和最大堆大小&#xff0c; 持久代大小&#xff1b; 第一行的参数是调节后的vm参数荔枝 &#xff1b;

类、变量、块、构造器、继承初始化顺序,终极解答

转载自 类、变量、块、构造器、继承初始化顺序&#xff0c;终极解答最近发现微信群里面有些群友在讨论类的初始化顺序&#xff0c;如类的静态变量、成员变量、静态代码块、非静态代码块、构造器&#xff0c;及继承父类时&#xff0c;它们的初始化顺序都是怎样的&#xff0c;下面…

数据表触发器

1.概念 触发器就是在表数据发生变化的时候&#xff0c;自动触发的一些 SQL 操作,查询不影响表中的数据&#xff0c;所以没有触发器。类似于web监听器机制,监听对应表的增删改。 2.触发器分类 触发器类型OLD 触发器之前的效果NEW 触发器之后的效果INSERT 类型的触发器无&…

Linux NAT网络连接权威指南

【1】准备工作&#xff0c;写在前面 1.1&#xff09;检查服务&#xff08;cmd>>services.msc,我用的是VM&#xff09; 1.2&#xff09;确保Vmnet8 连接处于启动状态 获取ipv4&#xff08;ipv6&#xff09;地址 &#xff08;在网络连接不正确时&#xff0c;作参考之用&a…