我需要找到2个幂幂N,其中N是一个非常大的数字(Java BigInteger类型)
Java BigInteger类具有pow方法,但仅将整数值作为指数。
因此,我编写了如下方法:
static BigInteger twoToThePower(BigInteger n)
{
BigInteger result = BigInteger.valueOf(1L);
while (n.compareTo(BigInteger.valueOf((long) Integer.MAX_VALUE)) > 0)
{
result = result.shiftLeft(Integer.MAX_VALUE);
n = n.subtract(BigInteger.valueOf((long) Integer.MAX_VALUE));
}
long k = n.longValue();
result = result.shiftLeft((int) k);
return result;
}
我的代码运行良好,我只是在分享我的想法,并想知道是否还有其他更好的想法?
谢谢。
答案 0 :(得分:2)
您不能使用BigInteger存储计算结果。从javadoc中:
BigInteger必须支持-2 ^ Integer.MAX_VALUE(不包括)到+ 2 ^ Integer.MAX_VALUE(不包括)之间的值,并且可以支持该范围之外的值。
这是pow方法采用int的原因。在我的计算机上,BigInteger.ONE.shiftLeft(Integer.MAX_VALUE)抛出java.lang.ArithmeticException(消息为“ BigInteger会溢出支持的范围”)。
答案 1 :(得分:1)
通过重复平方,可以实现您的目标。我在下面的示例代码中发布了代码,以了解重复平方的逻辑。
static BigInteger pow(BigInteger base, BigInteger exponent) {
BigInteger result = BigInteger.ONE;
while (exponent.signum() > 0) {
if (exponent.testBit(0)) result = result.multiply(base);
base = base.multiply(base);
exponent = exponent.shiftRight(1);
}
return result;
}
答案 2 :(得分:1)
一个有趣的问题。只是为了向公认的答案中添加更多信息,检查BigInteger的openjdk 8源代码会发现这些位存储在数组final int[] mag;
中。由于数组最多可以包含Integer.MAX_VALUE
个元素,因此这立即对BigInteger的2 (32 * Integer.MAX_VALUE)的特定实现施加了理论上的限制。因此,即使您反复进行左移的方法也只能超过一个int的大小最多32倍。
那么,您准备好生成自己的BigInteger实现了吗?
答案 3 :(得分:1)
伊曼纽尔·隆卡(Emmanuel Lonca)的答案是正确的。但是,根据Manoj Banik的想法,我也想分享我的想法。
我的代码与Manoj Banik的代码做得更快。这个想法是初始化缓冲区,并将位1放入正确的位置。我在1个字节上使用了左移运算符,而不是shiftLeft
方法。
这是我的代码:
static BigInteger twoToThePower(BigInteger n){
BigInteger eight = BigInteger.valueOf(8);
BigInteger[] devideResult = n.divideAndRemainder(eight);
BigInteger bufferSize = devideResult[0].add(BigInteger.ONE);
int offset = devideResult[1].intValue();
byte[] buffer = new byte[bufferSize.intValueExact()];
buffer[0] = (byte)(1 << offset);
return new BigInteger(1,buffer);
}
但是它仍然比BigInteger.pow
然后,我发现类BigInteger
有一个名为setBit
的方法。它还像int
方法一样接受参数类型pow
。使用此方法比BigInteger.pow
快。
该代码可以是:
static BigInteger twoToThePower(BigInteger n){
return BigInteger.ZERO.setBit(n.intValueExact());
}
类BigInteger
也具有一种称为modPow
的方法。但是它还需要一个参数。这意味着您应指定modulus
,并且结果应小于此modulus
。我没有对modPow
进行性能测试,但我认为它应该比pow
方法慢。