Java 常用类 07. Java BigDecimal类(浮点数精确计算)

问题:

//浮点数计算遇到的问题
package com.base.demo04;

public class Test10 {
    public static void main(String[] args) {
        double d1 = 1.0;
        double d2 = 0.9;
        System.out.println("d1:" + d1);
        System.out.println("d2:" + d2);
        System.out.println("d1-d2:" + (d1 - d2));
        double result = (1.4 - 0.5) / 0.9;
        System.out.println(result);
    }
}
  • 结果:

分析:

  • 计算机在存储浮点数字时,以二进制方法存储,在进行转化为二进制时,存储的小数部分,出现部分数据丢失,而成为近似值,从而导致在计算时出现错误。

解决:引入 BigDecimal 类

  • 位置:java.math 包中
  • 作用:精确计算浮点数
  • 创建方式:BigDecimal bd = new BigDecimal("1.0");

BigDecimal

  • 不可变的、任意精度的有符号十进制数。
  • BigDecimal 由任意精度的整数非标度值 (unscaledValue) 和 32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂。因此,BigDecimal 表示的数值是 unscaledValue × 10−scale

常用方法

  • 构造方法
    BigDecimal 类的构造方法挺多的,但这里只介绍一种 public BigDecimal(String val);,将字符串表示形式转换为 BigDecimal。注意这里一定是字符串 String,如果在参数为小数,使用 double 类型时,会出现问题。(注意看实例)
  • 普通方法
    BigDecimal 创建的是 对象,所以在运算的时候,不能再使用 +、-、*、/ 等算术运算符进行直接运算,而要使用相应的方法。
方法 描述
public BigDecimal add(BigDecimal augend) 加法
public BigDecimal subtract(BigDecimal subtrahend) 减法
public BigDecimal multiply(BigDecimal multiplicand) 乘法
public BigDecimal divide(BigDecimal divisor,int scale, int roundingMode) 除法。divisor:除数。scale:精确度。roundingMode:结果的舍入模式。

注意:在进行除法运算时,结果为除不尽的数,且未标明保留几位小数(或使用舍入的方式),会抛出的异常

  • 常用的舍入方法:Java 8 以后改为 RoundingMode.HALF_UP
常量 描述
ROUND_HALF_UP 四舍五入
ROUND_UP 直接进位
ROUND_DOWN 直接舍弃
ROUND_HALF_DOWN 舍弃部分 > 0.5 进位,否则舍弃
  • 实例:
package com.base.demo04;

import java.math.BigDecimal;

public class Test10 {
    public static void main(String[] args) {
        double d1 = 1.0;
        double d2 = 0.9;
        System.out.println("================= double ==================");
        System.out.println("d1:" + d1);
        System.out.println("d2:" + d2);
        System.out.println("d1-d2:" + (d1 - d2));
        double result = (1.4 - 0.5) / 0.9;
        System.out.println("double 类型计算 ");
        System.out.println("(1.4 - 0.5) / 0.9 --> " + result);
        System.out.println("=================BigDecimal==================");
        BigDecimal bd1 = new BigDecimal("1.0");
        BigDecimal bd2 = new BigDecimal("0.9");
        // 1.subtract(); 减法
        BigDecimal r1 = bd1.subtract(bd2);
        System.out.println(bd1 + " - " + bd2 + " = " + r1);
        // 2.add(); 加法
        BigDecimal r2 = bd1.add(bd2);
        System.out.println(bd1 + " + " + bd2 + " = " + r2);
        // 3.multiply(); 乘法
        BigDecimal r3 = bd1.multiply(bd2);
        System.out.println(bd1 + " x " + bd2 + " = " + r3);
        // 4.divide(); 除法
        BigDecimal r4 = new BigDecimal("1.4")
                .subtract(new BigDecimal("0.5"))
                .divide(bd2);
        System.out.println("(1.4 - 0.5)/ " + bd2 + " = " + r4);
        BigDecimal r5 = new BigDecimal("20")
                // Java 8 以后改为 RoundingMode.HALF_UP
                .divide(new BigDecimal("3"), 2, BigDecimal.ROUND_HALF_UP);
        System.out.println("20 / 3 " + " = " + r5 + " 四舍五入");
        // double 值为参数传入 BigDecimal
        System.out.println("========= double 值为参数传入 BigDecimal =========");
        BigDecimal r6 = new BigDecimal(d1);
        BigDecimal r7 = new BigDecimal(d2);
        System.out.println(r6);
        System.out.println(r7);
        System.out.println(r6.add(r7));
    }
}
  • 结果

分析:

  • 参数类型为 double 的构造方法的结果,有一定的不可预知性。你可能认为在 Java 中写入 newBigDecimal(0.1), 所创建的 BigDecimal 正好等于0.1(非标度值 1,其标度为 1),但是它实际上是近似值。这是因为 0.1 无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值,不会正好等于 0.1(虽然表面上等于该值)。

补充其他方法:BigDecimal.setScale(); 用于格式化小数点

// Java 8 以后改为 RoundingMode.HALF_UP
setScale(1); 表示保留一位小数,默认用四舍五入方式 
setScale(1,BigDecimal.ROUND_DOWN) 直接删除多余的小数位,如 2.35 会变成 2.3 
setScale(1,BigDecimal.ROUND_UP) 进位处理,2.35 变成 2.4 
setScale(1,BigDecimal.ROUND_HALF_UP) 四舍五入,2.35 变成 2.4
setScaler(1,BigDecimal.ROUND_HALF_DOWN) 舍弃部分,> 0.5 进位,否则舍弃。2.35 变成 2.3

总结

  • 对于不需要准确计算精度的数字,可以直接使用 float 或 double,但是如果需要精确计算结果,则必须使用 BigDecimal 类,而且使用 BigDecimal 类也可进行大数的操作。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容