#|BigDecimal类中的double类型值的加减问题-java

了解到BigInteger类可以存入无限大小的值,从而可以用它进行大数值计算.
BigInteger中的构造方法中的一个参数是没有可以直接接受int,double,等基本数据类型,一个参数是接受String类型.
但是,BigDecimal类是可以接受double,int,long,String类型的值.问题就由此出现了.
问题:
import java.math.BigDecimal; public class BigDecimalDemo { public static void main(String[] args) { System.out.println(1.1+1.2101); BigDecimal bd1 = new BigDecimal(1.1); BigDecimal bd2 = new BigDecimal(1.2101); System.out.println(bd1.add(bd2)); } } /*输出: 2.3101000000000003 2.3101000000000000422772927777259610593318939208984375 */

BigDecimal(摘自Java SE8 API文档)
public BigDecimal(double val)Translates a double into a BigDecimal which is the exact decimal representation of the double’s binary floating-point value. The scale of the returned BigDecimal is the smallest value such that (10scale × val) is an integer.

Notes:
??1.The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
??2.The String constructor, on the other hand, is perfectly predictable: writing new BigDecimal(“0.1”) creates a BigDecimal which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one.
??3.When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.

Parameters:
val - double value to be converted to BigDecimal.

Throws:
NumberFormatException - if val is infinite or NaN.
?文档中说的很明白,对于Decimal中double构造器,该构造器的结果可能有些不可预料.这是因为0.1不能精确地表示为双精度(或者,就此而言,不能表示为任何有限长度的二进制分式)。因此,传递给构造函数的值并不完全等于0.1,尽管看起来是这样。
?推荐使用String构造器,它与所存的double类型的字符串所预料的是一样的.
?可以看看这篇文章:浮点数存储.
解决办法:
import java.math.BigDecimal; public class BigDecimalDemo { public static void main(String[] args) { bd1 = new BigDecimal("1.1"); bd2 = new BigDecimal("1.2101"); System.out.println(bd1.add(bd2)); System.out.println(BigDecimal.valueOf(1.1).add(BigDecimal.valueOf(1.2101))); } } /*输出: 2.3101 2.3101 */

  1. 使用BigDecimal(String val)构造器


  2. 先将double类型的值使用public static BigDecimal valueOf(double val)方法.
    原理:将double类型的值先转换为String类型的值,在存储到BigDecimal对象中.
BigDecimal.valueOf(double val)源码:
public static BigDecimal valueOf(double val) { // Reminder: a zero double returns '0.0', so we cannot fastpath // to use the constant ZERO.This might be important enough to // justify a factory approach, a cache, or a few private // constants, later. return new BigDecimal(Double.toString(val)); }

API中0.1 (an unscaled value of 1, with a scale of 1)的理解
【#|BigDecimal类中的double类型值的加减问题-java】API文档中有一句(an unscaled value of 1, with a scale of 1)该如何理解呢?
BigDecimal类中有unscaledValue()scale()方法.通过这两个方法来理解这句话吧.
unscaledValue
public BigInteger unscaledValue()
Returns a BigInteger whose value is the unscaled value of this BigDecimal. (Computes (this * 10this.scale()).)

Returns:
the unscaled value of this BigDecimal.

Since:
1.2
scale
public int scale()
Returns the scale of this BigDecimal. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. For example, a scale of -3 means the unscaled value is multiplied by 1000.

Returns:
the scale of this BigDecimal.
方法应用
import java.math.BigDecimal; import java.math.BigInteger; import java.util.Arrays; public class FoctorialDemo { public static void main(String[] args) { BigDecimal bd = new BigDecimal("-1.2101"); System.out.println(bd.scale()); System.out.println(bd.unscaledValue()); } } /*输出: 4 -12101 */

通过输出可以了解到scale()方法是返回该BigDecimal的值的小数位数.scale这个单词有数值范围的意思.
?????????unscaledValue()方法是将BigInteger的值去除小数点.也就相当于
t h i s ? 1 0 t h i s . s c a l e ( ) this*10^{this.scale()} this?10this.scale()
0.1 (an unscaled value of 1, with a scale of 1)这句话也就好理解了.去掉小数点即为1; 小数点的数值范围为1.

    推荐阅读