BigDecimal类型加减乘除运算(Java必备知识)

2023-11-14

在现实开发当中经常会遇到这种计算,这里特此整理一下为方便以后学习,希望能帮助到其他的萌新。

1、为什么要用BigDecimal计算?

因为 float, double等浮点的存储和操作(比如:相加,相减…)存在误差(7.22f - 7.0f = 0.21999979 而不是 0.22)。

2、浮点计算误差产生的原因

将十进制数转为二进制,在计算机运行中本就存在误差
来看一个例子:将十进制的0.2转化为二进制,按照乘二取整法

0.2 * 2 = 0.4 0
0.4 * 2 = 0.8 0
0.8 * 2 = 1.6 1
0.6 * 2 = 1.2 1
… … …
0.2*2 = 0.4 0

很明显,已经进入了无限循环,受有效位数23位的影响,也就是说,存入计算机中的十进制数不是精准的。
float的有效位数只有7位有效数字,如果一个大数和一个小数相加时,会产生很大的误差,因为尾数得截掉好多位。

3、bigdecimal的初始化

Bigdecimal的初始化时用尽量用String,假如传的是浮点类型,会丢失精度。阿里的开发规范当中也明确说明了。

这一点在BigDecimal类的构造方法注释中有说明。

	BigDecimal num1 = new BigDecimal(0.005);
	BigDecimal num2 = new BigDecimal(1000000);
	
    BigDecimal string1 = new BigDecimal("0.005");
    BigDecimal string2 = new BigDecimal("1000000");
    
    System.out.println(num1);
    System.out.println(num2);
    System.out.println(string1);
    System.out.println(string2);

输出结果:

4、bigdecimal的加减乘除

	BigDecimal num1 = new BigDecimal("11.111");
    BigDecimal num2 = new BigDecimal("1");
    BigDecimal num3 = new BigDecimal("-11.111");
    
    //加法
    BigDecimal result1 = num1.add(num2);
    System.out.println("num1 + num2 = " + result1);
    
    //减法
    BigDecimal result2 = num1.subtract(num2);
    System.out.println("num1 - num2 = " + result2);

    //乘法
    BigDecimal result3 = num1.multiply(num2);
    System.out.println("num1 * num2 = " + result3);

    //除法(保留小数20位)
    BigDecimal result5 = num1.divide(num2,20,BigDecimal.ROUND_HALF_UP);
    System.out.println("num1 / num2 = " + result5);
    
    //绝对值
    BigDecimal result4 = num3.abs();
    System.out.println("num3的绝对值  = " + result4);

输出结果

5、除法divide()参数使用

使用除法函数在divide的时候要设置各种参数,要精确的小数位数和舍入模式,不然会出现报错

我们可以看到divide函数配置的参数如下
在这里插入图片描述
BigDecimal divisor 除数, int scale 精确小数位, int roundingMode 舍入模式

6、八种舍入模式解释如下

6.1、ROUND_UP

舍入远离零的舍入模式。

在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。

注意,此舍入模式始终不会减少计算值的大小。

6.2、ROUND_DOWN

接近零的舍入模式。

在丢弃某部分之前始终不增加数字(从不对舍弃部分前面的数字加1,即截短)。

注意,此舍入模式始终不会增加计算值的大小。

6.3、ROUND_CEILING

接近正无穷大的舍入模式。

如果 BigDecimal 为正,则舍入行为与 ROUND_UP 相同;

如果为负,则舍入行为与 ROUND_DOWN 相同。

注意,此舍入模式始终不会减少计算值。

6.4、ROUND_FLOOR

接近负无穷大的舍入模式。

如果 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同;

如果为负,则舍入行为与 ROUND_UP 相同。

注意,此舍入模式始终不会增加计算值。

6.5、ROUND_HALF_UP

向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。

如果舍弃部分 >= 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同。

注意,这是我们大多数人在小学时就学过的舍入模式(四舍五入)。

6.6、ROUND_HALF_DOWN

向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为上舍入的舍入模式。

如果舍弃部分 > 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同(五舍六入)。

6.7、ROUND_HALF_EVEN

向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。

如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同;

如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。

注意,在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。

