BigDecimal:踩坑

问题描述

两个BigDecimal相除, 抛了异常

原因分析:

Java 中使用 BigDecimal 做除法运算的时候,值有可能是无限循环的小数,结果是无限循环的小数,就会抛出上面这个异常。

来看看源码:

public BigDecimal divide(BigDecimal divisor) {
    // 省略N行
    BigDecimal quotient;
    MathContext mc = new MathContext( (int)Math.min(this.precision() + (long)Math.ceil(10.0*divisor.precision()/3.0), Integer.MAX_VALUE), RoundingMode.UNNECESSARY);
    try {
        quotient = this.divide(divisor, mc);
    } catch (ArithmeticException e) {
        throw new ArithmeticException("Non-terminating decimal expansion; " +
                                      "no exact representable decimal result.");
    }
}

是不是抛出来的异常跟我们堆栈里的一样,我们接着进入divide方法看看

private static BigDecimal divide(final long xs, int xscale, final long ys, int yscale, long preferredScale, MathContext mc) {
    ......
    quotient = divideAndRound(scaledXs, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
    ......
    // doRound, here, only affects 1000000000 case.
    return doRound(quotient,mc);
}

 接着进入divideAndRound方法

private static BigDecimal divideAndRound(long ldividend, long ldivisor, int scale, int roundingMode,
                                             int preferredScale) {

    int qsign; // quotient sign
    long q = ldividend / ldivisor; // store quotient in long
    if (roundingMode == ROUND_DOWN && scale == preferredScale)
        return valueOf(q, scale);
    long r = ldividend % ldivisor; // store remainder in long
    qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
    if (r != 0) {
        // 重点
        boolean increment = needIncrement(ldivisor, roundingMode, qsign, q, r);
        return valueOf((increment ? q + qsign : q), scale);
    } else {
        if (preferredScale != scale)
            return createAndStripZerosToMatchScale(q, scale, preferredScale);
        else
            return valueOf(q, scale);
    }
}

进入needIncrement方法

private static boolean needIncrement(long ldivisor, int roundingMode,
                                         int qsign, long q, long r) {
    assert r != 0L;

    int cmpFracHalf;
    if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
        cmpFracHalf = 1; // 2 * r can't fit into long
    } else {
        cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
    }

    return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, (q & 1L) != 0L);
}

 进入commonNeedIncrement方法

private static boolean commonNeedIncrement(int roundingMode, int qsign,
                                        int cmpFracHalf, boolean oddQuot) {
    switch(roundingMode) {
        case ROUND_UNNECESSARY:
            throw new ArithmeticException("Rounding necessary");
        ......
    }
}

最终进入了case第一个,此时roundingMode是7

倒着往上找,看看这个roundingMode从哪儿来的。

int roundingMode = mc.roundingMode.oldMode;

MathContext mc = new MathContext( (int)Math.min(this.precision() + (long)Math.ceil(10.0*divisor.precision()/3.0), Integer.MAX_VALUE), RoundingMode.UNNECESSARY);

终于找到源头了吧,就是在我们使用单个参数的divide方法时,默认给的就是7,如果除不尽,有这个限制。如果用1200除以12,可以除尽,就不会抛这个异常了。


解决方案:

JDK为我们提供了带精度的divide方法,当遇到这种除不尽的场景,可以很好的处理,综上,建议在用BigDecimal进行除法运算的时候,优先采用有精度控制的方法。

例如:

new BigDecimal("1200").divide(new BigDecimal("12"), 2, BigDecimal.ROUND_HALF_UP)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/596427.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++11,{}初始化,initializer_list,decltype,右值引用,类和对象的补充

c98是C标准委员会成立第一年的C标准&#xff0c;C的第一次更新是C03&#xff0c;但由于C03基本上是对C98缺陷的修正&#xff0c;所以一般把C98与C03合并起来&#xff0c;叫做C98/03&#xff1b; 后来原本C委员会更新的速度预计是5年更新一次&#xff0c;但由于C标准委员会的进…

