JavaRush /Java 博客 /Random-ZH /Java 中的 BigDecimal

Java 中的 BigDecimal

已在 Random-ZH 群组中发布
你好!在今天的讲座中,我们将讨论大数。不,关于真正大的。 之前,我们不止一次看到过原始数据类型的值范围表。它看起来像这样:
原始型 内存大小 数值范围
字节 8位 -128 至 127
短的 16位 至 -32768 至 32767
字符 16位 从 0 到 65536
整数 32位 从-2147483648 到 2147483647
长的 64位 从-9223372036854775808到9223372036854775807
漂浮 32位 从 (2 的 -149 次方) 到 ((2-2 的 -23 次方)*2 的 127 次方)
双倍的 64位 从 (-2 的 63 次方) 到 ((2 的 63 次方) - 1)
布尔值 8(用于数组时)、32(用于非数组时) 对或错
如果我们谈论整数,最大容量的数据类型是long,而当我们谈论浮点数时,最大容量的数据类型是 double。但是,如果我们需要的数字太大,甚至无法放入long中怎么办?可能的 Long 值的范围相当大,但仍然限制在一定的大小 - 64 位。如果我们的超大数有 100 位,我们能得出什么结果?幸运的是,您不需要发明任何东西。在 Java 中,为这种情况创建了两个特殊的类 - BigInteger(用于整数)和BigDecimal(用于浮点数)。他们的特点是什么?首先,理论上它们没有最大尺寸。理论上,因为不存在具有无限内存的计算机。而如果你在程序中创建的数字大于计算机内存的大小,当然程序将无法运行。但这种情况不太可能发生。因此,我们可以说数字的大小实际上BigIntegerBigDecimal无限的。这些类是用来做什么的?首先,对于精度要求极高的计算。例如,在某些程序中,人的生命可能取决于计算的准确性(飞机和火箭或医疗设备的软件)。因此,如果连小数点后150位也发挥重要作用,BigDecimal那么它就是最好的选择。此外,这些对象经常用于金融领域,其中最小数值的计算精度也极其重要。 如何使用对象BigInteger以及BigDecimal需要记住的重要事项是什么? 这些类的对象是这样创建的:
public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
将字符串作为参数传递只是可能的构造函数之一。Here we use strings because our numbers exceed the maximum values long​​and double, and somehow we need to explain to the compiler exactly what number we want to get :) Just pass the number 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 to the constructor 1111111111111111111111111111111111111111111111111111111111111111111 will not work: Java will try to将传递的数字“适合”一种原始数据类型,但它不适合其中任何一种。因此,使用字符串来传递所需的数字是一个不错的选择。这两个类都可以自动从传递的字符串中提取数值。使用大量类时要记住的另一个要点是它们的对象是不可变的 ( Immutable)String通过类和基元(Integer、Long 等)的包装类 的示例,您已经非常熟悉不变性原则。
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
控制台输出:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
正如您所期望的,我们的数字没有改变。为了使加法操作成功,您必须创建一个新对象并将加法结果分配给它。
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
控制台输出:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
现在一切都正常了:) 顺便说一句,您是否注意到加法操作看起来有多不寻常?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
这是另一个重要的一点。大量类在其操作中不使用 +-*/ 运算符,而是提供一组方法。 让我们看一下主要的方法(您可以一如既往地在 Oracle 文档中找到完整的方法列表:此处此处)。
  1. 执行算术运算的方法: add()subtract()multiply()divide()。分别用于加、减、乘、除运算。

  2. doubleValue()intValue()floatValue()longValue()ETC。- 用于将大量数字转换为 Java 基本类型。使用时要小心,记住容量的差异!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }

    控制台输出:

    
    8198552921648689607
  3. min()max()- 允许您找到传递的两个大数的最小值和最大值。
    请注意:方法不是静态的!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }

    控制台输出:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

BigDecimal 舍入控制

这个主题包含在一个单独的部分中,因为对大数进行舍入和调整并不是一件简单的事情。BigDecimal您可以使用 来设置数字的小数位数setScale()。例如,我们要将数字111.5555555555的精度设置为小数点后三位。但是,我们将无法将数字 3 作为参数传递给该方法setScale(),从而解决我们的问题。如上所述,BigDecimal这些是用于提高精度的计算的数字。在目前的形式中,我们的数字有 10 位小数。我们想丢弃其中的 7 个,只留下 3 个。因此,除了数字 3 之外,我们还必须将舍入模式作为参数传递共有8种舍入模式BigDecimal非常多!但如果您需要真正微调程序中的计算精度,您将拥有所需的一切。因此,以下是 中可用的 8 种舍入模式BigDecimal
  1. ROUND_CEILING- 围捕

    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
  2. ROUND_DOWN- 排放丢弃

    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
  3. ROUND_FLOOR- 向下舍入

    111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555

  4. ROUND_HALF_UP— 如果小数点后的数字 >= .5,则四舍五入

    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
  5. ROUND_HALF_DOWN— 如果小数点后的数字 > .5,则四舍五入

    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
  6. ROUND_HALF_EVEN— 四舍五入取决于小数点左边的数字。如果左边的数字是偶数,则向下舍入。如果小数点左边的数字是奇数,则四舍五入。

    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2

    小数点左边的数字 - 2 - 是偶数。向下舍入。由于我们要求小数点后 0 位,因此结果将为 2。

    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4

    小数点左边的数字 - 3 - 是奇数。向上舍入。由于我们要求小数点后 0 位,因此结果将为 4。

  7. ROUND_UNNECCESSARY— 用于需要将舍入模式传递给某种方法,但数字不需要舍入的情况。如果在设置 ROUND_UNNECCESSARY 模式时尝试对数字进行舍入,则会引发 ArithmeticException。

    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
  8. ROUND_UP- 围捕。

    111.5551 -> setScale(3, ROUND_UP) -> 111.556

大数比较

这个问题也很重要。您已经记得该方法用于比较 Java 中的对象equals()。它要么由语言本身提供(对于 Java 的内置类),要么由程序员覆盖。但对于类对象的情况,不建议BigDecimal使用该方法equals()进行比较。原因是只有当BigDecimal.equals()两个数字具有相同的值和小数位数时,双数方法才会返回true :让我们比较一下y和 y方法的行为: equals()DoubleBigDecimal
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));

   }
}
控制台输出:

true
false
正如您所看到的,在 c 的情况下,数字 1.5 和 1.50BigDecimal原来是不相等的!equals()发生这种情况正是因为类中方法的特殊性BigDecimal。为了更正确地比较两者,BigDecimal最好使用以下方法compareTo()
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
控制台输出:

0
该方法compareTo()返回 0,这意味着等于 1.5 和 1.50。这就是我们所指望的结果!:) 今天的课程到此结束。是时候回去执行任务了!:)
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION