目录
一、Biginteger
API解释:
学习笔记:
BigInteger 常见方法
BigInteger底层存储方式
二、BigDecimal
API解释
学习笔记
BigDecimal的作用
BigDecimal的使用
BigDecimal的底层存储方式
不可变的任意精度的整数。所有操作中,都以二进制补码形式表示 BigInteger(如 Java 的基本整数类型)。BigInteger 提供所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。另外,BigInteger 还提供以下运算:模算术、GCD 计算、质数测试、素数生成、位操作以及一些其他操作。
算术运算的语义完全模仿 Java 整数算术运算符的语义,如 The Java Language Specification 中所定义的。例如,以零作为除数的除法抛出 ArithmeticException,而负数除以正数的除法则产生一个负(或零)的余数。Spec 中关于溢出的细节都被忽略了,因为 BigIntegers 所设置的实际大小能适应操作结果的需要。
位移操作的语义扩展了 Java 的位移操作符的语义以允许产生负位移距离。带有负位移距离的右移操作会导致左移操作,反之亦然。忽略无符号的右位移运算符(>>>),因为该操作与由此类提供的“无穷大的词大小”抽象结合使用时毫无意义。
逐位逻辑运算的语义完全模仿 Java 的逐位整数运算符的语义。在执行操作之前,二进制运算符(and、or、xor)对两个操作数中的较短操作数隐式执行符号扩展。
比较操作执行有符号的整数比较,类似于 Java 的关系运算符和相等性运算符执行的比较。
提供的模算术操作用来计算余数、求幂和乘法可逆元。这些方法始终返回非负结果,范围在 0 和 (modulus - 1)(包括)之间。
位操作对其操作数的二进制补码表示形式的单个位进行操作。如有必要,操作数会通过扩展符号来包含指定的位。单一位操作不能产生与正在被操作的 BigInteger 符号不同的 BigInteger,因为它们仅仅影响单个位,并且此类提供的“无穷大词大小”抽象可保证在每个 BigInteger 前存在无穷多的“虚拟符号位”数。
为了简洁明了,在整个 BigInteger 方法的描述中都使用了伪代码。伪代码表达式 (i + j) 是“其值为 BigInteger i 加 BigInteger j 的 BigInteger”的简写。伪代码表达式 (i == j) 是“当且仅当 BigInteger i 表示与 BigInteger j 相同的值时,才为 true”的简写。可以类似地解释其他伪代码表达式。
当为任何输入参数传递 null 对象引用时,此类中的所有方法和构造方法都将抛出 NullPointerException
。
在Java中,整数有四种类型: byte,short,int,long。
在底层占用字节个数: byte1个字节、short2个字节、int4个字节、long8个字节。
超出long类型的范围可以使用BigInteger
对象一旦创建,内部记录的值不能发生改变
//1.获取一个随机的大整数
BigInteger bd1 = new BigInteger(4, new Random());
System.out.println(bd1);
//2.获取一个指定的大整数
//细节:字符串中必须是整数,否则会报错
BigInteger bd2 = new BigInteger("100");
System.out.println(bd2);
//3.获取指定进制的大整数
/*
* 细节:
* 1.字符串中的数字必须是整数
* 2.字符串中的数字必须要跟进制吻合
* 比如二进制中,那么只能写0和1,写其他的就报错
* */
BigInteger bd3 = new BigInteger("100", 10);
System.out.println(bd3);
//4.静态方法获取BigInteger的对象,内部有优化
/*
* 细节:
* 1.能表示范围比较小,只能在long的取值范围之内,如果超出long的范围就不行了
* 2.在内部对常用的数字:-16 ~ 16 进行了优化。
* 提前把 -16 ~ 16 先创好BigInteger的对象,如果多次获取不会重新创建新的。
* */
BigInteger bd4 = BigInteger.valueOf(100);
System.out.println(bd4);
//1.创建两个BigInteger对象
BigInteger bd1 = BigInteger.valueOf(10);
BigInteger bd2 = BigInteger.valueOf(3);
//2.加法
BigInteger bd3 = bd1.add(bd2);
System.out.println(bd3);
//3.减法
BigInteger bd4 = bd1.subtract(bd2);
System.out.println(bd4);
//4.乘法
BigInteger bd5 = bd1.multiply(bd2);
System.out.println(bd5);
//5.除法,获取商
BigInteger bd6 = bd1.divide(bd2);
System.out.println(bd6);
//6.除法,获取商和余数
BigInteger[] bd7 = bd1.divideAndRemainder(bd2);
System.out.println(bd7[0]);
System.out.println(bd7[1]);
//7.比较是否相同
boolean result = bd1.equals(bd2);
System.out.println(result);
//8.次幂
BigInteger bd8 = bd1.pow(2);
System.out.println(bd8);
//9.返回较大值/较小值
BigInteger bd9 = bd1.max(bd2);
System.out.println(bd9);
BigInteger bd10 = bd1.min(bd2);
System.out.println(bd10);
//10.转为int类型整数,超出范围数据有误
int i = bd1.intValue();
System.out.println(i);
不可变的、任意精度的有符号十进制数。BigDecimal 由任意精度的整数非标度值 和 32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂。因此,BigDecimal 表示的数值是 (unscaledValue × 10-scale)。
BigDecimal 类提供以下操作:算术、标度操作、舍入、比较、哈希算法和格式转换。toString()
方法提供 BigDecimal 的规范表示形式。
BigDecimal 类使用户能完全控制舍入行为。如果未指定舍入模式,并且无法表示准确结果,则抛出一个异常;否则,通过向该操作提供适当的 MathContext
对象,可以对已选择的精度和舍入模式执行计算。在任何情况下,可以为舍入控制提供八种舍入模式。使用此类(例如,ROUND_HALF_UP
)中的整数字段来表示舍入模式已过时;应改为使用 RoundingMode enum(例如,RoundingMode.HALF_UP
)的枚举值。
当为 MathContext 对象提供 0 的精度设置(例如,MathContext.UNLIMITED
)时,算术运算是准确的,它们是不采用任何 MathContext 对象的算术方法。(这是第 5 版之前的版本支持的唯一行为。)为了计算准确结果,不使用附带 0 精度设置的 MathContext 对象的舍入模式设置,因此与该对象无关。在除法中,准确的商可能是一个无限长的十进制扩展;例如,1 除以 3 所得的商。如果商具有无穷的十进制扩展,但是指定了该操作返回准确结果,则抛出 ArithmeticException。否则,像其他操作那样,返回除法运算的准确结果。
当精度设置不为 0 时,BigDecimal 算法的规则完全符合 ANSI X3.274-1996 和 ANSI X3.274-1996/AM 1-2000( 7.4 节)中定义的算法的可选操作模式。与上述标准不同,BigDecimal 包括多种舍入模式,它们对于版本 5 以前的 BigDecimal 版本中的除法是强制性的。这些 ANSI 标准和 BigDecimal 规范之间的任何冲突都按照有利于 BigDecimal 的方式进行解决。
由于同一数值可以有不同的表示形式(具有不同的标度),因此运算和舍入的规则必须同时指定数值结果和结果表示形式中所用的标度。
一般情况下,当准确结果(在除法中,可能有无限多位)比返回的数值具有更多位数时,舍入模式和精度设置确定操作如何返回具有有限位数的结果。 首先,MathContext 的 precision 设置指定要返回的总位数;这确定了结果的精度。位数计数从准确结果的最左边的非零数字开始。舍入模式确定丢弃的尾部位数如何影响返回的结果。
对于所有算术运算符,运算的执行方式是,首先计算准确的中间结果,然后,使用选择的舍入模式将其舍入为精度设置(如有必要)指定的位数。如果不返回准确结果,则将丢弃准确结果的某些数位。当舍入增加了返回结果的大小时,前导数字“9”的进位传播可能会创建新的数位。例如,将值 999.9 舍入为三位数字,则在数值上等于一千,表示为 100×101。在这种情况下,新的 "1" 是返回结果的前导数位。
除了逻辑的准确结果外,每种算术运算都有一个表示结果的首选标度。下表列出了每个运算的首选标度。
这些标度是返回准确算术结果的方法使用的标度;准确相除可能必须使用较大的标度除外,因为准确的结果可能有较多的位数。例如,1/32 得到 0.03125。
舍入之前,逻辑的准确中间结果的标度是该运算的首选标度。如果用 precision
位数无法表示准确的数值结果,则舍入会选择要返回的一组数字,并将该结果的标度从中间结果的标度减小到可以表示实际返回的 precision
位数的最小标度。如果准确结果可以使用最多 precision
个数字表示,则返回具有最接近首选标度的标度的结果表示形式。尤其是,通过移除结尾零并减少标度,可以用少于 precision
个数字来表示准确的可表示的商。例如,使用 floor 舍入模式将结果舍入为三个数字,19/100 = 0.19 // integer=19, scale=2
但是21/110 = 0.190 // integer=190, scale=3
注意,对于加、减和乘,标度的缩减量将等于丢弃的准确结果的数字位置数。如果舍入导致进位传播创建一个新的高位,则当未创建新的数位时,会丢弃该结果的附加数字。
其他方法可能与舍入语义稍微不同。例如,使用指定的算法的 pow 方法得到的结果可能偶尔不同于舍入得到的算术结果,如最后一位有多个单位(ulp)。
可以通过两种类型的操作来处理 BigDecimal 的标度:标度/舍入操作和小数点移动操作。标度/舍入操作(setScale
和 round
)返回 BigDecimal,其值近似地(或精确地)等于操作数的值,但是其标度或精度是指定的值;即:它们会增加或减少对其值具有最小影响的存储数的精度。小数点移动操作(movePointLeft
和 movePointRight
)返回从操作数创建的 BigDecimal,创建的方法是按指定方向将小数点移动一个指定距离。
为了简洁明了起见,整个 BigDecimal 方法的描述中都使用了伪代码。伪代码表达式 (i + j) 是“其值为 BigDecimal i 加 BigDecimal j 的 BigDecimal”的简写。伪代码表达式 (i == j) 是“当且仅当 BigDecimal i 表示与 BigDecimal j 相同的值时,则为 true”的简写。可以类似地解释其他伪代码表达式。方括号用于表示特定的 BigInteger 和定义 BigDecimal 值的标度对;例如,[19, 2] 表示 BigDecimal 在数值上等于 0.19,标度是 2。
注:如果 BigDecimal 对象用作 SortedMap
中的键或 SortedSet
中的元素,则应特别小心,因为 BigDecimal 的自然排序与 equals 方法不一致。有关更多信息,请参见 Comparable
、SortedMap
或 SortedSet
。
当为任何输入参数传递 null 对象引用时,此类的所有方法和构造方法都将抛出 NullPointerException。
用于小数的精确计算
用来表示很大的小数
public static void main(String[] args) {
//0.通过传递double类型的小数来创建对象
//细节:
//这种方式有可能是不精确的,所以不建议使用
System.out.println("0.通过传递double类型的小数来创建对象");
BigDecimal bd1 = new BigDecimal(0.01);
BigDecimal bd2 = new BigDecimal(0.09);
System.out.println(bd1);
System.out.println(bd2);
//1.通过传递字符串表示的小数来创建对象
System.out.println("1.通过传递字符串表示的小数来创建对象");
BigDecimal bd3 = new BigDecimal("0.01");
BigDecimal bd4 = new BigDecimal("0.09");
System.out.println(bd3);
System.out.println(bd4);
//2.通过静态方法获取对象
System.out.println("2.通过静态方法获取对象");
BigDecimal bd5 = BigDecimal.valueOf(10.1);
System.out.println(bd5);
/*
* 细节
* 0.如果要表示的数字不大,没有超出double的取值范围,建议使用静态方法
* 1.如果要表示的数字比较大,超出了double的取值范围,建议使用构造方法
* 2.如果传递的是0~10之间的整数,包含0,包含10,那么方法会返回已经创建好的对象,不会重新new
* */
}
RoundingMode的使用请查阅