我是靠谱客的博主 拉长篮球,最近开发中收集的这篇文章主要介绍探究Java中BigDecimalBigDecimal,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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> &times; 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所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部