BigInteger类实例的构造过程——JDK源码解析

学校1022: 进制转换问题 Description   大家都知道,计算机中是以二进制存储的!但是在现实生活中,我们遇到过各种各样的进制情况,我们接触得最多的就是十进制,不过,生活中还存在各种进制计数的情况。例如:一个星期七天是7进制、一年十二个月,是12进制等等。小明最近在学c语言,熟悉了c语言中的各种进制转换问题,所以就尝试着各种进制转换的程序,现在他想写一个程序,把一个无符号数n,转化成在b进制下的表示。例如:n为1 阅读详情

  最近看了下JDK1.6版本的BigInteger类,仔细研究了下大整数实例的构造过程,现在把自己的所得所想分享给大家.    

        首先,为什么需要大整数类?简单的说就是因为内部的数据类型能表示的最大数是64位长度,当需要更大长度位数的数据时,基本的数据类型无法处理. 跟密码学相关的加密算法常涉及到好几百位的整数的加减乘除,因此需要设计一种有效的数据结构能够满足这样的需求.

        其实要实现大整数类也不难,简单一想,我们可以把一个很大很长的数分成多个短小的数,然后保存在一个数组中,大数之间的四则运算及其它运算都是通过数组完成.JDK就是这么实现的.JDK的BigInteger类里用一个int数组来保存数据:

[java]  view plain  copy
  1. /** 
  2.      * The magnitude of this BigInteger, in <i>big-endian</i> order: the 
  3.      * zeroth element of this array is the most-significant int of the 
  4.      * magnitude.  The magnitude must be "minimal" in that the most-significant 
  5.      * int (<tt>mag[0]</tt>) must be non-zero.  This is necessary to 
  6.      * ensure that there is exactly one representation for each BigInteger 
  7.      * value.  Note that this implies that the BigInteger zero has a 
  8.      * zero-length mag array. 
  9.      */  
  10.     int[] mag;  

该int数组不会以'0'元素开头.同时该类还有一个属性来表示该数的正负.

[java]  view plain  copy
  1. /** 
  2.      * The signum of this BigInteger: -1 for negative, 0 for zero, or 
  3.      * 1 for positive.  Note that the BigInteger zero <i>must</i> have 
  4.      * a signum of 0.  This is necessary to ensures that there is exactly one 
  5.      * representation for each BigInteger value. 
  6.      * 
  7.      * @serial 
  8.      */  
  9.     int signum;  

1代表该数为正,0代表该数是0,-1代表该数是负数.

而本文重点分析的构造函数如下:

[java]  view plain  copy
  1. /** 
  2.      * Translates the String representation of a BigInteger in the specified 
  3.      * radix into a BigInteger.  The String representation consists of an 
  4.      * optional minus sign followed by a sequence of one or more digits in the 
  5.      * specified radix.  The character-to-digit mapping is provided by 
  6.      * <tt>Character.digit</tt>.  The String may not contain any extraneous 
  7.      * characters (whitespace, for example). 
  8.      * 
  9.      * @param val String representation of BigInteger. 
  10.      * @param radix radix to be used in interpreting <tt>val</tt>. 
  11.      * @throws NumberFormatException <tt>val</tt> is not a valid representation 
  12.      *         of a BigInteger in the specified radix, or <tt>radix</tt> is 
  13.      *         outside the range from {@link Character#MIN_RADIX} to 
  14.      *         {@link Character#MAX_RADIX}, inclusive. 
  15.      * @see    Character#digit 
  16.      */  
  17.     public BigInteger(String val, int radix) {  

        该构造函数就是把一个字符串val所代表的的大整数转换并保存mag数组中,并且val所代表的字符串可以是不同的进制(radix决定).

        分析该构造函数源码之前,先想一个问题,构造一个大整数开始最主要的问题是如何把一个大数保存到mag数组中,通常我们自己实现的话很有可能是数组每块存一位数(假设大数为10进制),但这样的话想想也知道太浪费空间,因为一个int值可以保存远不止一位十进制数.

        Java语言里每个int值大小范围是-2^31至2^31-1 即-2147483648~2147483647,因此一个int值最多可保存一个10位十进制的整数,但是为了防止超出范围(2222222222这样的数int已经无法存储),保险的方式就是每个int保存9位的十进制整数.JDK里的mag数组即是这样的保存方式.因此若一串数为:18927348347389543834934878.

        划分之后就为:18927348  |  347389543  |  834934878. mag[0]保存18927348 ,mag[1]保存347389543 ,mag[2]保存834934878. 这样划分可以最大利用每一个int值,使得mag数组占用更小的空间.当然这只是第一步.

        划分的问题还没有说完,上述构造函数能够支持不同进制的数,最终转换到mag数组里面的数都是十进制,那么不同进制的大数,每次选择划分的位数就不相同,若是2进制,每次就可以选择30位来存储到一个int数中(int值大小范围是-2^31至2^31-1),若是3进制3^19<2147483647<3^20,因此每次就可以选择19位来存储到一个int数中,对于不同进制每次选择的位数不同,因此需要有一个数组来保存不同进制应当选择的位数,于是就有:

[java]  view plain  copy
  1. private static int digitsPerInt[] = {0, 0, 30, 19, 15, 13, 11,  
  2.        11, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6,  
  3.        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5};  

该数组保存了java支持的最大至最小进制所对应的每次划分的位数.

该构造方法里还包含了一个相关的数组bitsPerDigit,该数组用于计算初始化mag数组的大小.

[java]  view plain  copy
  1. // bitsPerDigit in the given radix times 1024  
  2.    // Rounded up to avoid underallocation.  
  3.    private static long bitsPerDigit[] = { 0, 0,  
  4.        1024, 1624, 2048, 2378, 2648, 2875, 3072, 3247, 3402, 3543, 3672,  
  5.        3790, 3899, 4001, 4096, 4186, 4271, 4350, 4426, 4498, 4567, 4633,  
  6.        4696, 4756, 4814, 4870, 4923, 4975, 5025, 5074, 5120, 5166, 5210,  
  7.                                           5253, 5295};  

        自己从网上看资料琢磨了半天才搞懂,现摘用网上的一段话来解释该数组的含义:

     “bitsPerDigit是用于计算radix进制m个有效数字  转换成2进制所需bit位[假设所需x位],我们来看一个计算式:radix^m - 1 = 2^x - 1, 解这个方程得 x = m * log2(radix) , 现在m是几位有效数字,常量就只有 log2(radix),这是一个小数,这不是我们喜欢的,所以我们希望用一个整数来表示,于是我们把他扩大1024倍然后取整,例如3进制 bitsPerDigit[3] = 1624(我用计算器算了一下 x = log2(3) * 1024 ~= 1623.xxx) ,我们队这个数取整,为什么取1624呢,其实只要不超过太多都可以的,你可以设置为1620,1600,1610...;”

        也就是说对于一串数(N进制),其转换成二进制的位数再乘以1024就是bitsPerDigit数组里面对应的数据,乘以1024再取整可能让人看着舒服吧.

        有了以上的介绍之后,我们现在可以贴上该方法的源代码仔细看看.

[java]  view plain  copy
  1. public BigInteger(String val, int radix) {  
  2.           
  3.         int cursor = 0, numDigits;  
  4.         int len = val.length();//获取字符串的长度  
  5.   
  6.         //不符合条件的情况  
  7.         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)  
  8.             throw new NumberFormatException("Radix out of range");  
  9.         if (val.length() == 0)  
  10.             throw new NumberFormatException("Zero length BigInteger");  
  11.         //判断正负,处理掉字符串里面的"-"  
  12.         signum = 1;  
  13.         int index = val.lastIndexOf("-");  
  14.         if (index != -1) {  
  15.             if (index == 0) {  
  16.                 if (val.length() == 1)  
  17.                     throw new NumberFormatException("Zero length BigInteger");  
  18.                 signum = -1;  
  19.                 cursor = 1;  
  20.             } else {  
  21.                 throw new NumberFormatException("Illegal embedded minus sign");  
  22.             }  
  23.         }  
  24.         //跳过前面的0  
  25.         while (cursor < len &&  
  26.                 Character.digit(val.charAt(cursor),radix) == 0)  
  27.         cursor++;  
  28.         if (cursor == len) {//若字符串里全是0,则存储为ZERO.mag  
  29.             signum = 0;  
  30.             mag = ZERO.mag;  
  31.             return;  
  32.         } else {//numDigits为实际的有效数字  
  33.             numDigits = len - cursor;  
  34.         }  
  35.         //numDigits位的radix进制数转换为2进制需要多少位  
  36.         //bitsPerDigit数组里面的元素乘了1024这里就需要右移10位(相当于除以1024),做除法的时候会有  
  37.         //小数的丢失,因此加1确保位数一定够  
  38.         //一个int有32bit,因此除以32即是我们开始估算的mag数组的大小  
  39.         int numBits = (int)(((numDigits * bitsPerDigit[radix]) >>> 10) + 1);  
  40.         int numWords = (numBits + 31) /32;  
  41.         mag = new int[numWords];  
  42.         //开始按照digitsPerInt截取字符串里的数  
  43.         //将不够digitsPerInt[radix]的先取出来转换  
  44.         int firstGroupLen = numDigits % digitsPerInt[radix];  
  45.         if (firstGroupLen == 0)  
  46.             firstGroupLen = digitsPerInt[radix];  
  47.         //把第一段的数字放入mag数组的最后一位  
  48.         String group = val.substring(cursor, cursor += firstGroupLen);  
  49.             mag[mag.length - 1] = Integer.parseInt(group, radix);  
  50.         if (mag[mag.length - 1] < 0)  
  51.             throw new NumberFormatException("Illegal digit");  
  52.         //剩下的一段段转换  
  53.         int superRadix = intRadix[radix];  
  54.         int groupVal = 0;  
  55.         while (cursor < val.length()) {  
  56.             group = val.substring(cursor, cursor += digitsPerInt[radix]);  
  57.             groupVal = Integer.parseInt(group, radix);  
  58.             if (groupVal < 0)  
  59.             throw new NumberFormatException("Illegal digit");  
  60.                 destructiveMulAdd(mag, superRadix, groupVal);  
  61.         }  
  62.         mag = trustedStripLeadingZeroInts(mag);  
  63.           
  64.     }  

        现在我对最后的几行还没有分析,是因为有一个intRadix数组我们还没有解释.intRadix数组其实就是一个保存了对应各种radix的最佳进制的表, 上面我们说过了对于十进制我们选择一次性截取9位数,这样能充分利用一个int变量同时还可保证不超出int的范围,因此intRadix[10]=10^9=1000000000. intRadix[3]=3^19=1162261467. 也就是每次截取的数都不会超过其radix对应的最佳进制.举例 十进制数18927348347389543834934878 其最终转换为:

        18927348*(10^9)^2 +347389543*(10^9)+834934878,最终从整体上来看mag数组保存的是一个10^9进制的数.

         intRadix如下:

