bigdecimal类_BigDecimal类的常见陷阱以及如何避免它们

bigdecimal类When doing business calculations in Java, especially when it comes to currencies, you would preferably use the java.math.BigDecimal class to avoid the problems related to floating-point ari...
摘要由CSDN通过智能技术生成

bigdecimal类

When doing business calculations in Java, especially when it comes to currencies, you would preferably use the java.math.BigDecimal class to avoid the problems related to floating-point arithmetic, which you might experience if using one of the two primitive types float or double (or one of their boxed type counterparts).Indeed, the BigDecimal class contains a number of methods that can meet most of the requirements of common business calculations.However, I would like to draw your attention to the most common pitfalls in the use of the BigDecimal class and show you how to avoid them, by using the regular BigDecimal API on the one hand and a new, customized class that extends BigDecimal on the other.So, let’s start with the regular BigDecimal API.

在Java中进行业务计算时,特别是在涉及货币时,最好使用java.math.BigDecimal类来避免与浮点算术有关的问题,如果使用两种基本类型float或浮点型之一可能会遇到这些问题。 double(或与之对应的盒装类型之一)。实际上, BigDecimal类包含许多方法,这些方法可以满足大多数常规业务计算的要求。但是,我想提醒您注意使用中最常见的陷阱BigDecimal类,并告诉您如何避免它们,使用,一方面和延伸的BigDecimal在other.So一个新的,定制类的常规BigDecimal的 API,让我们与常规的BigDecimal API开始。

陷阱1:双重构造函数 (Pitfall #1: The double constructor)

Consider the following example:

考虑以下示例:

BigDecimal x = new BigDecimal(0.1);
System.out.println("x=" + x);Console output: x=0.1000000000000000055511151231257827021181583404541015625

As you can see, the result of this constructor can be somewhat unpredictable. This is because floating-point numbers are represented in computer hardware as base 2 (binary) fractions. However, most decimal fractions cannot be represented exactly as binary fractions. Therefore, the binary floating-point numbers actually stored in the machine only approximate the decimal floating-point numbers you enter. Hence, the value passed to the double constructor is not exactly equal to 0.1.

如您所见,此构造函数的结果可能有些不可预测。 这是因为浮点数在计算机硬件中表示为基数2(二进制)的分数。 但是,大多数十进制分数不能完全表示为二进制分数。 因此,实际存储在机器中的二进制浮点数仅近似于您输入的十进制浮点数。 因此,传递给double构造函数的值不完全等于0.1。

In contrast, the String constructor is perfectly predictable and produces a BigDecimal which is exactly equal to 0.1 as expected.

相反, String构造函数是完全可预测的,并且会产生一个BigDecimal ,该BigDecimal与预期的完全相等,等于0.1。

BigDecimal y = new BigDecimal("0.1");
System.out.println("y=" + y);Console output:
y=0.1

Thus, it is recommended to use the String constructor in preference to the double constructor.If, for any reason, a double must be used to create a BigDecimal, consider using the static BigDecimal.valueOf(double) method.This will give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor.

因此,建议使用String构造函数优先于double构造函数。如果出于任何原因必须使用double来创建BigDecimal ,请考虑使用静态BigDecimal.valueOf(double)方法。导致如使用Double.toString(double)方法转换到双String,然后使用BigDecimal(String)构造。

陷阱2:静态valueOf(double)方法 (Pitfall #2: The static valueOf(double) method)

If using the static BigDecimal.valueOf(double) method to create a BigDecimal, be aware of its limited precision:

如果使用静态BigDecimal.valueOf(double)方法创建BigDecimal ,请注意其有限的精度:

BigDecimal x = BigDecimal.valueOf(1.01234567890123456789); BigDecimal y = new BigDecimal("1.01234567890123456789"); System.out.println("x=" + x);
System.out.println("y=" + y);Console output:
x=1.0123456789012346
y=1.01234567890123456789

Here, the x value has lost 4 decimal digits because a double has only a precision of 15–17 digits (a float only of 6–9 digits), while a BigDecimal is of arbitrary precision (limited only by memory).Therefore, it is actually a good idea to use the String constructor, since two major problems caused by the double constructor are effectively avoided.

在这里,x值丢失了4个十进制数字,因为双精度仅具有15-17个数字的精度(浮点数仅6-9个数字),而BigDecimal具有任意精度(仅受内存限制)。使用String构造函数实际上是一个好主意,因为可以有效避免由double构造函数引起的两个主要问题。

陷阱3:equals(bigDecimal)方法 (Pitfall #3: The equals(bigDecimal) method)

Let’s take a look at this example:

让我们看一下这个例子:

BigDecimal x = new BigDecimal("1");
BigDecimal y = new BigDecimal("1.0"); System.out.println(x.equals(y));Console output:
false

This is because a BigDecimal consists of an unscaled integer value with arbitrary precision and a 32-bit integer scale, both of which must be equal to the corresponding values of the BigDecimal to be compared:

这是因为BigDecimal由具有任意精度和32位整数小数位数的未缩放整数值组成,这两者必须等于要比较的BigDecimal的对应值:

  • x has an unscaled value of 1 and a scale of 0

    x的无标度值为1,小数位数为0
  • y has an unscaled value of 10 and a scale of 1

    y的无标度值为10,小数位数为1

Hence, x is not equal to y.For this reason, BigDecimals shouldn’t be compared with the equals() method, but with the compareTo() method, which instead compares the numerical values (x=1; y=1.0) represented by the two BigDecimals.

因此,x不等于y。因此,不应将BigDecimalsequals()方法进行比较,而应与compareTo()方法进行比较,该方法将比较表示的数值(x = 1; y = 1.0)由两个BigDecimals组成

System.out.println(x.compareTo(y) == 0);Console output:
true

陷阱4:round(mathContext)方法 (Pitfall #4: The round(mathContext) method)

If you’re unfamiliar with the BigDecimal class, you might be tempted to use the round(new MathContext(precision, roundingMode)) method, because you want to round your BigDecimal to let’s say two decimal places.

如果您不熟悉BigDecimal类,则可能会想使用round(new MathContext(precision,roundingMode))方法,因为您想将BigDecimal 舍入为两个小数位。

BigDecimal x = new BigDecimal("12345.6789");
x = x.round(new MathContext(2, Rou
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值