【Java 常用类】(5)java.math.BigInteger的常用方法(一文简单学完BigInteger的常用方法)




前言

  上次更新了数字相关的,包装类Byte、Short、Integer、Long 、Float、Double和抽象类Number类。还更新了Math类。这次想着就顺手把大整型BigInteger和BigDecimal更新了。

  BigInteger和BigDecimal这两个类非常有用。尤其是在处理一些大数的情况下帮助巨大(算法题需要处理大数时都可以借助这两个类来简单解决)。这篇文章先讲BigInteger

一、大纲

java.math包:提供用于执行任意精度整数算法 (BigInteger) 和任意精度小数算法 (BigDecimal) 的类。

  包下一共也就才三个类:BigDecimal、BigInteger、MathContext(从没用过)。重点掌握前两个。我想很多学C/C++的选手学习Java主要就是这两个类吧。

  BigInteger描述是这样的:“不可变的、任意精度的有符号十进制数。” 简单理解BigInteger其实就是数字,不过这个数字可以比long还大而已。

  BigInteger中提供了算数运算比如加+ 减- 乘 *除 / 方法。提供了 java.lang.Math类(数学类)的相关方法。还提供了模算术、GCD(最大公约数) 计算、质数测试、素数生成、位操作以及一些其他操作。

  注意:BigInteger是不可变的,为啥不可变呢?这个类又没有final关键字修饰。那你想想之前学的基本数据类型包装类可变吗。BigInteger很多方法返回一个BigInteger类型的值,每次都是一个新的BigInteger对象(推荐按住ctrl点进去看源码)。

public class BigInteger extends Number implements Comparable<BigInteger>

二、使用

1.字段

提供了三个常量字段,分别是0、1、10。类型都是BigInteger。

BigInteger zero = BigInteger.ZERO;
BigInteger one = BigInteger.ONE;
BigInteger ten = BigInteger.TEN;

2.构造器

2.1 字节数组转十进制

传入一个字节数组,把字节数组转换成一个十进制的数字。

  • 可以理解成256进制,逢256进1。所以如果字节数组是{2, 0}就该输出512了。

  • 当然你可以理解成这样:将字节数组中的每一位转换成二进制,连接起来。
    如下字节数组:{1, 0}转化成二进制并连接成了0000 0001 0000 0000。然后再将这串二进制转换成十进制,则是256了。负数同理。

byte[] arr = {1,0};
BigInteger b01 = new BigInteger(arr);
System.out.println(b01); // 输出256。
// 可以理解成256进制,逢256进1。所以如果字节数组是{2, 0}就该输出512了。
2.2 字符串转数字

将一个字符串转换成一个数字,字符串需要是一个由正负号加上数字组成的字符串,不然会抛出异常。

BigInteger b = new BigInteger("123456789987654321");
System.out.println(b); // 输出 123456789987654321
2.3 n进制转十进制

将一个指定进制的字符串转换成一个BigInteger(十进制)。

备注:这个超级有用,当你需要将一个n进制的数转换成10进制,那你直接使用这个构造器即可。
我记得写算法题的时候用到过几次,给你一个比较大的n进制数字,然后进行进制转换变成10进制。
(如:蓝桥杯练习系统 - 试题集 - 基础练习 - 十六进制转八进制)

BigInteger b = new BigInteger("10000000", 2); // 输入2进制转10进制
System.out.println(b); // 输出 8

BigInteger b2 = new BigInteger("FF", 16); // 输入16进制转10进制
System.out.println(b2); // 输出 255

3.常用方法

我们刚开始可以主要学他的 算术运算符,其他常用方法可以慢慢学(欢迎收藏该篇文章。或关注我)。

3.1 算数运算符(加减乘除 + 取余)

BigInteger的重点来了,我们使用BigInteger不是使用构造器就是该类的加减乘除和取余了。掌握这几个方法你就可以说你会简单的BIgInteger了!