此舍入模式也称为“银行家舍入法”,主要在美国使用。四舍六入,五分两种情况。

如果前一位为奇数,则入位,否则舍去。

以下例子为保留小数点1位,那么这种舍入方式下的结果。

1.15>1.2 1.25>1.2

6.8、ROUND_UNNECESSARY

断言请求的操作具有精确的结果,因此不需要舍入。

如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。

注意:一般无特殊情况下,我们都是用的ROUND_HALF_UP(四舍五入)

7、保留小数位

开发当中经常会遇到浮点保留两位小数,这里我们也可以利用BigDecimal 来进行保留。

BigDecimal bg = new BigDecimal("0.005");
double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

8、比较大小

等于:new BigDecimal(“123.123”).compareTo(new BigDecimal(“123.123”))==0 —> true
小于:new BigDecimal(“123.122”).compareTo(new BigDecimal(“123.123”)) < 0 —> true就证明左边小于右边
大于:new BigDecimal(“123.124”).compareTo(new
BigDecimal(“123.123”)) > 0 —> true就证明左边大于右边

9、公共方法

以下是我在开发过程当中两数相除求百分比,写的一些简单的方法,感觉有用呢你可以直接拿去用。

	/**
	 * @Title: flotTwoDecimals 
	 * @author gzl
	 * @date 2021年3月31日上午12:59:11
	 * @Description: 传入浮点类型保留两位返回BigDecimal类型
	 */
	public static BigDecimal flotTwoDecimals(Double num) {
		if(!isBlankOrEmpty(num)) {
			BigDecimal bg = new BigDecimal(num.toString());
			Double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		    return new BigDecimal(f1.toString());
		}
		return new BigDecimal(0);
	}
	
	/**
	 * @Title: IntegerDivideTwoDecimals 
	 * @author gzl
	 * @date 2021年3月30日下午10:56:00
	 * @Description: 整数相除求百分比:结果等于整数的时候不留小数位,其余情况都是保留两位
	 */
	public static BigDecimal integerDivideTwoDecimals(Integer divisor,Integer dividend) {
		if(!isBlankOrEmpty(divisor) && !isBlankOrEmpty(dividend)) {
			BigDecimal result = divisor==0||dividend==0?new BigDecimal(0):new BigDecimal(divisor*100)
						.divide(new BigDecimal(dividend), 2, BigDecimal.ROUND_HALF_UP);
			String resultString = result.toString();
			String substring = resultString.substring(resultString.indexOf(".")+1);
			if (substring.equals("00")) {
				String substring2 = resultString.substring(0, resultString.indexOf("."));
				return new BigDecimal(substring2);
			}
			return result;
		}
		return new BigDecimal(0);
	}
	
	/**
	 * @Title: flotDivideTwoDecimals 
	 * @author gzl
	 * @date 2021年3月31日上午12:12:52
	 * @Description: 浮点数相除求百分比:小数点始终保持两位
	 */
	public static BigDecimal flotDivideTwoDecimals(Double divisor,Double dividend) {
		if(!isBlankOrEmpty(divisor) && !isBlankOrEmpty(dividend)) {
			if (divisor==0 || dividend==0) {
				return new BigDecimal(0);
			}
			BigDecimal divisor1 = new BigDecimal(divisor.toString()).multiply(new BigDecimal(100));
			BigDecimal result = divisor1.divide(new BigDecimal(dividend.toString()), 2, BigDecimal.ROUND_HALF_UP);
			return result;
		}
		return new BigDecimal(0);
	}
	
	/**
	 * @Title: isBlankOrEmpty 
	 * @author gzl
	 * @date 2021年3月30日下午11:00:21
	 * @Description: 判断对象是否为空
	 */
    public static boolean isBlankOrEmpty(Object object) {
        if (null == object) {
            return true;
        }
        if (object.toString().equals("")) {
            return true;
        }
        return false;
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

BigDecimal类型加减乘除运算(Java必备知识) 的相关文章

  • 如何在日期选择器中设置不在当前月份的单元格的样式

    我目前正在为我的 JavaFX 应用程序制作注册表 问题是 当日期选择器中的单元格不在页面的月份上时 我想让该单元格变灰 让我们看看我当前的日期选择器 我的日期选择器 正如您所看到的 我希望下个月的日期 27 日 28 日 30 日以及 1
  • 如果测试用例失败,Selenium Web 驱动程序无法关闭 Firefox 实例

    我各位 我正在使用 junit 和 selenium web 驱动程序 2 28 问题是 如果我运行成功的测试用例 Web 驱动器能够关闭 Firefox 实例 但是当测试用例失败时 Selenium Web 驱动器无法关闭 Firefox
  • AES 加密 Java/plsql

    我需要在Java和plsql DBMS CRYPTO for Oracle 10g 上实现相同的加密 解密应用程序 两种实现都工作正常 但这里的问题是我对相同纯文本的加密得到了不同的输出 下面是用于加密 解密过程的代码 Java 和 PLS
  • 在Windows上安装Java 11 OpenJDK(系统路径问题)

    Java 11 最近发布了 众所周知 这个版本没有安装文件 当然 要在没有安装程序的情况下安装 Java 我将系统设置 PATH 和 JAVA HOME 设置为解压缩 Java 11 的文件夹的地址 根据对类似问题的已接受回复建议 唯一的事
  • 解决错误:日志已在具有多个实例的atomikos中使用

    我仅在使用atomikos的实时服务器上遇到问题 在我的本地服务器上它工作得很好 我在服务器上面临的问题是 init 中出错 日志已在使用中 完整的异常堆栈跟踪 java lang RuntimeException Log already
  • HDFS:使用 Java / Scala API 移动多个文件

    我需要使用 Java Scala 程序移动 HDFS 中对应于给定正则表达式的多个文件 例如 我必须移动所有名称为 xml从文件夹a到文件夹b 使用 shell 命令我可以使用以下命令 bin hdfs dfs mv a xml b 我可以
  • 如何为 Gson 编写自定义 JSON 反序列化器?

    我有一个 Java 类 用户 public class User int id String name Timestamp updateDate 我收到一个包含来自 Web 服务的用户对象的 JSON 列表 id 1 name Jonas
  • jdbc4.MySQLSyntaxErrorException:数据库中不存在表

    我正在使用 SpringBoot 开发一个网络应用程序 这是我的application properties文件来指定访问数据库的凭据 spring datasource driverClassName com mysql jdbc Dri
  • hibernate总是自己删除表中的所有数据

    您好 我正在开发一个 spring mvc 应用程序 它使用 hibernate 连接到存储文件的 mysql 数据库 我有两个方法 一个方法添加我选择的特定文件路径中的所有文件 另一种方法调用查询以返回从 mysql 存储的文件列表 问题
  • OnClick 事件中的 finish() 如何工作?

    我有一个Activity一键退出Activity 通过layout xml我必须设置OnClick事件至cmd exit调用 this finish 效果很好 public void cmd exit View editLayout thi
  • Prim 的迷宫生成算法:获取相邻单元格

    我基于 Prim 算法编写了一个迷宫生成器程序 该算法是 Prim 算法的随机版本 从充满墙壁的网格开始 选择一个单元格 将其标记为迷宫的一部分 将单元格的墙壁添加到墙壁列表中 While there are walls in the li
  • 迁移到 java 17 后有关“每个进程的内存映射”和 JVM 崩溃的 GC 警告

    我们正在将 java 8 应用程序迁移到 java 17 并将 GC 从G1GC to ZGC 我们的应用程序作为容器运行 这两个基础映像之间的唯一区别是 java 的版本 例如对于 java 17 版本 FROM ubuntu 20 04
  • Spring Data 与 Spring Data JPA 与 JdbcTemplate

    我有信心Spring Data and Spring Data JPA指的是相同的 但后来我在 youtube 上观看了一个关于他正在使用JdbcTemplate在那篇教程中 所以我在那里感到困惑 我想澄清一下两者之间有什么区别Spring
  • Java直接内存:在自定义类中使用sun.misc.Cleaner

    在 Java 中 NIO 直接缓冲区分配的内存通过以下方式释放 sun misc Cleaner实例 一些比对象终结更有效的特殊幻像引用 这种清洁器机制是否仅针对直接缓冲区子类硬编码在 JVM 中 或者是否也可以在自定义组件中使用清洁器 例
  • org.jdesktop.application 包不存在

    几天以来我一直在构建一个 Java 桌面应用程序 一切都很顺利 但是今天 当我打开Netbeans并编译文件时 出现以下编译错误 Compiling 9 source files to C Documents and Settings Ad
  • 将多模块 Maven 项目导入 Eclipse 时出现问题 (STS 2.5.2)

    我刚刚花了最后一个小时查看 Stackoverflow com 上的线程 尝试将 Maven 项目导入到 Spring ToolSuite 2 5 2 中 Maven 项目有多个模块 当我使用 STS 中的 Import 向导导入项目时 所
  • Tomcat 6找不到mysql驱动

    这里有一个类似的问题 但关于类路径 ClassNotFoundException com mysql jdbc Driver https stackoverflow com questions 1585811 classnotfoundex
  • 使用 SAX 进行 XML 解析 |如何处理特殊字符?

    我们有一个 JAVA 应用程序 可以从 SAP 系统中提取数据 解析数据并呈现给用户 使用 SAP JCo 连接器提取数据 最近我们抛出了一个异常 org xml sax SAXParseException 字符引用 是无效的 XML 字符
  • 将2-3-4树转换为红黑树

    我正在尝试将 2 3 4 树转换为 java 中的红黑树 但我无法弄清楚它 我将这两个基本类编写如下 以使问题简单明了 但不知道从这里到哪里去 public class TwoThreeFour
  • java迭代器内部是如何工作的? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一个员工列表 List

随机推荐

  • 网络QoS解决方案

    网络QoS解决方案 在网络带宽不足时 对网络流量做区别服务 优先传输那些重要的 要求网络延迟小的 如果丢弃会导致更大业务代价的数据 并对不同应用的数据做合理的带宽分配与控制 如果一定需要丢弃一些数据 则丢弃那些代价比较低的 这就是网络 Qo
  • pnpm install出现:ERR_PNPM_PEER_DEP_ISSUES Unmet peer dependencies

    使用 pnpm install 安装项目依赖时出现 ERR PNPM PEER DEP ISSUES Unmet peer dependencies 在 pnpm github issues 中找到相关解决方案 一 前言 完整日志 ERR
  • Git修改IP重新定位的方法

    进入已clone项目的 git文件夹 打开config文件 打开config 如图显示 修改url中的IP为192 168 6 102 然后保存 在项目上右击选择属性 R 然后选择Git 即可看到当前项目的跟踪远端网址 转载于 https
  • js vue上传文件判断文件格式 GIF JPG PNG

    根据文件识别头信息获取图片文件的类型 JPG 文件头标识 FF D8 文件尾标识 FF D9 PNG 文件头标识 8 bytes 89 50 4E 47 0D 0A 1A 0A GIF 文件头标识 6 bytes 47 49 46 38 3
  • 计算机二级试题及分值分布,计算机二级各部分分值分布

    计算机二级考试分选择题和操作题两大类 其中选择题10题 每题2分 一共20分 操作题分字处理题 电子表格题 演示文稿题三大类 其中字处理题30分 电子表格题30分 演示文稿题20分 共计80分 计算机二级各科目考试题型及分值 二级 MS O
  • java垃圾回收机制概述以及优缺点

    Java中的垃圾回收机制是自动内存管理的一部分 它负责在程序运行时自动回收不再使用的内存对象 以便为程序提供可用的内存空间 基于所谓的 垃圾收集器 它是Java虚拟机 JVM 的一部分 以下是Java垃圾回收机制的主要特点 1 对象生命周期
  • 教室管理系统(相关技术和设备:stm32、w5500、mqtt)

    背景 某学校对新建的实验楼有门禁管理需求 因此我们项目组借助KOB门锁 某宝销量较高的电吸锁和电插锁品牌 搭建了前端 微信小程序和网页 服务器 java服务器和mqtt服务器 单片机 基于stm32 用于控制电插锁 实现了一套完整的门禁管理
  • 关于RuoYi-Vue和ruoyi-vue-pro的基本使用理解

    文章目录 概要 前后端分离架构 技术栈 技术细节 小结 概要 提示 这里是本文概要 RuoYi Vue和ruoyi vue pro两个Web开源项目都是基于当下主流技术栈的前后端分离版本 后端采用SpringBoot多模块架构 前端使用Vu
  • 秋叶一键重装系统连接服务器失败,秋叶一键重装系统win7系统安装和使用DAEMONToolsLite的方法【图文教程】...

    DAEMON Tools Lite是一款虚拟光驱工具 装完不需启动即可用 是一个非常先进的模拟备份以及合并保护盘的软件 但是有部分win7秋叶系统用户还不知道要怎么安装和使用DAEMON Tools Lite 针对这个情况 小编这就给大家分
  • 保研日记v

    目录 个人情况 夏令营情况 预推免情况 希望能对学弟学妹们能有一定的参考价值 同样也是为了本科前三年画上一个句号 有问题可以直接留言哈 认识我的话可以直接小窗私戳我 即便困惑你的是很小的问题也希望大家能够勇敢的开口问 因为走了很多弯路 也在
  • 我优化了进度条,页面性能竟提高了70%

    前言 大家好 我是零一 最近我准备在组里进行代码串讲 所以我梳理了下项目之前的业务代码 在梳理的过程中 我看到了有个进度条组件写的非常好 这又想起我刚开始学前端时写的进度条的代码 跟这个比起来真的差距太大了 大部分的初学者应该都想不到 而且
  • 程序员常用的命令

    写在前面 你们好 我是小庄 很高兴能和你们一起学习常用命令 如果您对Java感兴趣的话可关注我的动态 写博文是一种习惯 在这过程中能够梳理和巩固知识 常用的Linux命令 cd 改变目录 cd 回退到上一级目录 直接cd进入默认目录 pwd
  • Vulkan_片元着色器特效5(泛光Bloom)

    本部分主要结合上一部分的Vulkan 片元着色器特效4 高动态范围HDR 来综合展示HDR 泛光场景 主要参照 LearnOpenGL中的Bloom章节 一 基本原理 Bloom使我们能够注意到一个明亮的物体真的有种明亮的感觉 泛光可以极大
  • ctfshow web入门——web2

    无法查看源代码 点击右键确实不行 直接ctrl u查看即可 但这个也可以用另一种方法查看网页源代码 即在网页url前面 view source
  • stream详解

    Java中的Stream流 公司中用了很多Stream流 经常用来筛选出PO类型的List中想要的数据 所以还是比较常用的 Stream是Java8的新成员 允许以声明式方式处理数据集合 代码简洁 函数式编程写出的代码简洁且意图明确 使用s
  • ML-逻辑回归-Softmax-交叉熵(小航)

    在分类问题中 交叉熵的本质就是 对数 似然函数的最大化 逻辑回归的损失函数的本质就是 对数 似然函数的最大化 最大似然估计讲解 https www jianshu com p 191c029ad369 参考统计学习方法笔记 P79 soft
  • Svelte3聊天室

    Python微信订餐小程序课程视频 https edu csdn net course detail 36074 Python实战量化交易理财系统 https edu csdn net course detail 35475 基于svelt
  • 服务器的日常运维巡检视频,日常运维检查记录表

    日常运维检查记录表 2页 本资源提供全文预览 点击全文预览即可全文预览 如果喜欢文档就下载吧 查找使用更方便哦 19 90 积分 日常运维检查记录表检查分类检查分类检查对像检查对像检查内容检查内容检查结果检查结果备注备注检查通道检测卡上各部
  • 关于KEIL MDK调试ARM程序不能仿真的问题

    在单片机程序调试过程中 由于程序量小 利用仿真器进行仿真调试方便直观 所以一般经常使用 但是keil经常会出现罢工 无法用仿真器调试的现象 如下图 解决方法也很简单 按照下图设置即可
  • BigDecimal类型加减乘除运算(Java必备知识)

    在现实开发当中经常会遇到这种计算 这里特此整理一下为方便以后学习 希望能帮助到其他的萌新 目录 1 为什么要用BigDecimal计算 2 浮点计算误差产生的原因 3 bigdecimal的初始化 4 bigdecimal的加减乘除 5 除