概述
BigDecimal
BigDecimal是什么
摘抄自- - - 百度百科
Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用BigDecimal类来操作。
BigDecimal所创建的是对象,故我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。
BigDecimal 源码中继承实现
package java.math;
public class BigDecimal extends Number implements Comparable<BigDecimal> {
//......
}
为什么要用BigDecimal
浮点型明明已经有了double和float,为啥还要BigDecimal嘞,这个问题可能我们听的最多的就是Double会丢失精度,主要原因是它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。BigDecimal就不会,我们也知道一般数据库存钱的话就用BigDecimal,而不是其他。因为商业计算往往要求结果精确所以BigDecimal更加适合商业使用
BigDecimal常用构造
分为大类型的有以下几类
-
BigDecimal(int)
- 创建一个具有参数所指定整数值的对象
-
BigDecimal(double)
- 创建一个具有参数所指定双精度值的对象
-
BigDecimal(long)
- 创建一个具有参数所指定长整数值的对象
-
BigDecimal(String)
- 创建一个具有参数所指定以字符串表示的数值的对象
每个构造函数中都有不同的参数,可以看下图
构建简单的实例
BigDecimal a = new BigDecimal("1.3");
System.out.println("a = "+a);
BigDecimal b =new BigDecimal(1.3);
System.out.println("b = "+b);
//结果:
//a = 1.3
//b = 1.3000000000000000444089209850062616169452667236328125
BigDecimal常用方法
BigDecimal 对于常用的加,减,乘,除,BigDecimal类提供了相应的成员方法。
public BigDecimal add(BigDecimal value); //加法
public BigDecimal subtract(BigDecimal value); //减法
public BigDecimal multiply(BigDecimal value); //乘法
public BigDecimal divide(BigDecimal value); //除法
使用案例
BigDecimal bigDecimal1 = new BigDecimal(9);
BigDecimal bigDecimal2 = new BigDecimal(3);
System.out.println("add = "+ bigDecimal1.add(bigDecimal2));//add = 12
System.out.println("subtract = "+ bigDecimal1.subtract(bigDecimal2));//subtract = 6
System.out.println("multiply = "+ bigDecimal1.multiply(bigDecimal2));//multiply = 27
System.out.println("divide = "+ bigDecimal1.divide(bigDecimal2));//divide = 3
BigDecimal的两值比较
一般情況下比较两个值,可能会想起来equals,但是相对于BigDecimal而言,compareTo更加合适
compareTo和equals的区别。
BigDecimal decimal1 = new BigDecimal("1");
BigDecimal decimal2 = new BigDecimal("1.00");
System.out.println(decimal1.equals(decimal2));//false
System.out.println(decimal1.compareTo(decimal2));//0
BigDecimal的equals方法当精度不一样的时候也当做不相等,而compareTo方法却可以忽略精度的不同,只比较数值是否相同
小结:
- equals : equals 方法比较value和scale(数值和精度),精度不一样,也返回false。
- compareTo:数值相同但是精度不同的两个数(例如2.0和2.00)被认为是相等的两个数,返回0另外对于a.compareTo(b)方法
- a<b, 返回-1
- a=b,返回0
- a>b, 返回1
compareTo
public int compareTo(BigDecimal val) {
// Quick path for equal scale and non-inflated case.
if (scale == val.scale) {
long xs = intCompact;
long ys = val.intCompact;
if (xs != INFLATED && ys != INFLATED)
return xs != ys ? ((xs > ys) ? 1 : -1) : 0;
}
int xsign = this.signum();
int ysign = val.signum();
if (xsign != ysign)
return (xsign > ysign) ? 1 : -1;
if (xsign == 0)
return 0;
int cmp = compareMagnitude(val);
return (xsign > 0) ? cmp : -cmp;
}
compareTo方法的作用是BigDecimal大小的比较。从上面源码中看出,两个值比较,最终返回的是一个int类型数字,而不是true和false。
一般两个值比较的时候无非就是三大种情况,大于、小于、等于,与之对应的是 1 、-1、 0。
-
大于 = 1
-
小于 = -1
-
等于 = 0
当然还有两种小情况
- 大于等于 = >-1
- 小于等于 =<1
举个例子:==
public static void main(String[] args) { BigDecimal a = new BigDecimal (101); BigDecimal b = new BigDecimal (103); if(a.compareTo(b) == -1){ System.out.println("a小于b"); } if(a.compareTo(b) == 0){ System.out.println("a等于b"); } if(a.compareTo(b) == 1){ System.out.println("a大于b"); } if(a.compareTo(b) > -1){ System.out.println("a大于等于b"); } if(a.compareTo(b) < 1){ System.out.println("a小于等于b"); } }
注意:使用compareTo方法比较,a、b均不能为null,否则会报空指针
BigDecimal 常见的问题
divide方法进行除法时当不整除抛出异常
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result
原因分析:
通过BigDecimal的divide方法进行除法时当不整除,出现无限循环小数时,就会抛异常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
解决方法:
divide方法设置精确的小数点,如:divide(xxxxx,2)
BigDecimal一定不会丢失精度吗?
在使用 BigDecimal 时,使用它的 BigDecimal(String) 构造器创建对象才有意义。其他的如 BigDecimal b = new BigDecimal(3) 这种,还是会发生精度丢失的问题
BigDecimal a = new BigDecimal(1.01);
BigDecimal b = new BigDecimal(1.02);
BigDecimal c = new BigDecimal("1.01");
BigDecimal d = new BigDecimal("1.02");
System.out.println(a.add(b));
System.out.println(c.add(d));
//输出结果
2.0300000000000000266453525910037569701671600341796875
2.03
通过上面的案例可以看出,在使用BigDecimal(double)中构造器的时候同样会丢失精度,但是使用 Bigdecimal 的 BigDecimal(String) 构造器的变量在进行运算的时候却没有出现这种问题。
上面的问题我们从源码的注释中官方也给出了说明,如下是 BigDecimal 类的 double 类型参数的构造器上的一部分注释说明:
/**
* Translates a {@code double} into a {@code BigDecimal} which
* is the exact decimal representation of the {@code double}'s
* binary floating-point value. The scale of the returned
* {@code BigDecimal} is the smallest value such that
* <tt>(10<sup>scale</sup> × val)</tt> is an integer.
* <p>
* <b>Notes:</b>
* <ol>
* <li>
* The results of this constructor can be somewhat unpredictable.
* One might assume that writing {@code new BigDecimal(0.1)} in
* Java creates a {@code 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
* {@code double} (or, for that matter, as a binary fraction of
* any finite length). Thus, the value that is being passed
* <i>in</i> to the constructor is not exactly equal to 0.1,
* appearances notwithstanding.
*
* <li>
* The {@code String} constructor, on the other hand, is
* perfectly predictable: writing {@code new BigDecimal("0.1")}
* creates a {@code BigDecimal} which is <i>exactly</i> equal to
* 0.1, as one would expect. Therefore, it is generally
* recommended that the {@linkplain #BigDecimal(String)
* <tt>String</tt> constructor} be used in preference to this one.
*
* <li>
* When a {@code double} must be used as a source for a
* {@code BigDecimal}, note that this constructor provides an
* exact conversion; it does not give the same result as
* converting the {@code double} to a {@code String} using the
* {@link Double#toString(double)} method and then using the
* {@link #BigDecimal(String)} constructor. To get that result,
* use the {@code static} {@link #valueOf(double)} method.
* </ol>
*
* @param val {@code double} value to be converted to
* {@code BigDecimal}.
* @throws NumberFormatException if {@code val} is infinite or NaN.
*/
public BigDecimal(double val) {
this(val,MathContext.UNLIMITED);
}
第一段也说的很清楚它只能计算的无限接近这个数,但是无法精确到这个数。
第二段则说,如果要想准确计算这个值,那么需要把 double 类型的参数转化为 String 类型的。并且使用 BigDecimal(String) 这个构造方法进行构造。去获取结果。
BigDecimal 总结
在需要精确的小数计算时再使用BigDecimal,BigDecimal的性能比double和float差,在处理庞大,复杂的运算时尤为明显。故一般精度的计算没必要使用BigDecimal。
尽量使用参数类型为String的构造函数。
BigDecimal都是不可变的(immutable)的, 在进行每一次四则运算时,都会产生一个新的对象 ,所以在做加减乘除运算时要记得要保存操作后的值。
最后
以上就是拉长篮球为你收集整理的探究Java中BigDecimalBigDecimal的全部内容,希望文章能够帮你解决探究Java中BigDecimalBigDecimal所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复