161117-1735546277e446

BigDecimal

在开发过程中,我们会遇到一些需要严格要求浮点数计算精度的场景。此时,使用float,double等类型是满足不了需求的。案例如下:

1
2
3
4
5
6
7
public static void main(String[] args) {
double a = 0.1;
double b = 0.2;

double c = a + b;
System.out.println(c);
}

这段代码会返回0.3吗?

image-20250119171319428

我们可以看到运算的结果并不精确。

此时我们就需要使用BigDecimal来解决这种问题。

构造器

image-20250119171640684

我们可以看到有些构造器,接收的是一个double类型的参数。这个地方需要特别注意,我们不应该使用这些构造器。使用这些构造器仍然会有可能造成精度问题。

JDK的描述:参数类型为double的构造方法的结果具有一定的不可预知性。有人可能会认为在Java中写入new BigDecimal(0.1),所创建的BigDecimal正好等于0.1,但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为double。这样,传入到构造方法的值不会正好等于0.1(虽然表面上等于该值)。

正确姿势

1
2
3
4
5
double a = 0.1;
double b = 0.2;

BigDecimal b1 = new BigDecimal(Double.toString(a));
BigDecimal b2 = BigDecimal.valueOf(b);

其中**new BigDecimal(Double.toString(a));BigDecimal b2 = BigDecimal.valueOf(b);**是相等的。

可以查看valueOf的源码

image-20250119172425466

常用api

加减乘除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
double a = 0.1;
double b = 0.2;

BigDecimal b1 = new BigDecimal(Double.toString(a));
BigDecimal b2 = BigDecimal.valueOf(b);

// 加法
BigDecimal add = b1.add(b2);
System.out.println(add);

// 减法
BigDecimal subtract = b1.subtract(b2);
System.out.println(subtract);

// 乘法
BigDecimal multiply = b1.multiply(b2);
System.out.println(multiply);

// 除法
BigDecimal divide = b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);
System.out.println(divide);

其中需要注意的是,除法需要指定运算精度,否则遇到除不尽的情况会保存

转换成double

1
double d = b2.doubleValue();