BigDecimal的学习

BigDecimal

引入

在java语言中,double和float用于二进制浮点型计算,无法得到精确的结果。而BigDecimal则用于精确的计算。不超过16位有效数字(最好是不超过13位)的科学和工程计算,可以使用double和float,但要求精确计数或者超过了16位有效数字(超过13位也建议如此)的商业运算则需要使用BigDecimal进行运行,比如金融行业。

BigDecimal的介绍

BigDecimal 由任意精度的整数非标度值32 位的整数标度(scale)值 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负scale 次幂。因此,BigDecimal表示的数值是(unscaledValue × 10-scale)。

BigDecimal的构造方法

public BigDecimal(double val)
将 double 转换为 BigDecimal,后者是 double 的二进制浮点值准确的十进制表示形式。返回的 BigDecimal 的标度是使 (10scale × val) 为整数的最小值。

注意:

  1. 此构造方法的结果有一定的不可预知性。
BigDecimal bd = new BigDecimal(0.1);
System.out.println(bd);
结果:0.1000000000000000055511151231257827021181583404541015625
  1. 另一方面,String 构造方法是完全可预知的:写入 new BigDecimal(“0.1”) 将创建一个 BigDecimal,它正好 等于预期的 0.1。
BigDecimal bd = new BigDecimal("0.1525");
System.out.println(bd);
结果:0.152
  1. 当 double 必须用作 BigDecimal 的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用 Double.toString(double) 方法,然后使用 BigDecimal(String) 构造方法,将 double 转换为 String。要获取该结果,请使用 static valueOf(double) 方法。
double a = 0.1525;
BigDecimal bigDecimal = BigDecimal.valueOf(a);
System.out.println(bigDecimal);
结果:
0.1525
金融行业中

1) 优先使用String参数的构造方法;
2)如果需要通过double构造BigDecimal,有限使用valueOf(double val)方法;这样得到的BigDecimal和String参数的构造方法标度一致(即标度可控);
3)valueOf()的静态工厂方法优先于long、int等类型参数的构造方法,
4)如果想获取指定标度的初始化数值,比如2位小数的0,可以如下使用:
BigDecimal zero1 = new BigDecimal(“0.00”);
String的构造方法,会根据字符串的小数位来设定标度,其他的构造方法还需要额外调用setScale()来设定标度。

BigDecimal的标度、舍入方式
表示含义
CEILING向正无限大方向舍入的舍入模式。
DOWN向零方向舍入的舍入模式。
FLOOR向负无限大方向舍入的舍入模式。
HALF_DOWN向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向下舍入。
HALF_EVEN向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。
HALF_UP向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向上舍入。
UNNECESSARY用于断言请求的操作具有精确结果的舍入模式,因此不需要舍入。
UP远离零方向舍入的舍入模式。
BigDecimal的四则运算

public BigDecimal add(BigDecimal value); //加法
public BigDecimal subtract(BigDecimal value); //减法
public BigDecimal multiply(BigDecimal value); //乘法
public BigDecimal divide(BigDecimal value); //除法

double a = 0.1525;
String s = Double.toString(a);
BigDecimal bd1 = new BigDecimal(s);
BigDecimal bd2 = new BigDecimal("0.25888");
BigDecimal bd3 = bd1.add(bd2);
System.out.println(bd3);
double a = 0.125;
String s = Double.toString(a);
BigDecimal bd1 = new BigDecimal(s);
BigDecimal bd2 = new BigDecimal("0.3");
BigDecimal bd3 = bd1.divide(bd2);
System.out.println(bd3);
结果:ArithmeticException - 如果准确的商值没有无穷的十进制扩展

可以看出,无法精确表示商值时就会抛异常,而除法很大可能无法精确表示商值。所以,必须指定标度和舍入方式。以下几个重载方法可以供调用者指定标度和舍入方式。
public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
public BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode)
public BigDecimal divide(BigDecimal divisor, MathContext mc)

double a = 0.125;
String s = Double.toString(a);
BigDecimal bd1 = new BigDecimal(s);
BigDecimal bd2 = new BigDecimal("0.3");
BigDecimal bd3 = bd1.divide(bd2,5,FLOOR);
System.out.println(bd3);
结果:0.41666
BigDecimal的不可变性

BigDecimal有一个类似String的特性,就是不可变性。调用setScale或者add等运算方法后,原对象的scale和数值都不会改变,所以需要将方法的返回值进行保存使用。
比如:a = a.setScale(2); a = a.add(b). 其中a,b为BigDecimal对象。

总结

1)金融行业的金额一定要使用BigDecimal来表示;
2)BigDecimal最好使用String的构造方法创建,如果要使用double等数值作为参数,也要使用valueOf来创建对象。
3)BigDecimal进行四则运算时,最好指定其标度和舍入方式,否则可能抛异常。
4)BigDecimal是不可变的;四则运算后要使用对象保存结果;
5)多阅读相关API文档,写测试代码来验证其相关方法的调动,才能更好的掌握。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值