当前位置:首页 > Java技术 > BigDecimal 精度问题

BigDecimal 精度问题

2022年11月06日 08:37:05Java技术8

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

// 小计
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)).divide(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 精度问题 _ JavaClub全栈架构师技术笔记


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

BigDecimal 精度问题 _ JavaClub全栈架构师技术笔记


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

BigDecimal multiply2 = subtotal.multiply(bigDecimal);

改为:

BigDecimal bigDecimal = new BigDecimal(0.1);

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

BigDecimal 精度问题 _ JavaClub全栈架构师技术笔记


最终发现原来是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);

作者:无需有太多
来源链接:https://blog.csdn.net/qq_35170213/article/details/79992430

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/68110.html

标签: BigDecimal
分享给朋友:

“BigDecimal 精度问题” 的相关文章

【java提高】(19)---BigDecimal详解和精度问题

【java提高】(19)---BigDecimal详解和精度问题

BigDecimal详解和精度问题 一、背景 在实际开发中,对于 不需要任何准确计算精度的属性可以直接使用float或double,但是如果需要精确计算结果,则必须使用BigDecimal,例如价格、质量。 为什么这么说,主要有两点...

BigDecimal的使用

JAVA中有两个类BigInteger和BigDecimal分别表示大整数类和大浮点数类,至于两个类的对象能表示最大范围不清楚,理论上能够表示无线大的数,只要计算机内存足够大。 这两个类都在java.math.*包中,因此每次必须在开头处引用该包。   Ⅰ基...

BigDecimal 使用方法详解

BigDecimal 使用方法详解 博客分类:   java基础 bigdecimal multiply add divide  BigD...

java BigDecimal List求和

BigDecimal totalPrice=list.stream().map(DictRegisterClassVsChargeVO::getPriceFirst).reduce(BigDecimal.ZERO, BigDecimal::add);...

BigDecimal精确度问题

BigDecimal精确度问题

BigDecimal精确度问题 来源于关注Hollis公众号,认为很有用在此记录和分享; 很多涉及金额计算不能使用double、float等类型,而是使用精确度更高的bigdecimal; 所以,很多支付、电商、金融等业务中,BigDe...

Java中需要精确计算的,不要用float, double, 请用BigDecimal

float,double都有误差,适合做科学计算或工程计算,像商业应用,特别是购物,计费等系统,就一定要用这个BigDecimal,精确。 比如我们定义一个double是0.01,可能将来打印出来或计算的时候,实际上是0.010000000003456这样的数值,那么...

大数处理类BigInteger和BigDecimal浅谈

大数处理类BigInteger和BigDecimal浅谈

这两个类位于java.math包内,要使用它们必须在类前面引用该包:import java.math.BigInteger;和import java.math.BigDecimal; BigInteger和BigDecimal分别表示不可变的任意精度的整数和不可变的有符号的...

BigDecimal加减乘除计算

BigDecimal加减乘除计算

BigDecimal初始化 BigDecimal一共有4个构造方法: BigDecimal(int) 、BigDecimal(double) 、BigDecimal(long) 、BigDecimal(String) 当double必须用作B...

BigDecimal和int,float,double之间的转换,以及BigDecimal的四则运算和MathContext用法

BigDecimal和int,float,double之间的转换,以及BigDecimal的四则运算和MathContext用法 原文链接:https://blog.csdn.net/fightinglongshao/article/details...

string 与BigDecimal互转

小编知道在java中数据类型非常 的严格了,我们如果一个地方不小心就会导致应用出问题了,今天 小编就在string 转BigDecimal上碰到了一些问题,下面整理了几个例子大家一起来看看。   例子1,string 转BigDecim...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。