BigInteger a = new BigInteger("1111222233334444");
BigInteger b = new BigInteger("1111222233334444");

BigInteger add = a.add(b);// 加法
System.out.println(add); // 2222444466668888

BigInteger subtract = a.subtract(b); // 减法
System.out.println(subtract); // 0

BigInteger multiply = a.multiply(b); // 乘法
System.out.println(multiply); // 1234814851856789506098756789136

BigInteger divide = a.divide(b); // 除法
System.out.println(divide); // 1

BigInteger mod = a.mod(b); // 取余(只返回正数)
System.out.println(mod);

BigInteger remainder = a.remainder(b); // 取余(正负数都有可能返回)
System.out.println(remainder); // 0

// 求商和余数
BigInteger[] bigIntegers = a.divideAndRemainder(b); // 返回一个BigInteger数组,bigIntegers[0]是a/b的商,bigIntegersp[1]是a%b的余
System.out.println(bigIntegers[0]+" "+bigIntegers[1]); // 1 0(商1,余0)
3.2 比较两数大小

三个方法主要比较两个数的大小。

compareTo()方法是实现了接口Comparable来的方法。

另外两个min()和max()是比较并返回一个值。

BigInteger a = new BigInteger("2"); // 10
BigInteger b = new BigInteger("4"); // 100

int i = a.compareTo(b); // a和b谁大,小于返回-1,等于返回0,大于返回1
System.out.println(i); // -1

BigInteger max = a.max(b);  // 返回a和b中较大的一个
System.out.println(max); // 4

BigInteger min = a.min(b); // 返回a和b中较小的一个
System.out.println(min); // 2
3.3 十进制转n进制

我们在看BigInteger的构造器的时候看到了 n进制转十进制 ,同时他也提供了 十进制转n进制的方法

这个也是比较常用的。尤其是在大数进制转换的时候,虽然包装类Long和Integer也提供了进制转换,但是并不能转换大数。

感兴趣包装类请 点这里:

Java包装类详解

【Java 常用类】(2)java.lang.Byte、Short、Integer、Long 、Float、Double的常用方法(包装类)

BigInteger a = new BigInteger("15");

String s2 = a.toString(2);// 返回a的2进制
System.out.println(s2);
String s16 = a.toString(16); // 返回a的十六进制
System.out.println(s16);
3.3 最大公约数

计算两个数绝对值的 最大公约数

备注:这个方法非常好用,计算最大公约数的时候都可以用这个来做。而不用 辗转相除法辗转相减(更相减损术) 求最大公约数了。做算法题时候有遇到好几次求最大公约数的题目,用这个就很简单了。

BigInteger a = new BigInteger("4");
BigInteger b = new BigInteger("6");

BigInteger gcd = a.gcd(b); // a和b的最大公约数
System.out.println(gcd); // 2
3.4 BigInteger继承的方法

BigInteger继承了Object和Number的方法,这几个方法是很常见的,尤其是equals()和toString()方法。看过我前面博客的都见过这几个方法了。

BigInteger a = new BigInteger("5");
BigInteger b = new BigInteger("5");

// 继承Object类的方法
boolean equals = a.equals(b); // 比较两个BigInteger是否相等,只有传入值为BigInteger类型且值相等时才返回true
System.out.println(equals); // true
String s = a.toString(); // 打印a的字面量
System.out.println(s); // 5

// 继承Number抽象类的方法
int i = a.intValue(); // 返回一个int类型的值
System.out.println(i); // 5
long l = a.longValue(); // 返回一个long类型的值
System.out.println(l); // 5
3.5 BigInteger和Math类相同的方法

用法和作用java.lang.Matn类是一样的,只不过数字比较大而已。

BigInteger a = new BigInteger("-2");
BigInteger b = new BigInteger("-123456789987654321");

BigInteger abs = a.abs(); // a的绝对值
System.out.println(abs); // 2

BigInteger min = a.min(b); // 返回a和b较小的数
System.out.println(min); // -123456789987654321