SOLIDWORKS Electrical电气智能零部件的运用

电气2D向电气3D转型&#xff0c;3D模型无疑是重中之重&#xff0c;精准、正确的3D模型有利于电线长度、空间大小、耗材的计算。而线槽、导轨因为要根据实际情况裁剪&#xff0c;所以即使同一规格的线槽、导轨&#xff0c;在装配时也得根据实际情况&#xff0c;修改长度&#xf…

AAA、RADIUS、TACACS、Diameter协议介绍

准备软考高级时碰到的一个概念&#xff0c;于是搜集网络资源整理得出此文。 概述 AAA是Authentication、Authorization、Accounting的缩写简称&#xff0c;即认证、授权、记帐。Cisco开发的一个提供网络安全的系统。AAA协议决定哪些用户能够访问服务&#xff0c;以及用户能够…

linux系统-PXE高效批量网络装机

目录 一、PXE概述 PXE批量部署的优点 搭建PXE网络体系的前提条件 二、搭建PXE远程安装服务器 1.修改网络配置 2 .老样子关防火墙&#xff01;&#xff01;&#xff01;&#xff01; 3.确保挂载状态 和yum库 4. 安装TFTP服务 5.修改TFTP服务的配置文件 6.启动服务 7…

概念解析 | 基础模型:AI时代的“形而上学“