[java]  view plain  copy
  1. private static int intRadix[] = {0, 0,  
  2.         0x40000000, 0x4546b3db, 0x40000000, 0x48c27395, 0x159fd800,  
  3.         0x75db9c97, 0x40000000, 0x17179149, 0x3b9aca00, 0xcc6db61,  
  4.         0x19a10000, 0x309f1021, 0x57f6c100, 0xa2f1b6f,  0x10000000,  
  5.         0x18754571, 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,  
  6.         0x6c20a40,  0x8d2d931,  0xb640000,  0xe8d4a51,  0x1269ae40,  
  7.         0x17179149, 0x1cb91000, 0x23744899, 0x2b73a840, 0x34e63b41,  
  8.         0x40000000, 0x4cfa3cc1, 0x5c13d840, 0x6d91b519, 0x39aa400  
  9.     };  

        intRadix[10]=0x3b9aca00 = 1000000000; intRadix[3]=0x4546b3db=1162261467;       

        我们注意到 numWords = (numBits + 31) /32. 初始数组的大小并不是大整数划分的数目而是将计算大整数对应的二进制位数(加上31确保numWords大于0)然后除以32得到,因此mag数组中每一个int数的32位是被完全利用的,也就是把每个int数当成无符号数来看待.若不完全利用int的32位的话,我们完全可以根据划分的结果来确定mag数组的初始大小,之前的例子:18927348 | 347389543 | 834934878,我们知道10进制数每次选择9位不会越界,我们可以直观的得到mag数组的大小为3,但是这样的话每个int元素仍然有些空闲的位没有利用.

       因此我们之前的划分方法只是整个数组初始化的想象中第一步. 这个例子按照numWords = (numBits + 31) /32这样计算最后得到的应当仍是3.但是若是再大一些的数串结果就不一定一样,积少成多,很大的数串时节省的空间就能体现出来啦.

       Java没有无符号int数,因此mag数组中常常会符号为负的元素. 而最终把原大整数转换为mag数组保存的radix对应的最佳进制数的过程由destructiveMulAdd完成.现在把构造函数的最后一部分的和方法destructiveMulAdd的解析附上:

