You're not computing your divisors correctly. You need to set sum to 1
and then iterate starting at 2
while factorNum < number
. But a somewhat better method is to consider that if a % b == 0
then both b
and a/b
are divisors. So you only need to check factors <= to the square root
of the test number. It would look like the following:
int sum = 1;
int limit = (int)Math.sqrt(number);
for (int factorNum = 2; factorNum <= limit; factorNum++) {
if (number % factorNum == 0) {
sum += (factorNum + number/factorNum);
}
}
But even the above is not very efficient for finding larger perfect numbers. As they get large very quickly, the loop is very time consuming. A better way is to use BigInteger to allow for arbitrarily large numbers and to take advantage of their form as detailed in Perfect Number. An abbreviated explanation is provided below.
If p is prime and 2p-1 is prime then then (2p-1)(2p-1) is a perfect number. So the following will find all perfect numbers up to a given maximum. You can adjust it as required, but the max I have chosen is 2150. The only thing that is special about the following is that BigInteger
is used along with its test for primality. The computations are just basic mathematical operations.
int p = 2;
// BigInteger max = BigInteger.valueOf(22_000);
BigInteger max = BigInteger.TWO.pow(150);
BigInteger perfect = BigInteger.ZERO;
while(perfect.compareTo(max) < 0) {
if (BigInteger.valueOf(p).isProbablePrime(50)) {
BigInteger powerOfTwo = BigInteger.TWO.pow(p-1);
BigInteger mersenne = powerOfTwo.multiply(BigInteger.TWO).subtract(BigInteger.ONE);
if(mersenne.isProbablePrime(50)) {
perfect = powerOfTwo.multiply(mersenne);
System.out.println(perfect);
}
}
p += p > 2 ? 2 : 1;
}
prints
6
28
496
8128
33550336
8589869056
137438691328
2305843008139952128
2658455991569831744654692615953842176
191561942608236107294793378084303638130997321548169216