注1:本文系"概念解析"系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:基础模型(Foundation Models) 概念解析 | 基础模型:AI时代的"形而上学" What Are Foundation Models? | NVIDIA Blogs 第一部分:通俗解释 基础模型(…

echars设置渐变颜色的方法

在我们日常的开发中&#xff0c;难免会遇到有需求&#xff0c;需要使用echars设置渐变的图表&#xff0c;如果我们需要设置给图表设置渐变颜色的话&#xff0c;我们只需要在 series 配置项中 添加相应的属性配置项即可。 方式一&#xff1a;colorStops type&#xff1a;‘lin…

this关键字

this 文章目录 this引出Thisthis的作用this.属性内存分析 this.方法名this(&#xff09;构造方法 概念&#xff1a;this 关键字是 Java常用的关键字&#xff0c;可用于任何实例方法内指向当前对象&#xff0c;也可指向对其调用当前方法的对象&#xff0c;可以将this理解为一个指…

被问了n遍的小程序地理位置权限开通方法

小程序地理位置接口有什么功能&#xff1f; 在平时我们在开发小程序时&#xff0c;难免会需要用到用户的地理位置信息的功能&#xff0c;小程序开发者开放平台新规要求如果没有申请开通微信小程序地理位置接口( getLocation )&#xff0c;但是在代码中却使用到了相关接口&#…

【3dmax笔记】023:阵列工具(移动+一维+二维+三维)

文章目录 一、阵列工具二、案例演示 一、阵列工具 【阵列】命令将显示【阵列】对话框&#xff0c;使用该对话框可以基于当前选择创建对象阵列。 菜单栏&#xff1a;【工具】菜单 > 【阵列】 二、案例演示 首先&#xff0c;画一个物体&#xff0c;如茶壶&#xff0c;如下图…

Ps 中 曲线和色阶的区别在哪里?

【官方解释】 在Photoshop中&#xff0c;曲线&#xff08;Curves&#xff09;和色阶&#xff08;Levels&#xff09;是两种调整图像色调和对比度的工具&#xff0c;它们有一些相似之处&#xff0c;但也有一些重要的区别。 调整方式: 曲线&#xff08;Curves&#xff09;&…

04-19 周四 GitHub CI 方案设计

04-19 周四 GitHub CI 方案设计 时间版本修改人描述2024年4月19日14:44:23V0.1宋全恒新建文档2024年4月19日17:22:57V1.0宋全恒完成部署拓扑结构的绘制和文档撰写 简介 需求 由于团队最近把代码托管在GitHub上&#xff0c;为解决推理、应用的自动化CI的需要&#xff0c;调研了…

【C语言刷题系列】移除元素

目录 一、问题描述 二、解题思路 三、源代码 个人主页&#xff1a; 倔强的石头的博客 系列专栏 &#xff1a;C语言指南 C语言刷题系列 一、问题描述 二、解题思路 在C语言中&#xff0c;原地移除数组中所有等于特定值的元素并返回新长度的问题可以通过双指针法…

虚拟化之---virtio通信

一、理解virtio的背景 我们知道虚拟化hypervisor大的类型分为两种&#xff0c;全虚拟化和半虚拟化。 在全虚拟化的解决方案中&#xff0c;guest VM 要使用底层 host 资源&#xff0c;需要 Hypervisor 来截获所有的请求指令&#xff0c;然后模拟出这些指令的行为&#xff0c;这样…

python-dict序列化的数据为啥前后不一致

前情提要及背景:流式数据的二次处理终结篇-CSDN博客 假如直接将dict进行str,那么编码数据都是一致的,但是在postman上就表现不那么好看,如下: 而之前的显示如下: 其中的差别就是单引号与双引号的差别了。 采用如下方案无疑是最笨的方法了: 在Python中,如果你想将处理…

各城市-人口就业和工资数据(1978-2022年)

这份数据收集了1978年至2022年间300多个地级市的人口、就业和工资等数据。涵盖的指标包括从业人员数量、平均工资水平、人口密度等&#xff0c;通过这些数据可以深入了解中国各地城市的人口结构、就业状况以及工资水平的变化趋势。这些数据对于研究城市发展、劳动力市场以及区域…

微积分 --- 偏导数,方向导数与梯度(二)

方向导数 上图为一温度图&#xff0c;所反映的是加利福利亚洲和内华达州在十月的一天下午三点的温度。其中&#xff0c;图中的每一点都是温度T关于x,y的函数&#xff0c;即T(x,y)。对于图中的Reno市而言&#xff0c;沿着x方向的偏导反映的是温度沿着x方向&#xff0c;即沿着东方…

【搜索技能】外链

文章目录 前言一、外链是什么&#xff1f;二、如何进行外链调查&#xff1f;总结 前言 今儿因为在搜索一个很感兴趣的软件&#xff0c;但是软件信息所在的网址非常有限。因此产生了一个念头&#xff1a;我能不能找到所有的包含了或者是引用了这个网站的网站呢? 调查之下&…

五道链表习题,只过思路

建议先过一遍&#xff1a;保研机试前的最后七道链表题-CSDN博客 第一题 82. 删除排序链表中的重复元素 II - 力扣&#xff08;LeetCode&#xff09; 是不是似曾相识的感觉&#xff0c;好像数组顺序去重&#xff0c;请看&#xff1a;保研机试前的最后七道数组题-CSDN博客 第二…

幻兽帕鲁游戏主机多少钱?幻兽帕鲁游戏服务器一个月仅需32元

随着游戏产业的蓬勃发展&#xff0c;腾讯云紧跟潮流&#xff0c;推出了针对热门游戏《幻兽帕鲁Palworld》的专属游戏服务器。对于广大游戏爱好者来说&#xff0c;这无疑是一个激动人心的消息。那么&#xff0c;腾讯云幻兽帕鲁游戏主机到底多少钱呢&#xff1f;让我们一起来揭晓…

编程基础学什么课程内容

编程基础学习的课程内容有&#xff1a;程序设计基础、算法与数据结构、计算机科学原理、面向对象编程、网页开发基础等课程内容&#xff0c;以下是上大学网 (www.sdaxue.com)整理的具体课程或技能领域内容&#xff0c;供大家参考&#xff01; 程序设计基础&#xff08;或计算机…