Java 常用类 07. Java BigDecimal类(浮点
2021-12-18 本文已影响0人
yjtuuige
问题:
//浮点数计算遇到的问题
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 类也可进行大数的操作。