浅谈Java基础知识之BigDecimal
作者:lan00zi 发布时间:2021-09-06 16:49:27
一、基本使用
使用示例:
// 初始化
BigDecimal bd1=new BigDecimal("456");
BigDecimal bd2=new BigDecimal("123");
// 加
BigDecimal add=bd1.add(bd2);
// 减
BigDecimal subtract=bd1.subtract(bd2);
// 乘
BigDecimal multiply=bd1.multiply(bd2);
// 除
BigDecimal divide=bd1.divide(bd2);
// 指数运算, 2 is exponent
BigDecimal powerValue=bd2.pow(2);
// 四舍五入
multiply.setScale(1, RoundingMode.HALF_EVEN);
二、舍入模式
枚举类 java.math.RoundingMode
定义了8种数据的舍入模式,在 BigDecimal
中,可以用 BigDecimal.setScale(int newScale, RoundingMode roundingMode)
来设置数据的精度和舍入模式。
ROUND_UP
:向远离零的方向舍入。若舍入位为非零,则对舍入部分的前一位数字加1;若舍入位为零,则直接舍弃。即为向外取整模式。
ROUND_DOWN
:向接近零的方向舍入。不论舍入位是否为零,都直接舍弃。即为向内取整模式。
ROUND_CEILING
:向正无穷大的方向舍入。若
BigDecimal
为正,则舍入行为与ROUND_UP
相同;若为负,则舍入行为与ROUND_DOWN
相同。即为向上取整模式。ROUND_FLOOR
:向负无穷大的方向舍入。若
BigDecimal
为正,则舍入行为与ROUND_DOWN
相同;若为负,则舍入行为与ROUND_UP
相同。即为向下取整模式。ROUND_HALF_UP
:向“最接近的”整数舍入。若舍入位大于等于5,则对舍入部分的前一位数字加1;若舍入位小于5,则直接舍弃。即为四舍五入模式。
ROUND_HALF_DOWN
:向“最接近的”整数舍入。若舍入位大于5,则对舍入部分的前一位数字加1;若舍入位小于等于5,则直接舍弃。即为五舍六入模式。
ROUND_HALF_EVEN
:向“最接近的”整数舍入。若(舍入位大于5)或者(舍入位等于5且前一位为奇数),则对舍入部分的前一位数字加1;
若(舍入位小于5)或者(舍入位等于5且前一位为偶数),则直接舍弃。即为银行家舍入模式。
ROUND_UNNECESSARY
断言请求的操作具有精确的结果,因此不需要舍入。
如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。
三、注意事项
1.大量的数学计算时,使用 基本数据类型
而不是BigInteger
和 BigDecimal
。
原因:由于是不可变(immutable)的,在进行每一步运算时,都会产生一个新的对象,引起开销。
建议:应尽量用long
,float
,double
等基本类型做科学计算或者工程计算。
设计的目的是用来精确地表示大整数和小数,例如进行金额等比较敏感的数据运算。
2.构造 BigDecimal
时,使用 String
而不是 double
。
原因:有些数字用 double 根本无法精确表示,传给 BigDecimal 构造方法时就已经不精确了。例如:new BigDecimal(0.1)得到的值是0.1000000000000000055511151231257827021181583404541015625。
建议:使用 new BigDecimal(“0.1”) 得到的值是 0.1。BigDecimal
有4个构造方法,其中的两个用BigInteger
构造,一个用double
构造,一个用String
构造。
3.比较两个 BigDecimal
值时,使用 compareTo()
而不是 equals()
。
原因: equals() 方法认为 0.1 和 0.1 是相等的,返回true;认为 0.10 和 0.1 是不等的,返回false。
compareTo() 方法则认为 0.1 与 0.1 相等,0.10 与 0.1 也相等。
4.另外还有一些情形,任意精度的小数运算仍不能表示精确结果。例如,1 除以 9 会产生无限循环的小数 .111111…。
出于这个原因,在进行除法运算时,BigDecimal可以让您显式地控制舍入。
四、异常处理 ArithmeticException异常
在使用BigDecimal数据类型进行计算时,会有三种情况抛出 ArithmeticException
,分别是:
1.当除数为 0 时,这种情况比较常见,所以我们在进行除法运算之前先判断下除数是否为 0;
2.如果运算的结果是无线循环的小数,并且在除的时候没有对结果设置精确的位数;
BigDecimal divide 方法结果为无限小数问题 10/3=3.3333333333333333…
public static void main(String[] args) {
BigDecimal a = new BigDecimal("10");
BigDecimal o = new BigDecimal("3");
System.out.print(a.divide(o,2, BigDecimal.ROUND_DOWN).doubleValue());
}
Note:不设置精度范围会出现异常
3.当我们设置了结果的舍入模式是 ROUND_UNNECESSARY
模式时:
如果确保了计算的结果是精确的,则不会抛出异常;否则,就会抛出ArithmeticException
异常。
4.只设置精度(小数点后面的位数,scale),但没有设置舍入模式(roundingModel)时,会不知道如何对小数舍入而报错。
所以在设置精度时要连舍入模式一起设置。
// wrong code
bd = new BigDecimal(1.5); // is actually 1.4999....
bd.setScale(1); // throws ArithmeticException
// wright code
a = new BigDecimal("2.5"); // digit left of 5 is even, so round down
b = new BigDecimal("1.5"); // digit left of 5 is odd, so round up
a.setScale(0, BigDecimal.ROUND_HALF_EVEN).toString() // => 2
b.setScale(0, BigDecimal.ROUND_HALF_EVEN).toString() // => 2
5.指数运算,指数 exponent 为负数时
If you are raising things to negative exponents, you must specify a MathContext in BigDecimal.pow(int, MathContext) so it knows how much precision to use – otherwise, BigDecimal will try to compute it to infinite precision, which is not possible for some values.
//wrong code
BigDecimal powerValue=bd2.pow(-27);// -27 is exponent
来源:https://blog.csdn.net/u010541670/article/details/116667759


