必威体育Betway必威体育官网
当前位置:首页 > IT技术

BigDecimal 精度问题

时间:2019-10-11 10:14:23来源:IT技术作者:seo实验室小编阅读:80次「手机版」
 

bigdecimal

今天在做一个需求,遇到了一点问题,模拟代码如下:

// 小计
bigdecimal subtotal = new BigDecimal(1000000);
// 变更后数量
BigDecimal afterChangeTotal = new BigDecimal(300001);
Mathcontext mathContext = new MathContext(3, RoundingMode.UP);
BigDecimal result =  afterChangeTotal.subtract(subtotal.multiply(new BigDecimal(0.3), mathContext)).pide(subtotal, mathContext);
BigDecimal deductedAdvance = new BigDecimal(0);

if(result.compareTo(deductedAdvance) > 0){
    BigDecimal multiply = result.multiply(new BigDecimal(2), mathContext);		
    BigDecimal multiply2 = subtotal.multiply(new BigDecimal(0.1));
    deductedAdvance = multiply.multiply(multiply2, mathContext);
}
System.out.println(deductedAdvance.toString());

然后我发现 这一行算出来精度怎么都不对

 BigDecimal multiply2 = subtotal.multiply(new BigDecimal(0.1));

运行时值为这么大,照理说1000000 * 0.1 就是整整 100000; 怎么会带上这么多小数。

然后我想这给他做了格式化,没想到格式化了更糟糕...

我开始觉得我哪里写的有问题了,然后我把代码分开:

BigDecimal multiply2 = subtotal.multiply(bigDecimal);

改为:

BigDecimal bigDecimal = new BigDecimal(0.1);

BigDecimal multiply2 = subtotal.multiply(bigDecimal);
然后查看bigDecimal 这个值是多少

最终发现原来是new 出来的这个BigDecimal的问题,然后我查阅了下JDK API帮助文档,介绍如下:

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

注: 
此构造方法的结果有一定的不可预知性。有人可能认为在 java 中写入 new BigDecimal(0.1) 所创建的 BigDecimal 正好等于 0.1(非标度值 1,其标度为 1),
但是它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 无法准确地表示为 double(或者说对于该情况,
不能表示为任何有限长度的二进制小数)。这样,传入 到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。 另一方面,String 构造方法是完全可预知的:
写入 new BigDecimal("0.1") 将创建一个 BigDecimal,它正好 等于预期的 0.1。因此,比较而言,通常建议优先使用 String 构造方法。 
当 double 必须用作 BigDecimal 的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用 Double.toString(double) 方法,
然后使用 BigDecimal(String) 构造方法,将 double 转换为 String。要获取该结果,请使用 static valueOf(double) 方法。 

参数:
val - 要转换为 BigDecimal 的 double 值。 
抛出: 
numberformatexception - 如果 val 为无穷大或 NaN。

从API文档介绍中可以知道,这个double的构造方法他可能无法正确的构建BigDecimal, 如果需要构建建议使用带String的构造方法也可以使用BigDecimal.valueOf(double) 方法来构建, 方法内容如下:

public static BigDecimal valueOf(double val) {
    // Reminder: a zero double returns '0.0', so we cannot fastpath
    // to use the constant ZERO.  This might be important enough to
    // justify a factory APProach, a cache, or a few private
    // constants, later.
    return new BigDecimal(Double.toString(val));
}

其实看看可以看到,他也是把double数值先转成String, 然后使用带String的构造器创建对象。

总结:

构建BigDecimal时尽量使用下面两种方法构建,以免发生一些不必要,或难以想象的错误。 

public BigDecimal(String val) ;
public static BigDecimal valueOf(double val);

相关阅读

BigDecimal基本知识

在我们的日常计算中,有时会涉及到比较大的数字之间的计算(如:超大金额的计算,如果是韩元等的话,还要大),这时,使用float、double这样的

BigDecimal比较数据大小

上周遇到个需求是上传文件的大小不能超过5M,因为想尝试着获取准确值,所以使用了BigDecimal类来计算,而通常使用的float和double在计

高精度定位的几种解决方案

高精度定位解决途径 常见的高精度定位解决途径有三种:RTK、SBAS、“中国精度”星基增强服务。 1. RTK 载波相位差分技术又称RTK(Re

BigDecimal比较大小问题

BigDecimal比较大小  这个类是Java里精确计算的类,下面说一下两个BigDecimal对象大小,相等的判断  1比较对象是否相等一般的对象

BigDecimal比较大小的时候,比较结果与实际不符的情况

https://blog.csdn.net/qq_33451004/article/details/71247041 比较大小的时候最好不要使用new BigDecimal(xx)来比较,而应该使

分享到:

栏目导航

推荐阅读

热门阅读