[java]  view plain  copy
  1. int superRadix = intRadix[radix];  
  2.         int groupVal = 0;  
  3.         while (cursor < val.length()) {  
  4.             //选取新的一串数  
  5.             group = val.substring(cursor, cursor += digitsPerInt[radix]);  
  6.             groupVal = Integer.parseInt(group, radix);//转换为十进制整数  
  7.             if (groupVal < 0)  
  8.             throw new NumberFormatException("Illegal digit");  
  9.             //mag*superRadix+groupVal.类似于:18927348*10^9+347389543  
  10.                 destructiveMulAdd(mag, superRadix, groupVal);  
  11.         }  
  12.         //去掉mag数组前面的0,使得数组元素以非0开始.  
  13.         mag = trustedStripLeadingZeroInts(mag);  
  14.   
  15.    private final static long LONG_MASK = 0xffffffffL;  
  16.     // Multiply x array times word y in place, and add word z  
  17.     private static void destructiveMulAdd(int[] x, int y, int z) {  
  18.         // Perform the multiplication word by word  
  19.         //将y与z转换为long类型  
  20.         long ylong = y & LONG_MASK;  
  21.         long zlong = z & LONG_MASK;  
  22.         int len = x.length;  
  23.   
  24.         long product = 0;  
  25.         long carry = 0;  
  26.         //从低位到高位分别与y相乘,每次都加上之前的进位,和传统乘法一模一样.  
  27.         for (int i = len-1; i >= 0; i--) {  
  28.             //每次相乘时将x[i]转换为long,这样其32位数就可转变为其真正代表的数  
  29.             product = ylong * (x[i] & LONG_MASK) + carry;  
  30.             //x[i]取乘积的低32位.  
  31.             x[i] = (int)product;  
  32.             //高32位为进位数,留到下次循环相加  
  33.             carry = product >>> 32;  
  34.         }  
  35.   
  36.         // Perform the addition  
  37.         //执行加z  
  38.         //mag最低位转换为long后与z相加  
  39.         long sum = (x[len-1] & LONG_MASK) + zlong;  
  40.         //mag最低位保留相加结果的低32位.  
  41.         x[len-1] = (int)sum;  
  42.         //高32位当成进位数  
  43.         carry = sum >>> 32;  
  44.         //和传统加法一样进位数不断向高位加  
  45.         for (int i = len-2; i >= 0; i--) {  
  46.             sum = (x[i] & LONG_MASK) + carry;  
  47.             x[i] = (int)sum;  
  48.             carry = sum >>> 32;  
  49.         }  
  50.     }  

        整个过程下来,因为保存的方法和我们脑海中那简单的存储方法会有不同,最终mag数组里的元素跟原先的字符串就会有很大的不同,但实质上还是表示着相同的数,现把18927348347389543834934878 例子的构造过程展示出:

        初始化之后计算得numBits=87,这样数组初始化大小numWords=3.
        进入最终的循环前mag数组:[0]  [0]  [18927348]
        第一次循环后: [0]   [4406866]   [-1295432089] (18927348*10^9+347389543)
        第二次循环后: [1026053]   [-1675546271]   [440884830]. ((18927348*10^9+347389543)*10^9+834934878)
        最终我们就把18927348347389543834934878 转换成10^9进制的数保存到了mag数组中.虽然最终的结果我们让我们不太熟悉,但是其中数串划分的方法和数组节省空间的思想都是值得学习的.(感觉总结地好没有水平......)

       现在有最后一个问题,如何mag数组转换为原来的数串呢?JDK里面是通过不断做除法取余实现的,BigInteger类的实例在调用toString方法的时候会返回原先的数串.代码如下:

[java]  view plain  copy
  1. public String toString(int radix) {  
  2.     if (signum == 0)  
  3.         return "0";  
  4.     if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)  
  5.         radix = 10;  
  6.   
  7.     // Compute upper bound on number of digit groups and allocate space  
[java]  view plain  copy
  1.        //初始化字符串数组的大小,为mag数组长度一半多点.  
  2. int maxNumDigitGroups = (4*mag.length + 6)/7;  
  3. String digitGroup[] = new String[maxNumDigitGroups];  
  4.          
  5. // Translate number to string, a digit group at a time  
  6. BigInteger tmp = this.abs();  
  7. int numGroups = 0;  
  8. while (tmp.signum != 0) {  
  9.            BigInteger d = longRadix[radix];  
  10.   
  11.            MutableBigInteger q = new MutableBigInteger(),  
  12.                              r = new MutableBigInteger(),  
  13.                              a = new MutableBigInteger(tmp.mag),  
  14.                              b = new MutableBigInteger(d.mag);  
[java]  view plain  copy
  1. //a除以b商保存在q中,余数保存在r中  
  2.    a.divide(b, q, r);  
  3.    BigInteger q2 = new BigInteger(q, tmp.signum * d.signum);  
  4.    BigInteger r2 = new BigInteger(r, tmp.signum * d.signum);  
  5. //把余数转换为字符串保存在字符串数组中  
  6.    digitGroup[numGroups++] = Long.toString(r2.longValue(), radix);  
  7. //商作为被除数  
[java]  view plain  copy
  1. <span style="WHITE-SPACE: pre"> </span>    tmp = q2;  
  2.     }  
  3.      //用StringBuilder把字符串里面的数串拼接起来,中间段的数串可能需要添加一些0  
  4.     // Put sign (if any) and first digit group into result buffer  
  5.     StringBuilder buf = new StringBuilder(numGroups*digitsPerLong[radix]+1);  
  6.     if (signum<0)  
  7.         buf.append('-');  
  8.     buf.append(digitGroup[numGroups-1]);  
  9.   
  10.     // Append remaining digit groups padded with leading zeros  
  11.     for (int i=numGroups-2; i>=0; i--) {  
  12.         // Prepend (any) leading zeros for this digit group  
  13.         int numLeadingZeros = digitsPerLong[radix]-digitGroup[i].length();  
  14.         if (numLeadingZeros != 0)  
  15.         buf.append(zeros[numLeadingZeros]);  
  16.         buf.append(digitGroup[i]);  
  17.     }  
  18.     return buf.toString();  
  19.     }  
  20.   
  21.     /* zero[i] is a string of i consecutive zeros. */  
  22.     private static String zeros[] = new String[64];  
  23.     static {  
  24.     zeros[63] =  
  25.         "000000000000000000000000000000000000000000000000000000000000000";  
  26.     for (int i=0; i<63; i++)  
  27.         zeros[i] = zeros[63].substring(0, i);  
  28.     }  

        上述方法核心的地方就是 a.divide(b, q, r). longRadix数组和intRadix数组有着相似的涵义.

       intRadix[10]=10^9.因此longRadix[10]=10^18,相当于对intRadix进行了平方,也就是对long类型来说的最佳进制数.

       简单的想一下可以明白:mag数组若是不断除以10^9可以得到834934878,347389543,18927348最终可获得原先字符串.若是除以10^18(Java支持该数量级的运算),两次分别得到:34738954318927348,834934878,因此使用longRadix数组运算的效率更高.
