我有一个使用大整数(例如160位)的方案,并且我正在尝试创建可能在运行时用n
位数表示的最大可能无符号整数。在程序开始执行并从配置文件中读取值之前,不知道n的确切值。例如,n
可能是160,或128,或192,等等......
最初我的想法是:
BigInteger.valueOf((long)Math.pow(2, n));
然后我意识到,转换为long会发生这种情况有点失败的目的,因为long在第一时间不包含足够的位来存储结果。有什么建议吗?
答案 0 :(得分:9)
让我们先看看这个数字是什么,数学上。
在无符号二进制表示中,最大的 n 位数将所有位设置为1.让我们看一些例子:
1
(2)= 1 =
2 1 - 1
11
(2)= 3 =
2 2 - 1
111
(2)= 7 =
2 3 - 1
:
1………1
(2)=
2 n -1
名词
请注意,这也类似于十进制。最大的3位数字是:
10
3- 1 = 1000 - 1 = 999
因此,找到最大 n 位无符号数的子问题是计算2 n 。
由于以下模式,现代数字计算机可以有效地计算两个幂:
2 0
= 1
<子>(2)子>
2 1= 10
<子>(2)子>
2 2= 100
<子>(2)子>
2 3= 1000
<子>(2)子>
:
2 名词= 10………0
<子>(2)子>
名词
也就是说,2 n 只是将其位 n 设置为1的数字,其他所有设置为0(请记住位编号使用从零开始的索引编译。)
综上所述,我们使用BigInteger
为我们的问题找到了这个简单的解决方案:
final int N = 5;
BigInteger twoToN = BigInteger.ZERO.setBit(N);
BigInteger maxNbits = twoToN.subtract(BigInteger.ONE);
System.out.println(maxNbits); // 31
如果我们使用long
代替,那么我们可以这样写:
// for 64-bit signed long version, N < 64
System.out.println(
(1L << N) - 1
); // 31
没有为long
定义“设置位 n ”操作,因此传统上使用位移。实际上,这种移位技术的BigInteger
模拟也是可能的:
System.out.println(
BigInteger.ONE.shiftLeft(N).subtract(BigInteger.ONE)
); // 31
BigInteger
提示 BigInteger
确实有pow
方法来计算任意数字的非负幂。如果您使用模块化环,还有modPow
和modInverse
。
您可以单独setBit
,flipBit
或testBit
。您可以获得整体bitCount
,按位and
执行另一个BigInteger
和shiftLeft
/ shiftRight
等。
作为奖励,您还可以计算gcd
或检查数字isProbablePrime
。
始终请记住,BigInteger
与String
一样,不可变。您无法在实例上调用方法,并期望修改该实例。相反,始终将方法返回的结果分配给变量。
答案 1 :(得分:3)
只是为了澄清你想要最大 n位数(即,所有n位都设置)。如果是这样,以下内容将为您完成:
BigInteger largestNBitInteger = BigInteger.ZERO.setBit(n).subtract(BigInteger.ONE);
在数学上等效于2 ^ n - 1.您的问题是如何做2 ^ n实际上是最小的n + 1位数。你当然可以这样做:
BigInteger smallestNPlusOneBitInteger = BigInteger.ZERO.setBit(n);
答案 2 :(得分:2)
我认为BigInteger中直接有 pow 方法。您可以将它用于您的目的
答案 3 :(得分:0)
我能想到的最快捷的方法是使用BigInteger
的{{1}}构造函数。
byte[]
从字节数组构造BigInteger(byte[] val)
对象。但是,您正在处理位,因此为表示2 ^ 40 - 1的39位整数创建一个可能包含{127,255,255,255,255}的byte []可能有点乏味。
您还可以使用构造函数BigInteger
- 如果您不介意解析字符串的性能问题,那么您的代码中可能更容易发生什么。然后你可以生成一个像BigInteger(String val, int radix)
这样的字符串然后调用val = "111111111111111111111111111111111111111"
- 产生相同的39位整数。
第一个选项需要考虑如何表示您的号码。那个特定的构造函数需要一个二进制 - 赞美,big-endian表示的数字。第二个可能稍微慢一些,但更清晰。
编辑:更正的数字。我以为你的意思是代表2 ^ n,并没有正确读取n位可以存储的最大值。