如何改进我的 Java 代码以生成所有已知的完美数?
How can I improve my Java code to generate all known Perfect numbers?
我正在尝试使用 Euclid–Euler theorem
、
生成所有已知的 perfect numbers
我想知道我是否可以 modify/rewrite 我的代码 快速获得结果。
这是我的代码:
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 BigInteger class setBit() 方法以减少时间。
2^(p-1) * (2^p -1)
= (2^p)/2 * (2^p -1)
= ((2^p) * (2^p -1))/2
= (2^2p - 2^p)/2
= (2^(2p-1) - 2^(p-1))
因为 2^n
可以使用 BigInteger
setBit()
方法快速计算。 setBit
是最快的,因为它只使用一位。
这是完整的代码,需要大约 0.35 秒 我机器上的所有 51 个完全数。
public class PerfectNumbers
{
static BigInteger[] genAllPerfect(int howMany)
{
if (howMany > 51)
howMany = 51;
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 Zero = BigInteger.ZERO;
BigInteger[] perfectNums = new BigInteger[howMany];
for (int i = 0; i < howMany; i++)
{
BigInteger perfect1 = Zero.setBit(expn[i] - 1); // 2^(p-1)
perfectNums[i] = Zero.setBit(2 * expn[i] - 1); // 2^(2*p-1)
perfectNums[i] = perfectNums[i].subtract(perfect1); // 2^(2*p-1) - 2^(p-1)
}
return perfectNums;
}
我正在尝试使用 Euclid–Euler theorem
、
perfect numbers
我想知道我是否可以 modify/rewrite 我的代码 快速获得结果。
这是我的代码:
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 BigInteger class setBit() 方法以减少时间。
2^(p-1) * (2^p -1)
= (2^p)/2 * (2^p -1)
= ((2^p) * (2^p -1))/2
= (2^2p - 2^p)/2
= (2^(2p-1) - 2^(p-1))
因为 2^n
可以使用 BigInteger
setBit()
方法快速计算。 setBit
是最快的,因为它只使用一位。
这是完整的代码,需要大约 0.35 秒 我机器上的所有 51 个完全数。
public class PerfectNumbers
{
static BigInteger[] genAllPerfect(int howMany)
{
if (howMany > 51)
howMany = 51;
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 Zero = BigInteger.ZERO;
BigInteger[] perfectNums = new BigInteger[howMany];
for (int i = 0; i < howMany; i++)
{
BigInteger perfect1 = Zero.setBit(expn[i] - 1); // 2^(p-1)
perfectNums[i] = Zero.setBit(2 * expn[i] - 1); // 2^(2*p-1)
perfectNums[i] = perfectNums[i].subtract(perfect1); // 2^(2*p-1) - 2^(p-1)
}
return perfectNums;
}