对于上述方法出现的类MutableBigInteger,借用网上的一段话解释可能比我说的更好些: 

       "MutableBigInteger是BigInteger类的另一个版本,它的特点是不创建临时对象的前提上使调用程序得到象BigInteger类型的返回值(称为可变对象技术)。因为大整数的除法是由大量的其他算术操作组成的,所以需要大量的临时对象,而完成大量的操作而不创建新的对象可以极大地改善程序的性能,(因为创建对象的代价是很高的)所以在Java的大整数类中使用MutableBigInteger类中的方法来执行大整数除法。" 

       而最为关键的divide方法不好意思啊我看了好久仍然是没有弄懂代码的思路,希望大家能够指点迷津!

       JDK的BigInteger类中还实现了好多方法都值得我们一看,除了基本的四则元素外,里面还提供了判断素数的方法,求幂,求模,求逆元,求最大公约数,用到了Miller-Rabin算法,滑动窗口算法快速求幂(我看了看好像是),欧几里得算法,中国剩余定理等,3000多行的代码....若有兴趣的话仔细看看其中某个方法对我们可能会有启发.

       大家有不同意的地方希望能指出,多多交流,还有最好能帮我把遗留的divide方法给解释一下,我看了好久快看恶心了,大神在哪里!!!!

Burpsuit注册机使用时报错java.math.MutableBigInteger.inverseMod64(J)J-附件资源 立即下载

相关推荐

Cadence导入tsmcN65GP PDK的完整流程与常见问题解析

本文详细介绍了Cadence导入tsmcN65GP PDK的完整流程,包括文件解压、目录结构解析、安装脚本运行及Cadence集成配置。重点解析了常见问题如文件路径错误、权限问题和工艺库显示不全的解决方案,并提供了实战技巧与优化建议,帮助用户高效完成PDK安装与配置。

weixin_29215391的博客 548

java biginteger 最大值_[十六]大数计算来啦~深入源码,手撕BigInteger计算过程!

点击上方“布衣码农”,免费订阅~选择“设为星标”,第一时间免费获得更新~「布衣码农」一步一步教你BigInteger内部计算模式。BigInteger和BigDecimal都是Java针对大数提供的类超出了java的表示范围属性简介借助于signum和mag来实现数据的符号位和实际数据的保存final intsignum 保存BigInteger的符号负数-100正数1f...

weixin_39819327的博客 2598

STM32单片机远程升级

stm32远程升级

fang_yang_wa的博客 1万+

java mutable_java.math.MutableBigInteger的目的是什么?

