BigDecimal是什么?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.300000000000000040.199999999999999980.0200000000000000042.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=2bDouble=2.399999999999999911182158029987476766109466552734375bString=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.4bDouble2=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.834BigDecimal.ROUND_DOWN result2:0.833BigDecimal.ROUND_CEILING result3:0.834BigDecimal.ROUND_FLOOR result4:0.833BigDecimal.ROUND_HALF_UP result5:0.833BigDecimal.ROUND_HALF_DOWN result6:0.833BigDecimal.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不再是梦想!
标签:
相关推荐:
最新新闻:
- 微资讯!html常用长度度量单位 度量长度的单位是什么?
- 怎么使用java修改端口?springboot打包项目
- “红兔大展”演绎生肖酒文化,五粮浓香借创意快闪传递C端情深
- 焦点观察:心理测试小游戏有哪些?真的准吗?
- BigDecimal是什么?BigDecimal详细解析 -天天速递
- 天天观速讯丨ABAP自定义截取字符串长度函数 截取字符串长度的函数
- 【世界时快讯】遗传算法实例有哪些?函数的最大值怎么解?
- 回顾历史事件:首台通用电子计算机的发明者诞生 谷歌推出第一个涂鸦
- FBI的WARNING是什么?简单的静态代码检测规则_当前快看
- 当前快播:pps是什么格式?洪恩MDF格式用什么软件打开?
- mysql报错的解决方法 内部异常堆栈跟踪的结尾
- 每日快播:为什么需要命名空间?使用命名空间解决名字冲突
- 数学笔记有哪些?数学无穷级数和收敛判定
- 世界快报:域名访问升级怎么操作?追踪域名指向的IP地址
- 如何解决电脑文件夹打不开的情况?电脑文件夹打不开怎么解决?
- 热点评!为什么要使用框架?使用软件框架的优点总结
- Excel表格中的VALUE函数公式如何使用?VALUE函数使用教程
- bmp是什么格式?bmp文件怎么打开?
- macfee怎么用?macfee使用教程
- torrent是什么文件?torrent文件介绍?
- Tencent Files文件夹在哪?tencent files文件夹能删除吗?
- 什么是子网掩码?如何划分子网?
- windows无法完成格式化怎么办?windows无法完成格式化2种解决方案
- Facetime怎么用?Facetime详细使用指南
- 网线应该怎么接?网线水晶头做法标准
- pdf是什么格式?pdf格式介绍
- 怎么将U盘制作成DOS启动盘?U盘制作成DOS启动盘方法
- 三星P7500怎么刷机?三星P7500刷机教程
- 系统光盘怎么刻录?系统光盘刻录步骤
- 如何快速制作flash banner?制作flash banner步骤
- Win8每次开机gwx.exe进程都会自动启动怎么解决?解决方法
- KB2565063更新补丁是什么?KB2565063可以卸载吗?
- 百度云登陆失败总是显示网络连接失败该怎么办?解决方法
- 临时文件夹在哪?Win10临时文件夹的路径在哪?
- 怎么查看惠普电脑保修截止日期?惠普电脑保修截止日期查看方法
- 药企组团出国“抢单”,投资人“疯狂”加码低估的biotech,牛市启动了?
- TGA 2022:《猎天使魔女起源:Cereza and the Lost Demon》正式公布!明年3.17发售
- TGA 2022:《生化奇兵》之父新作《Judas》公布-全球最资讯
- TGA 2022:解谜游戏《Viewfinder》预告 支持简中 当前信息
- TGA 2022:《Among Us》捉迷藏新模式公布 12月9日发布_世界热资讯
- 抑郁症患者“阳了”之后,慎用这几种常见感冒药
- Windows 11即将支持原生录屏功能 全球速读
- 焦点速看:TGA 2022:生存恐怖游戏《创伤后》公布
- 世界即时看!TGA2022:《猎天使魔女:起源》公开 2023年3月17日发售
- TGA 2022:《自杀小队:杀死正义联盟》新预告:蝙蝠侠亮相!明年5.26发售
- TGA 2022:《Replaced》新预告 2023年正式发售 全球今亮点
- 接连减持!豪取11连板的天鹅股份,股东、高管要 “套现”了?
- TGA 2022:《死亡细胞》×《恶魔城》DLC预告:明年Q1推出
- 热门看点:《战地4》制作人回归DICE 领导开发该系列
- 《侏罗纪世界:进化2》资料片宣传片:前往地中海!-天天最新
- 灵感来自微信:微软计划开发一站式“超级应用”-天天时讯
- 首发用户杯具了!消息称RTX 4080要降价几千 你会买吗?
- 新固件更新惹祸:AirPods Pro 2出现严重掉电问题
- 千呼万唤始出来:Win11原生录屏功能即将上线 今日精选
- iPhone 15 Flip折叠屏手机渲染图曝光:最早明年发布_环球微动态
- 每日关注!真人互动恋爱游戏《十个约会》明年情人节上市
- 田园风格冒险游戏《邮件时间》明年4月登陆各平台
- 天天简讯:《三维弹球FX》确定明年2月登陆主机平台
- 日式休闲冒险游戏《峰子的夜市》延期至2023年
- 狼崽与小鹿的友情冒险《白之旅》情人节上市
- 英特尔酷睿i9-13900KS完整规格曝光,全球首个6GHz功耗大惊喜 全球焦点
- Edge和谷歌浏览器 均已放弃支持Win7/8.1|环球速递
- 今日观点!1滴血验癌骗子公司又一高管被判11年
- 改造后,厨房使用大变样!集成灶果然是神器:每日资讯
- 人民币6600以上!戴森降噪耳机净化面罩上市了
- 环球即时看!法兴:政府开支问题不解决 央行加息将难以为继
- 标普有望止步五日连跌,纳斯达克中国金龙指数涨超5%,美油一度涨4%:每日动态
- 【天天新视野】码头工人的“失落”叙事与基隆港的兴衰史
- 《暗黑破坏神4》公布新过场截图:仍为开发中画面|今日视点
- 世界今热点:制片人证实:《阿凡达5》将会前往地球
- 欧盟统一接口确定:苹果iPhone必须换USB-C 天天热资讯
- 视讯!《勇者斗恶龙宝藏》概述预告公开 12月9日登陆Switch
- Epic喜加一:《黑道圣徒4:改选》《暴走枪姬》免费、下周神秘游戏|焦点播报
- 天天看点:EA狩猎游戏《狂野之心》官方PC配置需求公布
- 单车旅行游戏《寄梦远方》明年1/31日发售:天天日报