[十六]基础类型BigInteger简介
属性简介
负数 | -1 |
0 | 0 |
正数 | 1 |
字节序为大端模式,大端模式就是低地址存储高位
对于BigInteger 他的数据打开就是这么一种形式
[ 101....32位....1] [ 110....32个....1] ....N个..... [ 0110....32个....1]
它的真值的计算方法与其他的二进制序列一样的
二进制为 0111 1110 的十进制为126 相信谁都会计算,BigInteger也是如此的
尤其是对于BigInteger字符串参数的构造形式
千万不要以为就是把字符的编码或者字符转换成数字切段存放到int数组中
他存放的都是转换后的真值
下面会详细介绍
|
使用字节数组构造
- 如果是一个负数,会先得到真值的绝对值
- 如果有前导零,还会去掉所有的前导零
原码/反码/补码
原码 |
符号位+数值位
符号位为0 表示正数,符号位为1 表示负数
数值位就是真值的绝对值
又被称为带符号的绝对值表示
|
反码 | 正数的反码为其原码 负数的反码为其原码的除符号位外,逐位取反 |
补码 | 正数的补码为其原码 负数的补码为其反码+1 |
补码计算步骤
第一步求原码: 先写出来她的原码--->符号位+数值位(绝对值) |
第二步求反码:
如果是正数 反码与原码一样
如果是负数 反码为原码取反(除符号位外,逐位翻转)
|
第三步求补码: 如果是正数 补码与原码一样 如果是负数 补码为反码 + 1 |
第四步扩充: 如果不足数据类型的宽度,将需要填充到指定宽度 符号位扩充,也就是正数补0 负数补1 |
总结 不管什么形式,第一位始终都是符号位,0 表示正数, 1表示负数 正数原码/反码/补码 全都一样,知道一种就直接得到另外的形式 负数如果知道补码,想要得到他的原码,只需要对补码再一次的求补码即可 |
示例1
示例2
使用String构造
算法基础
对于十进制
可以表示10位十进制数字
但是 2147483648 (2147483647+1) 仍旧是10位数字却溢出了
所以选择保存9位十进制数
所以每个int 十进制下最大值为10的9次方
|
对于二进制
最大值 231-1 ,所以只能保存30位 2进制数
所以每个int 二进制下最大值为2的30次方
|
对于三进制
319 =1162261467 <2147483647<320 = 3486784401
所以能够保存19位 三进制数
所以每个int 三进制下最大值为3的19次方
|
对于四进制
415 = 1073741824 < 2147483647 < 416 = 4294967296
所以能够保存15位 四进制数
所以每个int 四进制下最大值为4的15次方
|
对于十六进制 167 =268435456 < < 2147483647 < 168 = 4294967296 所以能够保存7位十六进制数 所以每个int 十六进制下最大值为16的7次方 |
所以就有了这么两个映射数组 digitsPerInt 表示每个int 可以表示的,指定进制下数字的位数,下标索引就是进制基数 比如可以表示十六进制的位数为digitsPerInt[16] = 7 intRadix 表示每个int可以表示的指定进制下的最大值,下标索引就是进制基数 比如 每一位int 可以表示的十进制的最大值为 intRadix[10] = 0x3b9aca00=1,000,000,000 其实intRadix这个数就是: BigInteger在这个基数下的基数 这句话有点绕,BigInteger内部是数组,假如为mag[0] mag[1] intRadix[10] = 0x3b9aca00 那么也就是,BigInteger在十进制,也就是10为基数下的基数为0x3b9aca00 那么这个值就是 mag[0] x 0x3b9aca001 + mag[1] x 0x3b9aca000 就如同十进制的数12的计算方式为1x101 + 2 x100 =12 一样的道理 下面还会继续说明 |
BigInteger内部使用int数组表示 普通数值使用每个数值位上的数字进行表示 |
一个BigInteger有多个int 一个普通数值有多个数字位 |
每个int能够表示的指定进制的最大值--intRadix 中保存的数据
其实 就是 BigInteger 的基于每个int作为一个元素的进制基数
|
假设R为指定的基数 L为指定基数的数字的长度 那么用多少位2进制数可以表示? |
x位二进制能够表示的最大值为 |
L位R进制的数能够表示的最大值为 比如R=10 L=2 也就是十进制两位数能够表示的最大值为: 10的平方减1 等于 99 |
解上面的方程,可以得出来 x的长度为 :L 乘以 以2为底R的对数 |
内部还有一个数组
这个数组的值就是以2为底R的对数的值,然后乘以1024,然后进行向上取整
|
bitsPerDigit 就是每个数字需要的比特位数乘以1024后在取整 之所以乘以1024然后在取整 应该是为了简化运算,这个数必然要是2的N次方,计算机移位最快 当然,这个地方乘以1024 实际使用的时候必然也还得除以1024 |
以2为底 2的对数 = 1 * 1024 = 1024 以2为底 3的对数 = 1.5849625007 * 1024 = 1623.0016007168 -> 1624 以2为底 4的对数 = 2 * 1024 = 2048 以2为底 5的对数 = 2.3219280949 * 1024 = 2377.6543691776 ->2378 以2为底 10的对数 = 3.3219280949 * 1024=3401.6543691776 -> 3402 以2为底 16的对数 = 4 * 1024 = 4096 |
digitsPerInt 表示不同基数(进制)下一个int 能够表示的数字的长度 ,这个位数其实就是按照多长进行分割组装
intRadix 就是基数
bitsPerDigit 是用来推算需要多少个int的,也就是int数组的长度
|
我们以一个最简单的例子进行演示:
计算字符串 "123" 十进制表示的数值
使用数组mag 来进行存储每一位数字
显然需要mag[3] 不要纠结mag类型,此处只是为了示例
|
1. 找到第一个字符 "1" ,转换为数字1, 然后保存到mag[3] = 1 (我们此处假定从数组最后开始存放) |
2. 找到第二个字符 "2" , 转换为数字2,然后 计算 mag[3] x 10 +2 mag[3] x 10 = 10 ,结果进行保存 mag[2] 保存1 mag[3] 保存0 然后再加上2 0+2 = 2 不用进位 所以最终结果为mag[3] = 2 mag[2] = 1 |
3. 找到第三个字符 "3" , 转换为数字3,然后 计算 (mag[2]mag[3]) x 10 +3 mag[2]mag[3] 就相当于是两位数 比如12 此时 mag[3] = 0 mag[2] = 2 mag[0] = 1 然后还需要加 3 mag[3] + 3 = 0+3 = 3 也没有进位 那么最终结果为 mag[0] = 1 mag[2] = 2 mag[3] = 3 |
以上就是一个简单的从字符串123 转换为10进制数,并且保存到数据的过程 String的构造就是类似这样的一个过程 |
构造方法源码解析
public BigInteger(String val, int radix) {
//定义了两个变量一个光标,光标记录着应该要处理的数据索引下标
//另一个numDigits 用来保存需要处理的数字位数 也就是有效长度,比如去掉前导零后的
, numDigits;
final int len = val.length();//传递进来的字符数组的长度
//如果给定的基数,不在合法范围内,那么抛出异常,不会默认处理
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
throw new NumberFormatException("Radix out of range");
//如果字符串长度为0 也是一种非法的参数
)
throw new NumberFormatException("Zero length BigInteger");
// Check for at most one leading sign
;
int index1 = val.lastIndexOf('-');
int index2 = val.lastIndexOf('+');
//符号- + 只能出现一个,而且还必须是第一个位置,否则都不合法
//根据最后一个的索引与0 进行比较,可以简便的判断符号位是否合法
) {
|| index2 >= ) {
throw new NumberFormatException("Illegal embedded sign character");
}
sign = -;
cursor = ;
} ) {
) {
throw new NumberFormatException("Illegal embedded sign character");
}
cursor = ;
}
//经过前面的判断,如果有符号位的话,光标的值更新为1 也就是后续不处理符号位
//如果此时光标的值等于字符长度,说明没有有效数字了,将会抛出异常
if (cursor == len)
throw new NumberFormatException("Zero length BigInteger");
// Skip leading zeros and compute number of digits in magnitude
//如果有前导0 ,将会去掉这些,光标的位置也会跟着一起移动
while (cursor < len &&
Character) {
cursor++;
}
//跳过了所有的0之后就不再有有效数据了,说明他就是个0
//哪怕他原来设置的负数的0 将会变为0 的标记
if (cursor == len) {
signum = ;
mag = ZERO.mag;
return;
}
//记录实际需要处理的数据长度以及对符号位使用signum进行记录
numDigits = len - cursor;
signum = sign;
// Pre-allocate array of expected size. May be too large but can
// never be too small. Typically exact.
//根据前面的公式计算实际需要的二进制位数 numDigits需要处理的数字的长度
//bitsPerDigit 里面记录了每个进制1位数需要的二进制位数,但是放大了1024倍,所以还要除以1024 也就是右移10
//真正的值可能是小数个,除以1024之后变成了取整了,然后再加上一,百分百够用,需要的比特位数保存到numBits
) + ;
>= (1L << )) {
reportOverflow();
}
//numWords 记录的是实际需要的int类型数据的个数,也就是数组的长度
//右移5位就是除以32 就是计算数组的长度,除法会取整,防止1个不足32位的时候,就会变成0了所以numBits加上31 之后再除以32
) >>> ;
//此时创建真正的保存数据的int数组了
int[] magnitude = new int[numWords];
// Process first (potentially short) digit group
//numDigits 需要处理的数字的个数
//digitsPerInt 保存的是每一个int能够保存的指定数制下的字符长度
//如果有余数,说明有一个不足最大长度的位数
//如果没有余数,那么每一组都是刚好能够保存的最大长度
int firstGroupLen = numDigits % digitsPerInt[radix];
)
firstGroupLen = digitsPerInt[radix];
//第一组数据存放到数组的最后一个
String group = val.substring(cursor, cursor += firstGroupLen);
magnitude[numWords - ] = Integer.parseInt(group, radix);
] < )
throw new NumberFormatException("Illegal digit");
// Process remaining digit groups
int superRadix = intRadix[radix];
;
while (cursor < len) {
group = val.substring(cursor, cursor += digitsPerInt[radix]);
groupVal = Integer.parseInt(group, radix);
)
throw new NumberFormatException("Illegal digit");
// 这个方法是用来累计计算的,方法内部写的很复杂
//其实逻辑很简单,比如一个数字序列1234,求他表示的值是多少
// ( ( (1*10)+2 )*10+3 )*10 +4 = 1234
//这个方法就是用来计算的,只不过每一个位置是一个int 低32位当做数值 高32位当做进位
destructiveMulAdd(magnitude, superRadix, groupVal);
}
// Required for cases where the array was overallocated.
mag = trustedStripLeadingZeroInts(magnitude);
if (mag.length >= MAX_MAG_LENGTH) {
checkRange();
}
}
构造方法运行步骤
字符串构造方法计算示例
-12345678986543215678901 字符串总长度24 负号占1位, 光标移动一个位置 cursor=1 还有23个字符长度需要处理 |
需要处理的数字个数为
numDigits = len - cursor = 23
需要的二进制位数为
((numDigits * bitsPerDigit[radix]) >>> 10) + 1
(23*3402)/1024 +1 = 76+1 = 77
需要的int个数, 也就是数组长度为3
(int) (numBits + 31) >>> 5 (77+31)/32 = 3(3.375)
|
十进制可以保存9位数字
23 不是9的倍数,商2 余数5
所以最高5位将会被截取单独存放
取前面5个数字,也就是12345
12345按照10进制解析为数字,存放到最后一个元素
也就是mag[2] = 12345 光标也跟随移动
|
数据显然没有处理结束, 进入循环处理, 直到最后结束 第一趟: 先获得接下来的9个字符 也就是 "678986543" ,然后解析为10进制数 678986543 此时 mag[0] = 0,mag[1] = 0 mag[2] = 12345 进入方法 destructiveMulAdd destructiveMulAdd(int数组, 基数, 截取到的值) 他会乘以基数然后加上截取到的数字 高32位进位,低32位作为得数 此时mag[0] 和mag[1] 不用在乘了,因为此时都是0 , mag[1] 加上进位即可 此时 mag[0]=0 mag[1] =2874 mag[2] 1263991296 还需要加上678986543 没有进位 所以第一趟结束之后,最终结果为 mag[0]=0 mag[1] =2874 1942977839 |
第二趟 获得接下来的9个字符 也就是 "215678901" ,然后解析为10进制数 215678901 低32位 为得数 高32位为计数
也就是
得数 -603122176 这是个有符号数
可以使用System.out.println(Integer.valueOf(0xDC0D1600)); 打印出来
进位 452384780
如同我们平时计算乘法一样,还需要计算前一位
此时 mag[0]=0 mag[1] =2874 mag[2] = -603122176
2874 x 10的9次方 = 2874000000000
加上 上一个进位 452384780
结果为 2874452384780
10 1001 1101 0100 0010 1011 0110 1001 1100 0000 1100
所以此时第二位得数为 1119263756(后32位)
进位 10 1001 1101 (高32位) 669
所以此时mag数组为:
mag[0] = 669 mag[1] = 1119263756 mag[2]= -603122176
还需要加上最后截取的数值
所以最终的结果为
mag[0]=669 mag[1] =1119263756 mag[2] = -387443275
|
其他构造方法
方法简介
基础方法
获取符号位 signum() |
常用数学函数 negate() 取负 abs() 绝对值 pow(int) 求幂
gcd(BigInteger) 最大公约数
min(BigInteger) 最小值
max(BigInteger) 最大值
|
四则运算与取整求余
add(BigInteger) 加法
subtract(BigInteger) 减法
multiply(BigInteger) 乘法
divide(BigInteger) 除法(取整)
remainder(BigInteger) 求余
divideAndRemainder(BigInteger) 取整和求余 返回的是一个数组
|
获取基本类型的值
不同于基本数值类型的包装类,此处并不是直接强转的
如果太大intValue 和 longValue 将分别返回低的32位和64位
longValue 和 doubleValue可能会被转换为无穷
intValue()
longValue()
floatValue()
doubleValue()
|
数值类型的准确值
longValueExact()
intValueExact()
shortValueExact()
byteValueExact()
所谓准确就是不会舍入或者转换,因为他们会进行数据长度的校验
否则将会抛出异常
比如
|
位操作相关
and(BigInteger) 与
or(BigInteger) 或
not() 非
xor(BigInteger) 异或
andNot(BigInteger) 返回其值为 (this & ~val) 的 BigInteger 等效于 and(val.not())
shiftLeft(int) 左移
shiftRight(int) 右移
|
取模与求余对比
计算过程相同
对于整型数a,b来说,取模运算或者求余运算的方法都是:
求模运算和求余运算在第一步不同:
取余运算在取c的值时,向0 方向舍入;
而取模运算在计算c的值时,向负无穷方向舍入;
因此,求模时结果的符号与b一致,求余时结果的符号与a一致
如果a,b都是正整数的话,求模与求余没有区别
|
mod(BigInteger)
返回其值为 (this mod m) 的 BigInteger,取模不同于 remainder
BigInteger modPow(BigInteger exponent,BigInteger m)
BigInteger modInverse(BigInteger m)
|
bitCount与bitLength
public int bitCount() 返回此 BigInteger 的二进制补码表示形式中与符号不同的位的数量 特别注意这个方法的含义 不是二进制补码表示形式的 1 位的数量,而是与符号不同的 |
bitLength 最小的二进制补码表示形式的位数,不包括 符号位 对于正 BigInteger,这等于常规二进制表示形式中的位数 就是去掉符号位占用的长度 |
valueOf(long)
valueOf(long) 包装一个long为BigInteger BigInteger的valueOf有缓冲的作用 |
equals(Object)
equals(Object) 重写了equals方法 数据相等 才是相等 |
toString hashCode CompareTo
public String toString(int radix) 转换为指定基数
toString()
|
hashCode() |
compareTo(BigInteger)
小于、等于或大于 时,返回 -1,0,或 1
|
素数相关
是否素数
public boolean isProbablePrime(int certainty)
如果此 BigInteger 可能为素数,则返回 true,如果它一定为合数,则返回 false
如果 certainty <= 0,则返回 true
参数:
certainty - 调用方允许的不确定性的度量
如果该调用返回 true,则此 BigInteger 是素数的概率超出 ( 1 - 1/(2的certainty次方) )
此方法的执行时间与此参数的值是成比例的
返回:
如果此 BigInteger 可能为素数,则返回 true,如果它一定为合数,则返回 false
|
public static BigInteger probablePrime(int bitLength,
Random rnd)
返回有可能是素数的、具有指定长度的正 BigInteger 参数:
bitLength - 返回的 BigInteger 的 bitLength。
rnd - 随机比特源,用这些随机比特选择用来进行质数测试的候选数
|
nextProbablePrime
public BigInteger nextProbablePrime()
返回大于此 BigInteger 的可能为素数的第一个整数
此方法返回的数是合数的概率不超出 2的-100次方
|
特殊的"位操作"
testBit(int) 计算 (this & (1<<n)) != 0
setBit(int) 计算 this | (1<<n)
clearBit(int) 计算 this & ~(1<<n)
flipBit(int) 计算 this ^ (1<<n)
|
getLowestSetBit()
返回此 BigInteger 最右端(最低位)1 比特位的索引
也就是从最右边开始数找到的第一个1
此字节的右端开始到本字节中最右端 1 之间的 0 比特的位数
如果此 BigInteger 不包含1位,则返回 -1
计算 this==0? -1 : log2(this & -this)
|
toByteArray
public byte[] toByteArray() |
BigInteger 内部使用int数组进行数据保存 一个int包含4个byte BigInteger可以使用byte数组构造 也自然能够分解成byte数组进行保存 |
总结
[十六]基础类型BigInteger简介的更多相关文章
- 第四百一十六节,Tensorflow简介与安装
第四百一十六节,Tensorflow简介与安装 TensorFlow是什么 Tensorflow是一个Google开发的第二代机器学习系统,克服了第一代系统DistBelief仅能开发神经网络算法.难 ...
- [十七]基础类型BigDecimal简介
BigDecimal是不可变的.任意精度的.有符号的.十进制数. 组成部分 BigDecimal 由任意精度的整数非标度值 和 32 位的整数标度 (scale) 组成 BigDecimal ...
- [十四]基础类型之StringBuffer 与 StringBuilder对比
StringBuilder 和 StringBuffer是高度类似的两个类 StringBuilder是StringBuffer的版本改写,下面从几个方面简单的对比下他们的区别 类继承关系 上文中,我 ...
- C++学习基础十四——基础类型vector
一.vector的使用 1. #include <vector> 2. 初始化的四种方法 vector<T> v1; vector<T> v2(v1); vecto ...
- 《手把手教你》系列基础篇(八十六)-java+ selenium自动化测试-框架设计基础-Log4j实现日志输出(详解教程)
1.简介 自动化测试中如何输出日志文件.任何软件,都会涉及到日志输出.所以,在测试人员报bug,特别是崩溃的bug,一般都要提供软件产品的日志文件.开发通过看日志文件,知道这个崩溃产生的原因,至少知道 ...
- Python之路【第十六篇】:Django【基础篇】
Python之路[第十六篇]:Django[基础篇] Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了O ...
- salesforce零基础学习(七十六)顺序栈的实现以及应用
数据结构中,针对线性表包含两种结构,一种是顺序线性表,一种是链表.顺序线性表适用于查询,时间复杂度为O(1),增删的时间复杂度为O(n).链表适用于增删,时间复杂度为O(1),查询的时间复杂度为O(n ...
- 十六. Python基础(16)--内置函数-2
十六. Python基础(16)--内置函数-2 1 ● 内置函数format() Convert a value to a "formatted" representation. ...
- 进击的Python【第十六章】:Web前端基础之jQuery
进击的Python[第十六章]:Web前端基础之jQuery 一.什么是 jQuery ? jQuery是一个JavaScript函数库. jQuery是一个轻量级的"写的少,做的多&quo ...
随机推荐
- 最简单的原生js和jquery插件封装
最近在开发过程中用别人的插件有问题,所以研究了一下,怎么封装自己的插件. 如果是制作jquery插件的话.就将下面的extend方法换成 $.extend 方法,其他都一样. 总结一下实现原理: 将 ...
- 资源验证(Modified)
Last-Modified : 上次修改时间 配合 If-Modified-Since 或者 If-Unmodified-Since (请求头携带) 对比上次修改时间对资源进行验证 Etag验证 数 ...
- deepin 开机进入 initramfs,无法开机
原因 这个问题多是由于不正常关机造成文件系统出问题导致的 解决 fsck -t ext4 /dev/sda6 这个命令用于修复磁盘,一直选择y即可. 如果sda6 不行就换位sda1 再试. 执行完后 ...
- VMware vsphere client报错问题
今天出现一种情况,搞了很久,重装client都不行,原来很简单,防止再犯. 异常信息:"VirtualInfrastructure.Utils.ClientsXml"的类型 ...
- 数位DP -启示录
http://poj.org/problem?id=3208 一个魔鬼数为包含连续三个666的的数字,给个n(n<5e7)求第n个魔鬼数. 预处理f[i][j],f[i][3]表示由前i位数字构 ...
- vue命名视图实现经典布局
vue命名视图实现经典布局 <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...
- web测试实践——day01
一.任务进展情况 主要是找寻网站的bug,分析bug的严重程度.同时找了本专业的同学进行博客园系统的使用. 二.存在的问题 由于上线的网站做的比较完善,导致找寻bug比较困难. 三.解决方法 对此我们 ...
- QEMU KVM Libvirt手册(11): Managing Storage
When managing a VM Guest on the VM Host Server itself, it is possible to access the complete file sy ...
- [IOT] 自制蓝牙工牌办公室定位系统 (二)—— 基于ESP32的蓝牙信号扫描系统
前面章节: 自制蓝牙工牌办公室定位系统 (一)-- 阿里物联网平台概览及打通端到云(硬核·干货) 目录: 1.蓝牙广播简介 2.蓝牙扫描简介 3.基于蓝牙广播和蓝牙扫描常见应用 4.ESP32 ...
- [Swift]LeetCode44. 通配符匹配 | Wildcard Matching
Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '? ...