BigDecimal遇到的问题,大伙也说说
一:相除精度丢失的问题
BigDecimal的api除法相对加减乘要实现的复杂多了,只介绍常用的我遇到的问题:
问题:两数相除,如果9/3=3整除没问题,但是10/3=0.33333333......除不尽,这里不能让电脑一直除不尽,所以BigDecimal做出一些限制;
必须按照(数,保留小数位(最好要合理限制最大精度),舍入方式)来操作

否则就会抛出异常,例如:
public static void main(String[] args) {
BigDecimal a = new BigDecimal(10);
BigDecimal b = new BigDecimal(3);
BigDecimal c = a.divide(b);
}
执行:抛出
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1616)
二:舍入方式精度丢失的问题
多数相乘时,请勿先进行四舍五入或者其他的方式,以最终计算结果为基础进行取舍精度,虽然一说就明白,但是这一个编码的习惯问题,特别是在金融行业。
舍入方式需要弄明白自己的业务才用,别为了用而随便选一个用
1.ROUND_UP:四舍五入模式从零四舍五入。
main(String[] args) {
BigDecimal a = BigDecimal(0.31);
BigDecimal b = BigDecimal(3);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_UP);
LOGGER.error("原值:0.1033333...///"+c.toString()+"=0.2");
//结论:0-9都是向前进一位(且当0后还有小数位为前提)
}
2.ROUND_DOWN 四舍五入模式到四舍五入接近零。
main(String[] args) {
BigDecimal a = BigDecimal(0.39);
BigDecimal b = BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_DOWN);
LOGGER.error("原值:0.39///"+c.toString()+"=0.3");
//结论:1-9都是向前进一位
}
3.ROUND_CEILING 四舍五入到正无穷。
public static void main(String[] args) {
BigDecimal a = new BigDecimal(0.301);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_CEILING);
LOGGER.error("原值:0.301///"+c.toString()+"=0.4");
//结论:与第一种类似,区别就是舍入到正无穷的范围大,当值为负数时舍入失效,当用第四种解决
}
4.ROUND_FLOOR 四舍五入到负无穷
main(String[] args) {
BigDecimal a = BigDecimal(-0.301);
BigDecimal b = BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_FLOOR);
LOGGER.error("原值:0.301///"+c.toString()+"=0.4");
//结论:与上面的正无穷舍入的方式相反,可以互补
}
5.ROUND_HALF_UP 四舍五入方式四舍五入,除非两个邻边距离相等,则四舍五入。
public static void main(String[] args) {
BigDecimal a = new BigDecimal(-0.36);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_UP);
LOGGER.error("原值:-0.36///"+c.toString()+"=-0.4"); //结论:正负数相同,以5为分界,<=5舍掉,>5的进1
}
6.ROUND_HALF_DOWN 四舍五入模式四舍五入,除非两个邻边距离相等
public static void main(String[] args) {
BigDecimal a = new BigDecimal(-0.35);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_DOWN );
LOGGER.error("原值:-0.35///"+c.toString()+"=-0.3"); //结论:正负数相同,以5为分界,<=5舍掉,>5的进1
}
7.ROUND_HALF_EVEN 四舍五入的方式是四舍五入,除非两个邻边是等距的,在这种情况下,四舍五入对甚至邻居。
public static void main(String[] args) {
BigDecimal a = new BigDecimal(-0.35);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_EVEN );
LOGGER.error("原值:-0.35///"+c.toString()+"=-0.3"); //结论:正负数相同,以5为分界,<=5舍掉,>5的进1
}
8.ROUND_UNNECESSARY 舍入模式,以断言所请求的操作具有精确值结果,因此不需要舍入。
public static void main(String[] args) {
BigDecimal a = new BigDecimal(-0.36);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_EVEN );
LOGGER.error("原值:-0.36///"+c.toString()+"=-0.4"); //结论:正负数相同,以5为分界,<=5舍掉,>5的进1 // 断言中使用的,实际开发过程中最好不用
}
三:BigDecimal取值范围的 validation 校验问题总结
常常在与客户端交互时需要做很多校验,在javax.validation下面有很多不错的校验规则