BigInteger max = a.max(b); // 返回a和b较大的数
System.out.println(max); // -2

BigInteger pow = a.pow(4); // 返回a的4次,即a^4
System.out.println(pow); // 16
3.6 素数判断获取

下面是素数的 判断 和 获取。

我想你碰到一个超级大的素数时,你调用这两个方法来判断和获取会简单很多吧。

BigInteger a = new BigInteger("2");
// 1.判断一个数是否是素数
boolean probablePrime = a.isProbablePrime(1); // 如果返回false,那么一定是合数。如果返回true可能是素数,概率和传入值有关
System.out.println(probablePrime);

// 2.获取下一个素数,返回是合数的概率为2的-100次方。还有有概率返回偶数的。
BigInteger b = a.nextProbablePrime(); // 返回大于a的下一个素数
System.out.println(b); // 3

3.7 最小的二进制补码表示形式的位数

获得该数最小的二进制补码表示形式的位数。

BigInteger a = new BigInteger("2"); // 10
BigInteger b = new BigInteger("4"); // 100

int bitA = a.bitLength(); // 最少能表示a的二进制补码bit位个数。不包括符号位
System.out.println(bitA); // 2

int bitB = b.bitLength(); // 最少能表示b的二进制补码bit位个数。不包括符号位
System.out.println(bitB); // 3
3.8 获取当前数的相反数 + 获取正负符号

个人感觉作用不大,当多认识单词了。

BigInteger a = new BigInteger("2");

//当BigInteger为正时,返回为负数的BigInteger,为负时,返回正的。即0减去当前BigInteger。
BigInteger negate = a.negate(); // 返回 0 - a
System.out.println(negate); // 2

// 获取BigInteger的正负符号,负数返回-1,0返回0,正数返回1
int signum = a.signum(); // 负数返回-1,0返回0,正数返回1
System.out.println(signum); // 1
3.9 long转BigInteger(静态方法)

用valueOf()方法可以将一个long类型的数字,转换成BigInteger类型。然后就可以进行大数运算和其他操作了。

long lg = 12345678910000l;
BigInteger b = BigInteger.valueOf(lg);
System.out.println(b); // 输出 12345678910000
3.10 位运算符(与或非 + 异或)

注意:看懂这里的方法需要理解 位运算符,原码反码补码

如果接下来几个有点难理解,看不懂就跳过这小结吧,位运算符 相比上面的 算数运算符 你会用的少一点。

毕竟只是几个方法而已不影响学习BigInteger的,反正用的相对较少。但是会这几个方法后,遇到了大整数位运算问题会从容很多。

你说你很感兴趣,想学?非常好,来,那我们继续,这里可能会比较花时间。

老规矩,上代码我们来看效果:

