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

目录

  • 1、为什么要用BigDecimal计算?
  • 2、浮点计算误差产生的原因
  • 3、bigdecimal的初始化
  • 4、bigdecimal的加减乘除
  • 5、除法divide()参数使用
  • 6、八种舍入模式解释如下
    • 6.1、ROUND_UP
    • 6.2、ROUND_DOWN
    • 6.3、ROUND_CEILING
    • 6.4、ROUND_FLOOR
    • 6.5、ROUND_HALF_UP
    • 6.6、ROUND_HALF_DOWN
    • 6.7、ROUND_HALF_EVEN
    • 6.8、ROUND_UNNECESSARY
  • 7、保留小数位
  • 8、比较大小
  • 9、公共方法

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;}

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

  1. 详解BigDecimal及其加减乘除运算

    目录 一.BigDecimal概述 二.构造函数详解 1.BigDecimal(int val) 2.BigDecimal(int val, MathContext mc) MathContext 3 ...

  2. java必备知识进阶

    目录 1.java的内存管理 a.主要包括:内存分配和内存回收 2.堆和栈的区别 3.字符串hash方法 4.字符串判等 5.Apache和tomcat的区别 6.nginx和tomcat的区别 7. ...

  3. 【java面对对象】分数类型加减乘除运算的实现

    /**作者:naru* 编写功能:分数类型的加减乘除实现* 本代码并不完美 之后可能会不断完善* 基本思路:利用最小公倍数和最大公约数实现分数的约分* 然后其他均为数学运算* */class Frac ...

  4. 阿里P8级Java必备知识之JVM面试合集

    JVM全教程 一,JVM 1.线程 2.JVM 内存区域 3.程序计数器(线程私有) 4.虚拟机栈(线程私有) 5.本地方法区(线程私有) 6.堆(Heap-线程共享)-运行时数据区 7.方法区/永久 ...

  5. Java异常处理(Java必备知识)

    在程序设计和运行的过程中,程序员也是尽可能规避错误,但使程序被迫停止的错误仍然不可避免.Java提供了异常处理机制来帮助程序员检查可能出现的错误,提高了程序的可读性和可维护性.Java中将异常封装到一 ...

  6. java 二维数组 的方法和属性_Java一维数组和二维数组详解(Java必备知识)

    数组是最为常见的一种数据结构,分为一级数组,二维数组以及多维数组.是把相同数据类型的元素,用一个标识符封装到一起的基本类型数据序列或对象序列. 目录 一维数组 创建一维数组 给一维数组赋值 获取数组的 ...

  7. 北大公开课老师整理出的Java必备知识(建议收藏)

    学Java,首先就是需要去了解Java是什么?可以做什么等情况!(文章转载自乐字节) Java是什么? Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承 ...

  8. Java循环语句详解(Java必备知识)

    循环语句就是在满足一定条件的情况下反复执行某一个操作.在Java中提供了4种常用的循环语句,分别是while语句.do-while语句.for语句和foreach语句,其中foreach语句是for语 ...

  9. Java中BigDecimal类型的加减乘除及大小比对

    Java中BigDecimal类型的加减乘除及大小比对 前言 BigDecimal解释 创建BigDecimal类型 加减乘除计算 结果分析 结论 除法的补充 两个BigDecimal的比对 前言 在 ...

  10. java中Bigdecimal加减乘除运算

    在java中的Bigdecimal类型的数据进行加减乘除运算的时候要调用以下方法: 加法:add 减法:subtract 乘法:multiply 除法:divide 例如: BigDecimal i ...

最新文章

  1. android web 打印,Android设备WebView打印Console Log
  2. 软件工程结对开发团队成员以及题目介绍
  3. 操作系统:SSH协议知识介绍
  4. tomcat如何修改java版本_Java程序员必备——Tomcat配置技巧Top10
  5. MSP432P401R TI Drivers 库函数学习笔记(八)ADC
  6. LeetCode 1684. 统计一致字符串的数目(哈希)
  7. no number java_java.lang.NumberFormatException问题!!!
  8. 做tab切换时,点击浏览器返回拿不到实时的tab参数,请求不到实时的数据
  9. Windows如何刷新DNS缓存
  10. 高数——两个重要极限
  11. u大师u盘装系统win7_使用U盘安装Win7/Win8/Win10系统完美教程
  12. 史上首例!阿里程序员写的代码,被国家博物馆收藏了!
  13. java mybatis的作用,【java框架】MyBatis-Plus(1)--MyBatis-Plus快速上手开发及核心功能体验-博客...
  14. linux的scp命令突然速度变慢,scp连接缓慢的解决方法
  15. 什么是外包公司你知道?
  16. (十一) ELK快速入门
  17. 流量控制组件, 技术选型:Sentinel vs Hystrix
  18. win7 修改服务器属性,win7打印机服务器属性设置
  19. 防止matplotlib画完图后自动关闭NN
  20. Java操作Access数据库使用方法及案例 及 所需jar包【源码及jar包在最后下载】

热门文章

  1. 今天开始写博客记录程序媛成长过程
  2. win7系统服务优化——服务列表禁止项
  3. Child returned status 1问题解决
  4. 易烊千玺代言雀巢咖啡;美国食品科技公司获3.5亿美元C轮融资;都乐“菠萝废物”开发皮革替代品...
  5. 水星如何设置虚拟机服务器,水星mercury路由器电脑怎么设置?
  6. Hotpot - 让使用CKettle像吃火锅一样爽
  7. “爆炸图“ArcGIS中制作一张好看的爆炸分析图(附练习数据)
  8. 武汉理工计算机研究生就业去向统计,武汉理工大学《2019届毕业生就业质量报告》发布,本科生月薪7333...
  9. java 金额数字转换大写算法
  10. CentOS 6.5 CentOS 7 rpm安装ftp服务端与ftp客户端