猜你喜欢
- 背景 我们知道在.NET Framework中存在四种常用的定时器,他们分别是:1 两个是通用的多线程定时器:Syste
- c#判断代码是否执行超时一、使用委托delegate void dg();dg dgCase;void method(){ &n
- 表达式目录树表达式目录树:语法树,或者说是一种数据结构1.表达式目录树Expression:System.Linq.Expressions;
- 1.基本语法key: value;kv之间有空格大小写敏感使用缩进表示层级关系缩进不允许使用tab,只允许空格缩进的空格数不重要,只要相同层
- 前言本文主要是将最近工作中遇到的一个问题进行总结分享,主要介绍的是如何让WebView中H5页面全屏播放视频。关于这个问题,做一下简单分析,
- QueryWrapper实现MybatisPlus多表关联查询1.dao层接口使用Select注解写SQL重点:@Param("e
- 上篇《Spring Aop实例之xml配置》中,讲解了xml配置方式,今天来说说AspectJ注解方式去配置spring aop。依旧采用的
- 本文实例讲述了C#实现DataSet内数据转化为Excel和Word文件的通用类。分享给大家供大家参考,具体如下:前不久因为项目的需要写的一
- 前言:文件的上传和下载在日常开发中很是常见,那么这一功能是如何实现的呢,下面我给大家介绍一下实现条件:1、需要一个form标签,method
- 现实开发中,我们难免遇到跨域问题,以前笔者只知道jsonp这种解决方式,后面听说spring只要加入@CrossOrigin即可解决跨域问题
- 对单机服务做接口限流的处理方案简单说就是设定某个接口一定时间只接受固定次数的请求,比如/add接口1秒最多接收100次请求,多的直接拒绝,这
- 一、简介在Spring中,有这么2个接口:BeanFactory和FactoryBean,名字很相似,很多小伙伴经常混淆,在面试的时候也经常
- 本文实例为大家分享了java生成验证码图片的具体代码,供大家参考,具体内容如下示例一:import org.apache.commons.c
- 本文实例为大家分享了Android仿QQ讨论组头像展示的具体代码,供大家参考,具体内容如下一、效果图二、实现基本实现过程:1.将原图片读取为
- 为方便自己以后学习,自己记录学习,大家也可以参考,有什么问题一起探讨。今天学习RecyclerView,下边来说一下实现数据垂直滚动和数据横
- 一、前言最近在看android fragment与Activity进行数据传递的部分,看到了接口回调的内容,今天来总结一下。二、回调的含义和
- 当我们在spring容器中添加一个bean时,如果没有指明它的scope属性,则默认是singleton,也就是单例的。例如先声明一个bea
- Android 监听手机GPS打开状态实现代码GPS_Presenterpackage com.yiba.core;import andro
- 与任何程序设计语言一样,Java使用条件语句和循环结构确定控制流。本文将简单讲解条件、循环和switch。一、块作用域块(block),即复
- 一、解决方案1声明:jdk1.8已经经过线上环境使用1. 调研JDK8的加密策略存在限制版本和无限制版本,随着越来越多的第三方工具只支持 J