如何改进我的Java代码以生成所有已知的Perfect数字?

问题描述 投票:0回答:2

我正在尝试使用perfect numbers生成所有已知的Euclid–Euler theorem

我想知道我是否可以修改/重写我的代码来获得快速结果

这是我的代码:

   public static BigInteger[] genAllPerfect(int howMany)
   {
      int[] expn = { 2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203, 2281, 3217, 4253, 4423, 9689,
            9941, 11213, 19937, 21701, 23209, 44497, 86243, 110503, 132049, 216091, 756839, 859433, 1257787, 1398269,
            2976221, 3021377, 6972593, 13466917, 20996011, 24036583, 25964951, 30402457, 32582657, 37156667, 42643801,
            43112609, 57885161, 74207281, 77232917, 82589933 };

      BigInteger[] perfectNums = new BigInteger[51];
      BigInteger One = BigInteger.ONE;
      BigInteger Two = One.add(One);

      for (int i = 0; i < howMany; i++)
      {
         BigInteger firstPart = Two.pow(expn[i] - 1); // 2^(p-1)

         BigInteger secondPart = Two.pow(expn[i]); // 2^p

         secondPart = secondPart.subtract(One); // (2^p - 1)

         perfectNums[i] = firstPart.multiply(secondPart);
      }

      return perfectNums;
   }

此代码平均花费30秒。谢谢。

java algorithm performance biginteger perfect-numbers
2个回答
1
投票

您可以做的一项改进是预先计算所有2的幂,并将它们存储在数组中。同样,为所有2^p - 1创建一个数组。


1
投票

我重写了适合Java BigInteger类的公式以减少时间。

2^(p-1) * (2^p -1)

= (2^p)/2 * (2^p -1)

= ((2^p) * (2^p -1))/2

= (2^2p - 2^p)/2

因为2^n可以使用BigInteger setBit()方法快速计算。 setBit是最快的,因为它仅适用于单个位。

用以下代码替换for循环并检查结果。

for (int i = 0; i < howMany; i++)
      {
         BigInteger perfect1 = Zero.setBit(expn[i]); // 2^p

         perfectNums[i] = Zero.setBit(2 * expn[i]); // 2^(2*p)

         perfectNums[i] = perfectNums[i].subtract(perfect1); // 2^(2*p) - 2^p

         perfectNums[i] = perfectNums[i].shiftRight(1); // {2^(2*p) - 2^p}/2 = (2^(p-1))*(2^p- 1)
      }
© www.soinside.com 2019 - 2024. All rights reserved.