[⼗六]基础类型BigInteger简介
BigInteger和BigDecimal都是Java针对⼤数提供的类
超出了java的表⽰范围
属性简介
借助于signum和mag来实现数据的符号位和实际数据的保存
final int signum 保存BigInteger的符号
负数-1
00
正数1
final int[] mag;保存数字的数据
字节序为⼤端模式,⼤端模式就是低地址存储⾼位
数组的第⼀个元素必须是⾮0的,也就是如果有前导零将会被移除
这样可以保证每个数都有⼀个唯⼀的表⽰形式
这种要求下 BigInteger的0有⼀个0长度的数组保存
对于BigInteger 他的数据打开就是这么⼀种形式
[ 32位....1] [ 32个....1] ....N个..... [ 32个....1]
它的真值的计算⽅法与其他的⼆进制序列⼀样的
⼆进制为 0111 1110    的⼗进制为126 相信谁都会计算,BigInteger也是如此的
尤其是对于BigInteger字符串参数的构造形式
千万不要以为就是把字符的编码或者字符转换成数字切段存放到int数组中
他存放的都是转换后的真值
下⾯会详细介绍
使⽤字节数组构造
内部是Int数组,⼀个int 32位就是 4个字节,所以⾃然是可以使⽤字节对BigInteger进⾏构造的
提供了两种形式的字节构造⽅法,可以指定符号的
使⽤字节进⾏构造,就是把所有的字节填充到int数组中
不过要注意的是,
计算机中存储的数值都是补码的形式
正数的补码与原码相同
负数的补码是他的原码取反再加⼀
就是把这些字节的补码按照顺序拼在⼀起,组合成int数组
如果是⼀个负数,会先得到真值的绝对值
如果有前导零,还会去掉所有的前导零
⽽且,是⼤端排序,⼤端排序,⼤端排序的把最终的数据存储起来
也就是说int数组中保存的都是真值的绝对值,使⽤专门的符号位记录正负和0原码/反码/补码
先回顾下原码/反码/补码的概念
原码符号位+数值位
符号位为0 表⽰正数,符号位为1 表⽰负数
数值位就是真值的绝对值
⼜被称为带符号的绝对值表⽰
反码
正数的反码为其原码
负数的反码为其原码的除符号位外,逐位取反
补码
正数的补码为其原码
负数的补码为其反码+1
补码计算步骤
第⼀步求原码: 先写出来她的原码--->符号位+数值位(绝对值)
第⼆步求反码:
如果是正数反码与原码⼀样
如果是负数反码为原码取反(除符号位外,逐位翻转)
第三步求补码:
如果是正数补码与原码⼀样
如果是负数补码为反码 + 1
第四步扩充:
如果不⾜数据类型的宽度,将需要填充到指定宽度
符号位扩充,也就是正数补0  负数补1
总结
不管什么形式,第⼀位始终都是符号位,0 表⽰正数, 1表⽰负数
正数原码/反码/补码全都⼀样,知道⼀种就直接得到另外的形式
负数如果知道补码,想要得到他的原码,只需要对补码再⼀次的求补码即可⽰例1
⽰例2
通过这两个例⼦应该可以看得出来,数值都是补码形式存放
字节存储的也是补码, int存储的也是补码,
所以使⽤字节构造就是把所有的补码拼凑在⼀起就好了
拼凑排列好的补码,如果是正数,那么原码/反码/补码全都⼀样,存储的就是这个值
如果是负数,还需要取他的绝对值,绝对值就是再求⼀次补码,去掉符号位就是绝对值了
BigInteger数组中,存储的都是真值的绝对值的补码,真值绝对值得补码,其实就是原码去掉符号位嘛,⼀个意思就像上⾯的第⼆个例⼦得到的补码为:
1000  0011  1111 0111  0000  0000  0101 1001
实际存储的是:
0111  1100  0000 1000  1111  1111 1010  0111
使⽤String构造
String作为参数的构造⽅法有两种形式
本质上只是⼀种,那就是指定基数的字符串转换为BigInteger
简化形式就是默认⼗进制的形式
通过String构造BigInteger的逻辑⽐较简单,但是实现看起来会有些令⼈模糊
接下来我们先介绍⼀点相关的计算基础
算法基础
int能够⽀撑的数据长度以及基数
我们知道,存储实际数据的是int数组
int表⽰范围是:
-231 ~ 231-1    也就是  -2147483648 ~ 2147483647
对于⼗进制
可以表⽰10位⼗进制数字
但是 2147483648 (2147483647+1)  仍旧是10位数字却溢出了
所以选择保存9位⼗进制数
所以每个int  ⼗进制下最⼤值为10的9次⽅
对于⼆进制
最⼤值 231-1 ,所以只能保存30位 2进制数
所以每个int  ⼆进制下最⼤值为2的30次⽅
对于三进制
字符串长度1是什么意思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 ⼀样的道理
下⾯还会继续说明
同理它内部也有两个针对Long 的数组,⽤于内部计算使⽤
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数组的长度
以上是String构造BigInteger的⽤到的⼀些基本概念
我们以⼀个最简单的例⼦进⾏演⽰:
计算字符串 "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的构造就是类似这样的⼀个过程

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。