@NotNull :不为空,适用任何地方(@NotBlank只是用字符类型)
@DecimalMax:取得最大值范围
@DecimalMin(value = "0.00", message = "") 取值最小值
三:BigDecimal精度科学计数法问题总结
BigDecimal有一种方法是:stripTrailingZeros(),它提供了去掉小数点后面的多余的0,但是问题是:
public static void main(String[] args) {
BigDecimal A = BigDecimal.valueOf(0.36000).stripTrailingZeros();
BigDecimal B = new BigDecimal(0.36000).stripTrailingZeros();
BigDecimal zeroDecimal = new BigDecimal(0.000).stripTrailingZeros();
System.out.println("原值0.36000//////"+A.toPlainString()+"===0.36");
System.out.println("原值0.36000//////"+B.toPlainString()+"===35999999999999998667732370449812151491641998291015625");
System.out.println("原值0.00000//////"+zeroDecimal+"==0.0000////"+zeroDecimal.toPlainString()+"==0");
}
①:导出是excel会以科学计数法展示数据,如120 -》1.2+E2;
②:如果0.000然后用stripTrailingZeros()是无效的,导出时toPlainString()加上之后就可以了;
③:慎用new BigDecimal();源代码如下;
/**这个构造函数的结果可能有些不可预测。
*可能会假设编写{@code new BigDecimal(0.1)}
* Java创建一个完全等于的{@code BigDecimal}
* 0.1(未缩放值为1,刻度为1),但它是
*实际上等于 *0.1000000000000000055511151231257827021181583404541015*625.
**/public BigDecimal(double val) {
this(val,MathContext.UNLIMITED);
}
BigDecimal遇到的问题,大伙也说说的更多相关文章
- BigDecimal 详细解析
参加工作之后发现公司项目的数据库有关数值的字段类型,很少是之前常用的float和double, 而是一个没有接触过的decimal,在Java中表示的类型为BigDecimal, 而在业务中常常有关B ...
- Java BigDecimal 转换,除法陷阱(转)
源地址: http://blog.csdn.net/niannian_315/article/details/24354251 今天在用BigDecimal“出现费解”现象,以前虽然知道要避免用, ...
- JAVA BigDecimal 小数点处理
1,保留两位小数 方法一:{ double c=3.154215; java.text.DecimalFormat myformat=new java.text.DecimalFormat(" ...
- BigDecimal 处理集合
1 创建一个BigDecimal 对象 BigDecimal Sum = new BigDecimal(0); 2 一个BigDecimal 对象,保留2位小数点 Sum.setScale(2,B ...
- BigDecimal用法详解
一.简介Java在java.math包中提供的API类BigDecimal,用来对超过16位有效 位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更 ...
- 网站压力负载测试工具:Web版已逝,只好送大伙单机版
前言: 最近老板资金周转出了点问题,工资好久没发了,于是暂闲置在家,静待老板弄到钱东山再起的消息: QQ群里,偶尔不时的会有人问,原来的分布式网站负载工具怎么下载不了啦?或者不能用啦?之类的问题. 我 ...
- java 大数据处理类 BigDecimal 解析
这两天,由于我的必修课概率论里经常要用到排列组合的计算,感觉很麻烦,加上现代智能手机的计算器是没有这方面功能的. 所以,就自己动手写了个安卓的 排列组合 计算器,用了一天,发现有很大的问题,阶乘达百亿 ...
- BigDecimal 加减乘除
BigDecimal bignum1 = new BigDecimal("10"); BigDecimal bignum2 = new BigDecimal("5&quo ...
- 关于BigDecimal 和 double 类型保存金钱,以及精度问题,银行家舍入法
1. BigDecimal 类型数据 的创建,构造函数 有 public BigDecimal(BigInteger intVal, long val, int scale, int prec); p ...
随机推荐
- python 旋转数组 多种解题思路
leetcode 题目描述:给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题. 要求使用空间复杂度为 O(1) 的 ...
- Ubuntu 16.04下安装谷歌浏览器(转)
1.进入 Ubuntu 16.04 桌面,按下 Ctrl + Alt + t 键盘组合键,启动终端. 2.在终端中,输入以下命令,将下载源加入到系统的源列表. sudo wget http://www ...
- Android快速实现二维码扫描--Zbar
Android中二维码扫描的最常用库是zxing和zbar,上一篇<Android快速实现二维码扫描–Zxing>介绍了Zxing.这次说Zbar,Zbar速度极快,我就比较常用,项目地址 ...
- Feign自定义编程配置
介绍 在Spring Cloud中,Feign的默认配置类是FeignClientsConfiguration,该类定义了Feigh默认使用的编码器.解码器.所使用的契约等.Spring Cloud允 ...
- Netty心跳机制
一.概念介绍网络中的接收和发送数据都是使用操作系统中的SOCKET进行实现.但是如果此套接字已经断开,那发送数据和接收数据的时候就一定会有问题.可是如何判断这个套接字是否还可以使用呢?这个就需要在系统 ...
- 自动生成getter setter
如何使用java黑魔法给一个entity生成getter,setter方法? 由于java是一门静态语言,要给一个类动态添加方法,看似是不可能的.但牛B的程序员会让任何事情发生.我只知道有两种方式可以 ...
- 深入理解 Java 虚拟机
Java 代码编译和执行的整个过程 Java 代码编译是由 Java 源码编译器来完成,流程图如下所示: Java 字节码的执行是由 JVM 执行引擎来完成,流程图如下所示: Java 代码编译和执行 ...
- go map的使用
欢迎关注go语言微信公众号 每日go语言 golang_everyday go中map用于存储健值对.map格式: map[KeyType]ValueType 声明一个map,键为字符型,值为int型 ...
- 网络基础知识-TCP/IP协议各层详解
TCP/IP简介 虽然大家现在对互联网很熟悉,但是计算机网络的出现比互联网要早很多. 计算机为了联网,就必须规定通信协议,早期的计算机网络,都是由各厂商自己规定一套协议,IBM.Apple和Micro ...
- MyBatis(国税)
一.MyBatis概要 1.1.ORM介绍 对象关系映射(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),用于实现面向对象编程语言里不同类型系统 ...