你好!在今天的讲座中,我们将讨论大数。不,关于真正大的。 之前,我们不止一次看到过原始数据类型的值范围表。它看起来像这样:
如果我们谈论整数,最大容量的数据类型是long,而当我们谈论浮点数时,最大容量的数据类型是 double。但是,如果我们需要的数字太大,甚至无法放入long中怎么办?可能的 Long 值的范围相当大,但仍然限制在一定的大小 - 64 位。如果我们的超大数有 100 位,我们能得出什么结果?幸运的是,您不需要发明任何东西。在 Java 中,为这种情况创建了两个特殊的类 - BigInteger(用于整数)和BigDecimal(用于浮点数)。他们的特点是什么?首先,理论上它们没有最大尺寸。理论上,因为不存在具有无限内存的计算机。而如果你在程序中创建的数字大于计算机内存的大小,当然程序将无法运行。但这种情况不太可能发生。因此,我们可以说数字的大小实际上
原始型 | 内存大小 | 数值范围 |
---|---|---|
字节 | 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(用于非数组时) | 对或错 |
BigInteger
是BigDecimal
无限的。这些类是用来做什么的?首先,对于精度要求极高的计算。例如,在某些程序中,人的生命可能取决于计算的准确性(飞机和火箭或医疗设备的软件)。因此,如果连小数点后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 文档中找到完整的方法列表:此处和此处)。
-
执行算术运算的方法:
add()
、subtract()
、multiply()
、divide()
。分别用于加、减、乘、除运算。 -
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
-
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
:
-
ROUND_CEILING
- 围捕111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
-
ROUND_DOWN
- 排放丢弃111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
-
ROUND_FLOOR
- 向下舍入111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555
-
ROUND_HALF_UP
— 如果小数点后的数字 >= .5,则四舍五入0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6 0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
-
ROUND_HALF_DOWN
— 如果小数点后的数字 > .5,则四舍五入0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5 0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.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。
-
ROUND_UNNECCESSARY
— 用于需要将舍入模式传递给某种方法,但数字不需要舍入的情况。如果在设置 ROUND_UNNECCESSARY 模式时尝试对数字进行舍入,则会引发 ArithmeticException。3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
-
ROUND_UP
- 围捕。111.5551 -> setScale(3, ROUND_UP) -> 111.556
大数比较
这个问题也很重要。您已经记得该方法用于比较 Java 中的对象equals()
。它要么由语言本身提供(对于 Java 的内置类),要么由程序员覆盖。但对于类对象的情况,不建议BigDecimal
使用该方法equals()
进行比较。原因是只有当BigDecimal.equals()
两个数字具有相同的值和小数位数时,双数方法才会返回true :让我们比较一下y和 y方法的行为: equals()
Double
BigDecimal
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。这就是我们所指望的结果!:) 今天的课程到此结束。是时候回去执行任务了!:)
GO TO FULL VERSION