使用BigDecimal除法的时候,遇到了鬼畜的问题。 预想的精度计算结果回到了0。 当然,最终我意识到姿势不对。 因此,请记录下来,以免以后重复同样的事情
使用
I. 问题抛出
bigdecimal进行高精度除法时,不小心遇到了小问题。 如下所示@Test
公共语音测试比特医学(
bigdecimal origin=新bigdecimal (541253;
bigdecimal now=新bigdecimal (12389431;
bigdecimal val=origin.divide (新,循环模式.半_上);
系统输出打印(val;
origin=新二进制数字(541253;
now=newbigdecimal(12389431.3;
val=origin.divide (新,循环模式.半_上);
系统输出打印(val;
origin=新二进制数字(541253.4;
now=newbigdecimal(12389431;
val=origin.divide (新,循环模式.半_上);
system.out.println (值;
}上面的输出是什么?
0
0
0.043686703610520937021487456961257为什么前面两个会变成0呢? 如果直接541253/12389431=0的话可以理解,但BigDecimal不是高精度的计算吗? 按理说不会发生这样的一刀切的问题吧
我知道当BigDecimal成为触发器时,可以指定保存小数的参数,但是添加它会有所不同吗?
bigdecimal origin=新bigdecimal (541253;
bigdecimal now=新bigdecimal (12389431;
bigdecimal val=origin.divide (新,5,循环模式.半_上);
系统输出打印(val; 输出结果为:
因为是0.04369,所以指定预约小数后没有问题。 因此,在上述几个case中,如果没有指定scale值,则由于默认值不同,所以大胆推测最终结果的精度是否不同。
如果简单地深入分析源代码,就会发现origin.divide(now,RoundingMode.HALF_UP ); 因此,该scale参数以origin对象为目标。 这个对象没有其他地方可以使用,所以只能分析结构
II. 源码定位
1. 整形传参构造
分析以下行并直接访问源代码bigdecimal origin=新bigdecimal (541253; 因为是明显的int传参结构,所以我们进去简单看看吧
//Java.math.bigdecimal # bigdecimal (int ) )。
公共视觉(国际) {
this.int压缩=val;
this.scale=0;
this.intval=空值;
}
公共生物医学(长值) {
this.int压缩=val;
this.intVal=(val==INFLATED )? inflated _ bigint :空值;
this.scale=0;
) so清楚地知道缺省比例为0。 也就是说,如果origin为正数,那么除法实际上如果未指定scale参数,则会返回小数。 同样,一眼就可以看出long的传播方式。 big整合器也一样
2. 浮点传参
其次,确认了浮点的scale默认值。 因为这个结构比之前的复杂一点,所以不粘贴源代码。 太长了,我不太清楚做了什么。 直接以不俗的方法进入调试模式,单步执行@Test
公共语音测试比特医学(
bigdecimal origin=新bigdecimal (541253.0;
bigdecimal now=新bigdecimal (12389431.1;
bigdecimal tmp=新bigdecimal (0.0;
根据debug的结果,第一个,scale为0; 第二个比例为29,第三个比例为0
3. String传参
仍然是一个大逻辑,同样以单步调试的方式尝试@Test
公共语音测试比特医学(
bigdecimal origin=新bigdecimal (' 541253.0 );
bigdecimal now=新bigdecimal (12389431.1 );
bigdecimal t=新bigdecimal (' 0.0 );
}上面的三个scale都是1
对
4. 小结
BigDecimal进行除法运算时,优选指定其scale参数。 否则,可能有坑对BigDecimla的scale初始化原理。 详细看看bigdecimal是如何实现的,最后贴上乘法的图作为结束