简介

​ 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

几种常用函数

  1. 加:BigDecimal add(BigDecimal augend)

  2. 减:BigDecimal subtract(BigDecimal subtrahend)

  3. 乘:BigDecimal multiply(BigDecimal multiplicand)

  4. 除法:BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)

    (BigDecimal divisor 除数, int scale 精确小数位, int roundingMode 舍入模式)

  5. 绝对值: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详细解析相关推荐

  1. OpenCL编程详细解析与实例

    OpenCL编程详细解析与实例 C语言与OpenCL的编程示例比较 参考链接: https://www.zhihu.com/people/wujianming_110117/posts 先以图像旋转的 ...

  2. 深度学习目标检测详细解析以及Mask R-CNN示例

    深度学习目标检测详细解析以及Mask R-CNN示例 本文详细介绍了R-CNN走到端到端模型的Faster R-CNN的进化流程,以及典型的示例算法Mask R-CNN模型.算法如何变得更快,更强! ...

  3. celery的使用(最新详细解析)

    celery的使用(最新详细解析) 一. Celery简介 Celery是一个简单.灵活且可靠的,处理大量消息的分布式系统,专注于实时处理的异步任务队列,同时也支持任务调度. Celery的架构由三部 ...

  4. 汇编语言 第3版 王爽 检测点习题部分—答案及详细解析

    第一章 基础知识 检测点1.1 (1)1个CPU的寻址能力为8KB,那么它的地址总线的宽度为()位. (2)1KB的存储器有() 个存储单元,存储单元的编号从()到() . (3)1KB的存储器可以存 ...

  5. Eclipse快捷键详细解析

    android开发中常用的Eclipse快捷键详细解析 1.查看快捷键定义的地方 Window->Preferences->General->Keys. 2.更改启动页 在Andro ...

  6. AlphaCode到底强在哪儿?清华博士后十分钟视频详细解析

    来源:机器之心 本文约2300字,建议阅读5分钟 AlphaCode 到底是怎么练成的? 春节期间,DeepMind 的编程版 AlphaGo--AlphaCode 一度火到刷屏.它可以编写与普通程序 ...

  7. mysql grant all详解_MySQL grant 语法的详细解析

    以下的文章是MySQL grant语法的详细解析,如果你对MySQL grant 语法的相关的实际操作有兴趣的话,你就可以对以下的文章点击观看了.我们大家都知道MySQL数据库赋予用户权限命令的简单格 ...

  8. 线程同步锁 java_java多线程同步之重入锁,详细解析

    上次已经为大家介绍过java多线程同步,Volatile详解的主要内容了.今天再来为大家介绍一些相关的内容,也就是java多线程同步之重入锁,一起来了解一下吧. 使用重入锁实现线程同步 在JavaSE ...

  9. 终端不能联网_详细解析物联网是什么?

    原标题:详细解析物联网是什么? 物联网的英文是Internet of Things,缩写为IoT.这里的"物"指的是我身边一切能与网络联通的物品.例如你带的手表.你骑的共享单车.马 ...

最新文章

  1. 依赖倒转原则(Dependency Inversion Principle,DIP)
  2. guns 最新开源框架企业版下载_优秀!Github上10个开源免费的后台控制面板你值得拥有!...
  3. 九、序列参数集Sequence Paramater Set(SPS)解析
  4. [reference]-ARM core timeline
  5. 前端小技巧-定位的活学活用之仿淘宝列表
  6. 米家zigbee传感器抓包_如果有一代,米家人体传感器2值得你去更换吗?
  7. 随便贴两个漏洞,如 Apache JServ协议服务
  8. akka 消息发送接收_Akka型演员:探索接收器模式
  9. Qt UDP的初步使用
  10. linux pid t 头文件_linux系统调用相关头文件
  11. matlab 数字调制函数,matlab用于数字调制,几个函数的使用问题
  12. 收藏 | 清华团队将Transformer用到3D点云分割
  13. springsecurity 不允许session并行登录_Spring Security 实战干货:实现自定义退出登录...
  14. 小米推出售价 19999 元的 MIX Alpha;高通已向华为重启供货;.NET Core 3.0 发布 | 极客头条...
  15. vcenter报esxi主机 上行链路网络冗余丢失或网络冗余已降级
  16. vue 直接访问静态图片_在使用vue中实现本地静态图片路径(详细教程)
  17. Unity3D——AR小游戏
  18. 在QTCreator中保存某个文件出现:保存文件时发生错误:无法写入文件D:\test\test.h.磁盘已满?
  19. pyqt5中利用搜索框和按钮,搜索表中内容
  20. 微信小程序,几行代码实现图片瀑布流

热门文章

  1. 查看java项目线程运行情况,以及总线程数
  2. 有关optimizer.param_groups用法的示例分析
  3. DolphinScheduler 邮件告警设置
  4. 历史上十大杰出的皇帝
  5. WinEdt入门使用总结
  6. python爬虫教程书籍-Python爬虫教程-爬取豆瓣读书
  7. 七夕到了,还在加班?98后小哥哥教你用 sula 快速配置页面提前下班去约会
  8. MacType最强配置图解
  9. Ubuntu20.04修复网络不显示问题
  10. 电脑自动跳出各种传奇广告怎么解决