BigDecimal详细解析
简介
BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负scale 次幂。因此,BigDecimal表示的数值是(unscaledValue × 10-scale)。
先运行一套代码
public static void main(String[] args){System.out.println(0.2 + 0.1);System.out.println(0.3 - 0.1);System.out.println(0.2 * 0.1);System.out.println(0.3 / 0.1);}
输出效果
0.30000000000000004
0.19999999999999998
0.020000000000000004
2.9999999999999996
原因
我们的计算机是二进制的。浮点数没有办法是用二进制进行精确表示。我们的CPU表示浮点数由两个部分组成:指数和尾数,这样的表示方法一般都会失去一定的精确度,有些浮点数运算也会产生一定的误差。如:2.4的二进制表示并非就是精确的2.4。反而最为接近的二进制表示是 2.3999999999999999。浮点数的值实际上是由一个特定的数学公式计算得到的。
构造方法
1.public BigDecimal(double val) 将double表示形式转换为BigDecimal *不建议使用
2.public BigDecimal(int val) 将int表示形式转换成BigDecimal
3.public BigDecimal(String val) 将String表示形式转换成BigDecimal
示例
BigDecimal bigDecimal = new BigDecimal(2);
BigDecimal bDouble = new BigDecimal(2.4);
BigDecimal bString = new BigDecimal("2.4");
System.out.println("bigDecimal=" + bigDecimal);
System.out.println("bDouble=" + bDouble);
System.out.println("bString=" + bString);
输出结果
bigDecimal=2
bDouble=2.399999999999999911182158029987476766109466552734375
bString=2.4
JDK的描述(原因)
1、参数类型为double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。
2、另一方面,String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用String构造方法。
如果是确定用double,则可以用Double.toString(2.4),如下代码
BigDecimal bDouble1 = BigDecimal.valueOf(2.4);
BigDecimal bDouble2 = new BigDecimal(Double.toString(2.4));System.out.println("bDouble1=" + bDouble1);
System.out.println("bDouble2=" + bDouble2);
输出结果
bDouble1=2.4
bDouble2=2.4
几种常用函数
加:BigDecimal add(BigDecimal augend)
减:BigDecimal subtract(BigDecimal subtrahend)
乘:BigDecimal multiply(BigDecimal multiplicand)
除法:BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
(BigDecimal divisor 除数, int scale 精确小数位, int roundingMode 舍入模式)
绝对值:BigDecimal abs()
例子代码
BigDecimal num1 = new BigDecimal(2.4);
BigDecimal num2 = new BigDecimal(2);
BigDecimal num3 = new BigDecimal(-2);
//尽量用字符串的形式初始化
BigDecimal num12 = new BigDecimal("2.4");
BigDecimal num22 = new BigDecimal("2");
BigDecimal num32 = new BigDecimal("-2");//加法
BigDecimal result1 = num1.add(num2);
BigDecimal result12 = num12.add(num22);
//减法
BigDecimal result2 = num1.subtract(num2);
BigDecimal result22 = num12.subtract(num22);
//乘法
BigDecimal result3 = num1.multiply(num2);
BigDecimal result32 = num12.multiply(num22);
//绝对值
BigDecimal result4 = num3.abs();
BigDecimal result42 = num32.abs();
//除法
BigDecimal result5 = num2.divide(num1,20,BigDecimal.ROUND_HALF_UP);
BigDecimal result52 = num22.divide(num12,20,BigDecimal.ROUND_HALF_UP);System.out.println("加法用value结果 result1:"+result1);
System.out.println("加法用string结果 result12:"+result12);System.out.println("减法value结果:"+result2);
System.out.println("减法用string结果:"+result22);System.out.println("乘法用value结果 result3:"+result3);
System.out.println("乘法用string结果 result32:"+result32);System.out.println("绝对值用value结果 result4:"+result4);
System.out.println("绝对值用string结果 result42:"+result42);System.out.println("除法用value结果 result5:"+result5);
System.out.println("除法用string结果 result52:"+result52);
输出结果
加法用value结果 result1:4.399999999999999911182158029987476766109466552734375
加法用string结果 result12:4.4
减法value结果:0.399999999999999911182158029987476766109466552734375
减法用string结果:0.4
乘法用value结果 result3:4.799999999999999822364316059974953532218933105468750
乘法用string结果 result32:4.8
绝对值用value结果 result4:2
绝对值用string结果 result42:2
除法用value结果 result5:0.83333333333333336417
除法用string结果 result52:0.83333333333333333333
除法的八种舍入模式
1、ROUND_UP
舍入远离零的舍入模式。
在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。
注意,此舍入模式始终不会减少计算值的大小。
2、ROUND_DOWN
接近零的舍入模式。
在丢弃某部分之前始终不增加数字(从不对舍弃部分前面的数字加1,即截短)。
注意,此舍入模式始终不会增加计算值的大小。
3、ROUND_CEILING
接近正无穷大的舍入模式。
如果 BigDecimal 为正,则舍入行为与 ROUND_UP 相同;
如果为负,则舍入行为与 ROUND_DOWN 相同。
注意,此舍入模式始终不会减少计算值。
4、ROUND_FLOOR
接近负无穷大的舍入模式。
如果 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同;
如果为负,则舍入行为与 ROUND_UP 相同。
注意,此舍入模式始终不会增加计算值。
5、ROUND_HALF_UP
向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。
如果舍弃部分 >= 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同。
注意,这是我们大多数人在小学时就学过的舍入模式(四舍五入)。
6、ROUND_HALF_DOWN
向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为上舍入的舍入模式。
如果舍弃部分 > 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同(五舍六入)。
7、ROUND_HALF_EVEN
向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。
如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同;
如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。
注意,在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。
此舍入模式也称为“银行家舍入法”,主要在美国使用。四舍六入,五分两种情况。
如果前一位为奇数,则入位,否则舍去。
以下例子为保留小数点1位,那么这种舍入方式下的结果。
1.15>1.2 1.25>1.2
8、ROUND_UNNECESSARY
断言请求的操作具有精确的结果,因此不需要舍入。
示例
BigDecimal num1 = new BigDecimal("2.4");
BigDecimal num2 = new BigDecimal("2");BigDecimal result1 = num2.divide(num1,3,BigDecimal.ROUND_UP);
BigDecimal result2 = num2.divide(num1,3,BigDecimal.ROUND_DOWN);
BigDecimal result3 = num2.divide(num1,3,BigDecimal.ROUND_CEILING);
BigDecimal result4 = num2.divide(num1,3,BigDecimal.ROUND_FLOOR);
BigDecimal result5 = num2.divide(num1,3,BigDecimal.ROUND_HALF_UP);
BigDecimal result6 = num2.divide(num1,3,BigDecimal.ROUND_HALF_DOWN);
BigDecimal result7 = num2.divide(num1,3,BigDecimal.ROUND_HALF_EVEN);System.out.println("BigDecimal.ROUND_UP result1:"+result1);
System.out.println("BigDecimal.ROUND_DOWN result2:"+result2);
System.out.println("BigDecimal.ROUND_CEILING result3:"+result3);
System.out.println("BigDecimal.ROUND_FLOOR result4:"+result4);
System.out.println("BigDecimal.ROUND_HALF_UP result5:"+result5);
System.out.println("BigDecimal.ROUND_HALF_DOWN result6:"+result6);
System.out.println("BigDecimal.ROUND_HALF_EVEN result7:"+result7);
输出结果
BigDecimal.ROUND_UP result1:0.834
BigDecimal.ROUND_DOWN result2:0.833
BigDecimal.ROUND_CEILING result3:0.834
BigDecimal.ROUND_FLOOR result4:0.833
BigDecimal.ROUND_HALF_UP result5:0.833
BigDecimal.ROUND_HALF_DOWN result6:0.833
BigDecimal.ROUND_HALF_EVEN result7:0.833
这里要注意ROUND_UNNECESSARY如果相除是无限小数会报异常
BigDecimal num1 = new BigDecimal("2.4");
BigDecimal num2 = new BigDecimal("2");
BigDecimal result8 = num2.divide(num1,2,BigDecimal.ROUND_UNNECESSARY);
System.out.println("BigDecimal.ROUND_UNNECESSARY result8:"+result8);
输出结果
Exception in thread "main" java.lang.ArithmeticException: Rounding necessaryat java.math.BigDecimal.commonNeedIncrement(BigDecimal.java:4179)at java.math.BigDecimal.needIncrement(BigDecimal.java:4235)at java.math.BigDecimal.divideAndRound(BigDecimal.java:4143)at java.math.BigDecimal.divide(BigDecimal.java:5214)at java.math.BigDecimal.divide(BigDecimal.java:1564)at fking.Demo5.main(Demo5.java:35)
如果改成
BigDecimal num1 = new BigDecimal("2");
BigDecimal num2 = new BigDecimal("5");
BigDecimal result8 = num2.divide(num1,2,BigDecimal.ROUND_UNNECESSARY);
System.out.println("BigDecimal.ROUND_UNNECESSARY result8:"+result8);
输出结果
BigDecimal.ROUND_UNNECESSARY result8:2.50
总结结论
(1)商业计算使用BigDecimal。
(2)尽量使用参数类型为String的构造函数。
(3) BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以在做加减乘除运算时千万要保存操作后的值。
如果大家对java架构相关感兴趣,可以关注下面公众号,会持续更新java基础面试题, netty, spring boot,spring cloud等系列文章,一系列干货随时送达, 超神之路从此展开, BTAJ不再是梦想!
BigDecimal详细解析相关推荐
- OpenCL编程详细解析与实例
OpenCL编程详细解析与实例 C语言与OpenCL的编程示例比较 参考链接: https://www.zhihu.com/people/wujianming_110117/posts 先以图像旋转的 ...
- 深度学习目标检测详细解析以及Mask R-CNN示例
深度学习目标检测详细解析以及Mask R-CNN示例 本文详细介绍了R-CNN走到端到端模型的Faster R-CNN的进化流程,以及典型的示例算法Mask R-CNN模型.算法如何变得更快,更强! ...
- celery的使用(最新详细解析)
celery的使用(最新详细解析) 一. Celery简介 Celery是一个简单.灵活且可靠的,处理大量消息的分布式系统,专注于实时处理的异步任务队列,同时也支持任务调度. Celery的架构由三部 ...
- 汇编语言 第3版 王爽 检测点习题部分—答案及详细解析
第一章 基础知识 检测点1.1 (1)1个CPU的寻址能力为8KB,那么它的地址总线的宽度为()位. (2)1KB的存储器有() 个存储单元,存储单元的编号从()到() . (3)1KB的存储器可以存 ...
- Eclipse快捷键详细解析
android开发中常用的Eclipse快捷键详细解析 1.查看快捷键定义的地方 Window->Preferences->General->Keys. 2.更改启动页 在Andro ...
- AlphaCode到底强在哪儿?清华博士后十分钟视频详细解析
来源:机器之心 本文约2300字,建议阅读5分钟 AlphaCode 到底是怎么练成的? 春节期间,DeepMind 的编程版 AlphaGo--AlphaCode 一度火到刷屏.它可以编写与普通程序 ...
- mysql grant all详解_MySQL grant 语法的详细解析
以下的文章是MySQL grant语法的详细解析,如果你对MySQL grant 语法的相关的实际操作有兴趣的话,你就可以对以下的文章点击观看了.我们大家都知道MySQL数据库赋予用户权限命令的简单格 ...
- 线程同步锁 java_java多线程同步之重入锁,详细解析
上次已经为大家介绍过java多线程同步,Volatile详解的主要内容了.今天再来为大家介绍一些相关的内容,也就是java多线程同步之重入锁,一起来了解一下吧. 使用重入锁实现线程同步 在JavaSE ...
- 终端不能联网_详细解析物联网是什么?
原标题:详细解析物联网是什么? 物联网的英文是Internet of Things,缩写为IoT.这里的"物"指的是我身边一切能与网络联通的物品.例如你带的手表.你骑的共享单车.马 ...
最新文章
- 依赖倒转原则(Dependency Inversion Principle,DIP)
- guns 最新开源框架企业版下载_优秀!Github上10个开源免费的后台控制面板你值得拥有!...
- 九、序列参数集Sequence Paramater Set(SPS)解析
- [reference]-ARM core timeline
- 前端小技巧-定位的活学活用之仿淘宝列表
- 米家zigbee传感器抓包_如果有一代,米家人体传感器2值得你去更换吗?
- 随便贴两个漏洞,如 Apache JServ协议服务
- akka 消息发送接收_Akka型演员:探索接收器模式
- Qt UDP的初步使用
- linux pid t 头文件_linux系统调用相关头文件
- matlab 数字调制函数,matlab用于数字调制,几个函数的使用问题
- 收藏 | 清华团队将Transformer用到3D点云分割
- springsecurity 不允许session并行登录_Spring Security 实战干货:实现自定义退出登录...
- 小米推出售价 19999 元的 MIX Alpha;高通已向华为重启供货;.NET Core 3.0 发布 | 极客头条...
- vcenter报esxi主机 上行链路网络冗余丢失或网络冗余已降级
- vue 直接访问静态图片_在使用vue中实现本地静态图片路径(详细教程)
- Unity3D——AR小游戏
- 在QTCreator中保存某个文件出现:保存文件时发生错误:无法写入文件D:\test\test.h.磁盘已满?
- pyqt5中利用搜索框和按钮,搜索表中内容
- 微信小程序,几行代码实现图片瀑布流