/*** A class used to represent multiprecision integers that makes efficient* use of allocated space by allowing a number to occupy only part of* an array so that the arrays do not have to be reallocat...

weixin_42175776的博客 508

SSD盘符漂移导致OSD down场景模拟与恢复

运维团队反馈一个问题,现象是:某个OSD对应的cache分区发生了变化,比如原来cache使用的分区是/dev/sde,后来还是这块盘,但分区信息不知何故,变成了/dev/sdf(产品OSD设备并不是根据分区名称来map,而是根据partlabel),最终的现象是这个OSD down了,没法启动.接到这个现象的反馈后,记录一下这个问题在lab的复现方法。

Gavin Blog 943

Pluto SDR新手避坑指南:从环境配置到第一个MATLAB收发程序(附完整代码)

本文为Pluto SDR新手提供全面的避坑指南,从硬件连接到MATLAB环境配置,再到第一个信号收发程序的实现。详细介绍了驱动安装、常见问题排查以及关键参数设置,帮助用户快速上手软件定义无线电(SDR)技术,并附有完整代码示例。

weixin_33168937的博客 325

Java篇 - 最全BigInteger和BigDecimal实战

最近公司在做一款区块链钱包,区块链上传输的数值都是很大的,大到几十位。用Java的基本类型是处理不了的,int占32位,long、double占64位,如果用这些基本数据类型运算的话,第一是存储不了这么大的数,第二会出现精度丢失以及科学计数法等问题。 一般处理商业计算,如钱包,交易所等业务,都离不开这两个类。   目录: BigInteger BigDecimal 实战演练   ...

u014294681的博客 1832

手把手教你用scRNA-seq和scTCR-seq分析CD8⁺ T细胞在免疫治疗中的动态变化

本文详细介绍了如何整合单细胞RNA测序(scRNA-seq)与单细胞TCR测序(scTCR-seq)技术,深入解析CD8⁺ T细胞在癌症免疫治疗中的动态变化。通过从数据预处理、细胞亚群鉴定到TCR克隆追踪的完整分析流程,揭示了T细胞的功能状态转变与克隆演化规律,为理解免疫应答机制和开发精准治疗策略提供了关键方法学指导。

p8q9r0的博客 570

[源码解析]BigInteger

本篇文章是我解析Java-API的笔记,更多的是从方法着手,少对类的整体情况进行说明,故并不详尽,可供大家参考。 如果文中阐述不全或不对的,多多交流。

进步*于辰的博客 1万+

docker安装fastdfs+nginx配置

docker安装fastdfs+nginx,实现图片或文件的上传与下载

weixin_47325126的博客 2193

【国产化信创实践】宝兰德bes中间件集成springboot

【国产化信创实践】宝兰德bes中间件集成springboot

项目管理、软件工厂、vue研发、Java研发、中国文化等。 1万+

biginteger 原理_java BigInteger源码学习

在java中,有很多基本数据类型我们可以直接使用,比如用于表示浮点型的float、double,用于表示字符型的char,用于表示整型的int、short、long等。但是,拿整数来说,如果我们想要表示一个非常大的整数,比如说超过64位,那么能表示数字最大的long也无法存取这样的数字时,我们怎么办。以前的做法是把数字存在字符串中,大数之间的四则运算及其它运算都是通过数组完成。JDK也有类似的实现...

weixin_36296215的博客 982

YOLOv11改进策略【损失函数篇】| Shape-IoU:考虑边界框形状和尺度的更精确度量

本文记录的是改进YOLOv11的损失函数,将其替换成Shape-IoU。现有边界框回归方法通常考虑与之间的几何关系,通过边界框的相对位置和形状计算损失,但忽略了边界框本身的形状和尺度等固有属性对边界框回归的影响。为了弥补现有研究的不足,Shape-IoU提出了一种关注边界框本身形状和尺度的边界框回归方法。

Limiiiing的博客 4598

BigInteger的加减操作

大数加减法的时间复杂度都为O(max(n, m)), 这里n和 m分别是两个加数的mag数组的长度, 进一步可以推出时间复杂度为O(max(nn, mm) / 32), 这里的nn和mm分别是两个加数的二进制位的多少。大数加减法的时间复杂度都为O(max(n, m)), 这里n和 m分别是两个加数的mag数组的长度, 进一步可以推出时间复杂度为O(max(nn, mm) / 32), 这里的nn和mm分别是两个加数的二进制位的多少。

moli138的博客 1447

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

从底层重学 Java 之 BigInteger 大整数 Gitchat连接

Gitchat连接 https://gitbook.cn/gitchat/activity/5f395a80aced402379f6a0ca 简介 从底层,从原理,我们来重学一次 Java。BigInteger 是大整数计算类,是BigDecimal用于存储大数属性的类型,BigDecimal中很多计算就是基于BigInteger的函数进行计算的,采用了多种优化的算法实现,他的源码及实现是怎样的呢? 本系列秉承所有结论尽量从源码中来,没有源码的尽量标明出处。相关源码会附着在文章中,读本文即可,不用再自行查找

草宝虫的博客 797

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Java大数源码剖析(一) - BigInteger的底层数据结构

Java大数源码剖析(一) - BigInteger的底层数据结构 本系列文章对Java大数类源码进行剖析, Java大数类包括java.math.BigInteger和java.math.BigDecimal, 本人使用的JDK版本为13.0.2 本系列文章按照以下顺序 : BigInteger的介绍和底层数据结构 (一篇文章) 依次剖析BigInteger各个常用方法的源码实现(从简到难) (若干篇文章) 讲解BigDecimal的的介绍和底层数据结构 (一篇文章) 依次剖析BigInteger各个

PGZXB的博客 1347

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

java BigInteger类的原理

转载自:https://blog.youkuaiyun.com/gjb724332682/article/details/51488765/ JDK对BigInteger类的介绍: Immutable arbitrary-precision integers. All operations behave as if BigIntegers were represented in two's-compleme...

qq_27430551的博客 1596

Java大数源码剖析(二) - BigInteger的加减操作

这是Java大数源码剖析系列的第二篇文章, 上一篇文章是 Java大数源码剖析(一) - BigInteger的底层数据结构 BigInteger提供的加减操作 加法 : public BigInteger add(BigInteger val), 将返回本身加上val的结果 减法 : public BigInteger subtract(BigInteger val), 返回本身减去val的结果 使用示例 public class Test { public static void main(

PGZXB的博客 2068

Java 7 源码学习系列(三)——BigInteger

http://www.hollischuang.com/archives/176 在java中,有很多基本数据类型我们可以直接使用,比如用于表示浮点型的float、double,用于表示字符型的char,用于表示整型的int、short、long等。但是,拿整数来说,如果我们想要表示一个非常大的整数,比如说超过64位,那么能表示数字最大的long也无法存取这样的数字时,我们怎么办。以

hold on 4744

BigInteger精讲

BigInteger初识 在java的整数类型里面,byte为8位,short为16位,int为32位,long为64位。 正因为这些数值的二进制位数已经固定,所以它们能表示的数值大小就有一定的范围限制。 如果想表示比这些数值更大的数,怎么办呢?可以使用BigInteger来帮忙. BigInteger用多少位二进制表示呢?其实,在BigInteger里面使用int数组来存储实现的. 为...

只有变秃 才能变强 4797

BigDecimal 和 BigInteger 介绍

一、BigDecimal   熟悉浮点记数的朋友知道,用二进制表示十进制小数是存在误差的,在涉及到金钱等其他对小数精度要求高的场景下Java提供了BigDecimal类,以满足需要。   先看构造函数:  public static void main(String[] args) { BigDecimal aNum = new BigDecimal(...

TZJ0709的博客 184

java BigInteger源码学习

转载自http://www.hollischuang.com/archives/176 在java中,有很多基本数据类型我们可以直接使用,比如用于表示浮点型的float、double,用于表示字符型的char,用于表示整型的int、short、long等。但是,拿整数来说,如果我们想要表示一个非常大的整数,比如说超过64位,那么能表示数字最大的long也无法存取这样的数字时,我们怎...

weixin_30849591的博客 288

JDK8 BigDecimal API-创建BigDecimal源码浅析三

第三篇 先介绍以BigInteger为构造参数的构造器 1 public BigDecimal(BigInteger val) {// 根据BigInteger创建BigDecimal对象 2 scale = 0;// BigInteger为整数因此有效小数位数为0 3 intVal = val; 4 intCom...

weixin_34375054的博客 222

JDK源码解析基础篇-8种基本数据类型的包装类及相关讨论

这是源码解析系列的第二篇,依然来学习java.lang包下常用的类–8种基本数据类型对应的包装类。将从概念到源码进行学习,并对其缓存、自动拆装箱的语法糖等注意点进行分析。 在开始之前,今天看到一个有趣问题:Java到底是纯面向对象语言吗?有人认为是,有人认为不是。认为不是的因为:(1)类的static修饰的静态内容(变量和方法)不属于任何对象,所以这是非对象的东西;(2)所有的8种基本数据类型都不

怕什么真理无穷, 进一寸有一寸的欢喜 929

BigInteger如何存储大数据的,存储的范围是什么

首先我写贴一个BigInteger的构造函数 这也就是说,我们在使用这个类的时候,若直接定义BigInteger类型,挺麻烦,需要先转换串在转换其他格式。 他们之间的关系是这样的 BigInteger ←→ String ←→ int 例如: import java.math.BigInteger; public class Test { public static void main(String[] args) { BigInteger a = new BigInteger("5");

weixin_44035979的博客 1745
上一篇: BigInteger的源代码
下一篇: final修饰的变量是引用不能改变还是引用的对象不能改变
ole_triangle_java
博客等级 码龄10年 82粉丝 83原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值