IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java 浮点数运算【BigDecimal】 -> 正文阅读

[Java知识库]Java 浮点数运算【BigDecimal】

背景

最近需求需要极端销售额,同环比等一系列数据,而且有的数比较大甚至到亿元。涉及计算的数据的要小心了。
在这里插入图片描述

Float/Double在工程运算中使用的比较多,在商业计算中使用Decimal类型的比较多。(注:
在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal,另外,我们如果需要精确计算,要用String来够造BigDecimal。在《Effective Java》一书中的例子是用String来够造BigDecimal的。(注意:divide方法中推荐使用枚举RoundingMode.HALF_UP)
————————————————
版权声明:本文为CSDN博主「michaelgo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/michaelgo/article/details/81627069

BigDecimal使用

简介

Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。

Bigdecimal初始化

  • BigDecimal(int) 创建一个具有参数所指定整数值的对象。
  • BigDecimal(double) 创建一个具有参数所指定双精度值的对象。
  • BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
  • BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。【推荐使用】

测试案例

/**
     * 构造函数精确度比较
     * @author guochao.bj@fang.com
     * @date 2021/9/9
     */
    @Test
    public void precision(){
        BigDecimal bigDecimal = new BigDecimal("0.1");
        BigDecimal bigDecimal1 = new BigDecimal(0.1);
        System.out.println("字符串构造->"+bigDecimal);
        System.out.println("double构造->"+bigDecimal1);
        BigDecimal bigDecimal2 = new BigDecimal(new Double(0.1).toString());
        System.out.println("double转字符串构造->"+bigDecimal2);
    }

在这里插入图片描述

原因

不懂我们就看源码
在这里插入图片描述
个人理解:我们的数字在代码中其实是二进制数据,不能真正的标识具体的数,(在我们做一些基础数据类型计算转换时,会出现精度丢失情况就可以看出来),所以在使用double 0.1表示0.1时,其实他并不是0.1,只是计算让我们觉得是0.1。以至使用 BigDecimal(double)会出现错误,不可预知的。作者也写道String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。

BigDecimal运算

/**
     * 加减乘除
     * @author guochao.bj@fang.com
     * @date 2021/9/9
     */
    @Test
    public void operation(){
        BigDecimal num1 = new BigDecimal(0.005);
        BigDecimal num2 = new BigDecimal(1000000);
        BigDecimal num3 = new BigDecimal(-1000000);
        //尽量用字符串的形式初始化
        BigDecimal num12 = new BigDecimal("0.005");
        BigDecimal num22 = new BigDecimal("1000000");
        BigDecimal num32 = new BigDecimal("-1000000");
        //加法
        BigDecimal result1 = num1.add(num2);
        BigDecimal result12 = num12.add(num22);
        System.out.println("double"+result1);
        System.out.println("字符串"+result12);
        System.out.println("加法-------------------------------");

        //减法
        BigDecimal result2 = num1.subtract(num2);
        BigDecimal result22 = num12.subtract(num22);
        System.out.println("double"+result2);
        System.out.println("字符串"+result22);
        System.out.println("减法-------------------------------");
        //乘法
        BigDecimal result3 = num1.multiply(num2);
        BigDecimal result32 = num12.multiply(num22);
        System.out.println("double"+result3);
        System.out.println("字符串"+result32);
        System.out.println("乘法-------------------------------");
        //绝对值
        BigDecimal result4 = num3.abs();
        BigDecimal result42 = num32.abs();
        System.out.println("double"+result4);
        System.out.println("字符串"+result42);
        System.out.println("绝对值-------------------------------");
        //除法
        BigDecimal result5 = num2.divide(num1,20,BigDecimal.ROUND_HALF_UP);
        BigDecimal result52 = num22.divide(num12,20,BigDecimal.ROUND_HALF_UP);
        System.out.println("double"+result5);
        System.out.println("字符串"+result52);
        System.out.println("除法-------------------------------");
    }

在这里插入图片描述

数据处理

/**
     * 四舍五入数据处理
     * @author guochao.bj@fang.com
     * @date 2021/9/9
     */
    @Test
    public void HALFUPOperation(){
        BigDecimal num12 = new BigDecimal("10.2548");
        System.out.println(num12.setScale(1,BigDecimal.ROUND_HALF_UP));
        System.out.println(num12.setScale(2,BigDecimal.ROUND_HALF_UP));
        System.out.println(num12.setScale(3,BigDecimal.ROUND_HALF_UP));
        System.out.println(num12.setScale(4,BigDecimal.ROUND_HALF_UP));
        System.out.println(num12.setScale(5,BigDecimal.ROUND_HALF_UP));
    }

在这里插入图片描述

注意

进行除法运算的时候,结果不能整除,有余数,这个时候会报java.lang.ArithmeticException:

这边我们要避免这个错误产生,在进行除法运算的时候,针对可能出现的小数产生的计算,必须要多传两个参数
divide(BigDecimal,保留小数点后几位小数,舍入模式)

    @Test
    public void divideOperation(){
        BigDecimal num12 = new BigDecimal("10");
        BigDecimal num22 = new BigDecimal("3");
        //ROUND_CEILING  向正无穷方向舍入
        System.out.println("ROUND_CEILING--------"+num12.divide(num22,2,BigDecimal.ROUND_CEILING));
        //ROUND_DOWN    向零方向舍入
        System.out.println("ROUND_DOMN-------- "+num12.divide(num22,2,BigDecimal.ROUND_DOWN));
        //ROUND_FLOOR    向负无穷方向舍入
        System.out.println("ROUND_FLOOR------"+num12.divide(num22,2,BigDecimal.ROUND_FLOOR));
        //ROUND_HALF_DOWN    向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入, 例如1.55 保留一位小数结果为1.5
        System.out.println("ROUND_HALF_DOMN------"+num12.divide(num22,2,BigDecimal.ROUND_HALF_DOWN));
        //ROUND_FLOOR    向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,如果保留位数是奇数,使用ROUND_HALF_UP,如果是偶数,使用ROUND_HALF_DOWN
        System.out.println("ROUND_HALF_EVEN-------"+num12.divide(num22,2,BigDecimal.ROUND_HALF_EVEN));
        //ROUND_FLOOR    向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6, todo 也就是我们常说的“四舍五入”
        System.out.println("ROUND_HALF_UP--------"+num12.divide(num22,2,BigDecimal.ROUND_HALF_UP));
        //ROUND_FLOOR    向远离0的方向舍入
        System.out.println("ROUND_Up-------"+num12.divide(num22,2,BigDecimal.ROUND_UP));

        BigDecimal num32 = new BigDecimal("10");
        BigDecimal num33 = new BigDecimal("2");
        //ROUND_UNNECESSARY 计算结果是精确的,不需要舍入模式
        System.out.println("ROUND_UNNECESSARY-------"+num32.divide(num33,2,BigDecimal.ROUND_UNNECESSARY));

    }

在这里插入图片描述

除法就要考虑到除数为0的情况,java.lang.ArithmeticException: / by zero

    @Test
    public void ZEROOperation(){
        BigDecimal num12 = new BigDecimal("10");
        BigDecimal num22 = new BigDecimal("0");
        if(num22.equals(BigDecimal.ZERO)){
            System.out.println("除数不能为0");
        }else {
            //ROUND_FLOOR    向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6, todo 也就是我们常说的“四舍五入”
            System.out.println("ROUND_HALF_UP--------"+num12.divide(num22,2,BigDecimal.ROUND_HALF_UP));
        }
    }

使用equals(BigDecimal.ZERO) 来判断是否为0

工具类

public class Arith {
    /**
     * 提供精确加法计算的add方法
     * @param value1 被加数
     * @param value2 加数
     * @return 两个参数的和
     */
    public static double add(double value1,double value2){
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确减法运算的sub方法
     * @param value1 被减数
     * @param value2 减数
     * @return 两个参数的差
     */
    public static double sub(double value1,double value2){
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确乘法运算的mul方法
     * @param value1 被乘数
     * @param value2 乘数
     * @return 两个参数的积
     */
    public static double mul(double value1,double value2){
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供精确的除法运算方法div
     * @param value1 被除数
     * @param value2 除数
     * @param scale 精确范围
     * @return 两个参数的商
     * @throws IllegalAccessException
     */
    public static double div(double value1,double value2,int scale) throws IllegalAccessException{
        //如果精确范围小于0,抛出异常信息
        if(scale<0){
            throw new IllegalAccessException("精确度不能小于0");
        }
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.divide(b2, scale).doubleValue();
    }
}

参考博客

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-10 10:43:56  更:2021-09-10 10:45:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:10:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码