BigInteger使用什么算法将整数转换为字节数组

时间:2018-01-26 16:02:18

标签: java algorithm biginteger

似乎Java有一种使用BigInteger.toByteArray()方法将Integer转换为byteArray的非常有效的方法,它在空间方面是最佳的。

因此,对于0-128范围内的整数,它只使用1个字节,对于2147483648 - 549755813888范围内的整数,它将使用5个字节。

他们用来实现这个的算法/想法是什么?

2 个答案:

答案 0 :(得分:1)

没有必要的真正算法。只需将8位块中的现有位复制到目标字节数组中即可。

内部表示(*见下文)是具有无限长度的二进制补码二进制(但仅存储重要的下部,而不是无限多的零或1)。并且在结果字节数组中使用相同的表示。

只有内部存储使用32位整数块,字节数组使用8位块。

(*)当然,兼容的BigInteger类可以使用他们喜欢的任何内部表示,但32位整数类非常合理。

回答OP的评论,我想更详细地解释一下BigInteger和字节数组之间的情况。

什么是Java int?

让我们从一个简单的int开始。它是一个32位实体,使用“二进制补码”编码范围为-2147483648到2147483647(-2 ^ 31到2 ^ 31-1)的整数。二进制和十六进制的一些例子:

-2147483648 is encoded as 1000 0000 0000 0000 0000 0000 0000 0000 or 0x80000000.
        -16 is encoded as 1111 1111 1111 1111 1111 1111 1111 0000 or 0xfffffff0.
         -2 is encoded as 1111 1111 1111 1111 1111 1111 1111 1110 or 0xfffffffe.
         -1 is encoded as 1111 1111 1111 1111 1111 1111 1111 1111 or 0xffffffff.
          0 is encoded as 0000 0000 0000 0000 0000 0000 0000 0000 or 0x00000000.
          1 is encoded as 0000 0000 0000 0000 0000 0000 0000 0001 or 0x00000001.
         16 is encoded as 0000 0000 0000 0000 0000 0000 0001 0000 or 0x00000010.
 2147483647 is encoded as 0111 1111 1111 1111 1111 1111 1111 1111 or 0x7fffffff.

请记住,一个十六进制数字代表4位:

0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
a 1010
b 1011
c 1100
d 1101
e 1110
f 1111

负数以1位开始,正数以0开始,如果数字较小,则以1位或0位开头。  原始类型(如short,int或long)的限制是它们只能表示某些给定的数字范围。

什么是BigInteger?

如果我们的数字代表有无限多的位可用,那么无论多大,我们都可以代表任何数字。这就是BigInteger模型,只有一个改进,我们不会重复大量的前导1或0位,而只是有趣的尾随部分。

BigInteger类(至少一个似是而非的实现)用整数数组表示数字,只保留位表示的有趣部分。一些例子(现在只使用十六进制,因为线宽有限......):

                   0 [0x00000000]
          2147483647 [0x7fffffff]
          2147483648 [0x00000000, 0x80000000]
          4294967296 [0x00000001, 0x00000000]
          8589934592 [0x00000002, 0x00000000]
     281474976710655 [0x0000ffff, 0xffffffff]
     281474976710656 [0x00010000, 0x00000000]
18446744073709551616 [0x00000001, 0x00000000, 0x00000000]
    -281474976710656 [0xffff0000, 0x00000000]

提取字节数组

创建字节数组只意味着每8位(= 2个十六进制数字)

分割整数

让我们从一个例子开始:

8589934592 [0x00 00 00 02, 0x00 00 00 00]
bytes:     [           02,   00,00,00,00]

所以,它是:

  • 知道前三个00字节可以省略。在我们的例子中,因为第一个整数以至少25位的0开始。
  • 将整数中的位复制到字节中。

如果没有前导零测试,字节数组将为8个字节长,每个整数只创建4个字节。

因此,创建字节数组的唯一“算法”部分是检查一些前导0位(如果是负数,则为1位)。

答案 1 :(得分:0)

该算法是多精度基数转换的标准技术:重复除以目标基数并在每次迭代时存储余数。

参见Knuth,D.E。,计算机程序设计的艺术,第二卷。