BigInteger a = new BigInteger("2"); // 二进制 0000 0010
BigInteger b = new BigInteger("4"); // 二进制 0000 0100
// &
BigInteger and = a.and(b); // & 与运算
System.out.println(and); // 0(二进制:0000 0000)
// |
BigInteger or = a.or(b); // | 或运算
System.out.println(or); // 6(二进制:0110)
// ^
BigInteger xor = a.xor(b); // ^ 异或运算
System.out.println(xor); // 6(二进制:0110)
// ~
BigInteger not = a.not(); // ~ 非运算(取反运算)
System.out.println(not); // -3(二进制原码:负数0011)请看上面我的解释
BigInteger not2 = b.not(); // ~ 取反运算
System.out.println(not2); // -9(二进制原码:负数1001) 同理
// <<
BigInteger shiftLeftA = a.shiftLeft(1); // <<左移运算,0000 0010向左移动1位变成0000 0100,后面补了1个0,相当于a*2
System.out.println(shiftLeftA); // 4
BigInteger shiftLeftB = b.shiftLeft(1); // <<左移运算,0000 0100向左移动1位变成0000 1000,后面补了1个0,相当于b*2
System.out.println(shiftLeftB); // 8
BigInteger shiftLeftA2 = a.shiftLeft(2); // <<左移运算,0000 0010向左移动2位变成0000 1000,后面补了2个0,相当于a*2*2
System.out.println(shiftLeftA2); // 8
BigInteger shiftLeftB2 = b.shiftLeft(2); // <<左移运算,0000 0100向左移动1位变成0001 0000,后面补了2个0,相当于b*2*2
System.out.println(shiftLeftB2); // 16		
// >>
BigInteger shiftRightA = a.shiftRight(1); // >>右移运算,0000 0010向右移动1位变成0000 0001,最后去除了1个数,相当于a/2
System.out.println(shiftRightA); // 1
BigInteger shiftRightB = b.shiftRight(1); // >>右移运算,0000 0100向左移动1位变成0000 0010,最后去除了1个数,相当于b/2
System.out.println(shiftRightB); // 3
BigInteger shiftRightA2 = a.shiftRight(2); // >>右移运算,0000 0010向左移动2位变成0000 0000,最后去除了2个数,相当于a/2/2
System.out.println(shiftRightA2); // 0
BigInteger shiftRightB2 = b.shiftRight(2); // >>右移运算,0000 0100向左移动1位变成0000 0001,最后去除了2个数,相当于b/2/2
System.out.println(shiftRightB2); // 1

我猜测你非运算符可能没看懂。如果你看懂了,很好,说明基础还不错。没看懂也没关系,多百度google学一下就好了。

没看懂的话来吧,我在这里等你呢。不过你在看下面之前,推荐你去百度google 位运算符原码反码补码 了解一下!一定要理解我加粗了的这几个名词再继续往下!

  • Java中位运算符有这七种:与&、或|、非~、异或^、左移<<、右移>>、右移>>>。
    除了(右移>>>运算符),BigInteger都有实现了的方法。

我这里单独解释一下稍微难理解的难的非运算符~ ,运算符~ 涉及到了原码反码补码。

  • 非运算问题:
    问:为什么2的取反是-3?
    答:数字在计算中是以补码的形式存储。正数的原码补码反码都一样。负数就不一样了(负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1))
    1.原码2转换二进制为0000 0010(原码,反码,补码都是它)。.
    2.得知2的补码为0000 0010,此时使用非运算符~,取反得到的补码为1111 1101(补码)。
    3.此时将1111 1101(补码)转成原码,此时减一变成1111 1100(反码),取反变成1000 0011(原码)
    注意:第一个是符号位,代表负数,取反时不变。
    所以二进制1000 0011就是 - 3了。

  • 非运算问题 2:
    问:为什么4的取反是-9?
    答:与上面同理。
    1.4转二进制0000 1000(原码,补码,反码)
    2.4的补码用非~运算符取反1111 0111(补码)
    3.1111 0111(补码)转成原码,减一变反码1111 0110(反码),取反变原码 1000 1001(原码)。
    所以二进制1000 1001就是 - 9了。

总结:

  以上就是我用BigInteger的常用方法了,主要就是一个对数的操作。

  最后:如果你能把我分享的这篇看到最后,我就很高兴了。如果对你有帮助,欢迎给我点赞,也非常欢迎关注我,我正在继续更新中。

  当然有不足也希望可以留言或私信我。感谢!


相关链接

上一篇:【Java 常用类】(4)java.lang.Math的常用方法

当前篇:【Java 常用类】(5)java.math.BigInteger的常用方法(一文简单学完BigInteger的常用方法)

下一篇:【Java 常用类】(6)java.math.BigDecimal的常用方法。正在更新中

相关:

Java包装类详解

【Java 常用类】大纲

【Java 常用类】(2)java.lang.Byte、Short、Integer、Long 、Float、Double的常用方法(包装类)

发布了86 篇原创文章 · 获赞 104 · 访问量 6604

猜你喜欢

转载自blog.csdn.net/weixin_44034328/article/details/103942171