M.M.
M.M.

Reputation: 77

How to print 10 perfect numbers from a user given number in C?

I can't figure out how to print next ten Perfect numbers. Here's what I have got so far:

#include <stdio.h>

int main() {
    int n, c = 1, d = 2, sum = 1;
    printf("Enter any number \n");
    scanf("%d", &n);
    printf("The perfect numbers are:");
    while(c <= 10) { 
        sum = 1;
        d = 2;
        while(d <= n / 2) { //perfect no
            if(n % d == 0) {
                sum = sum + d;
            }
            d++;
        }
        if(sum == n) {
            printf("%d\n", n);
        }
        c++;
    }
    return 0;
}

The output I am currently receiving:

input: 2 (say)  
output: 6  

What I want:

input: 2  
output:
6  
28  
496  
8128  
33550336  
858986905  
137438691328  
2305843008139952128  
2658455991569831744654692615953842176
191561942608236107294793378084303638130997321548169216

I have just started coding. Any help will be appreciated.

Upvotes: 2

Views: 1127

Answers (4)

chux
chux

Reputation: 154255

Research, divide and conquer

Perfect numbers are of the form 2p − 1 * (2p − 1).

Code will need extended precision to form 191561942608236107294793378084303638130997321548169216

Increase efficiency

Iterating to <= n / 2 takes far too long. Iterate up to <= n / d

// while(d <= n / 2) {
while(d <= n / d) {

Sample improved code:

bool isprime(unsigned long long x) {
  if (x > 3) {
    if (x % 2 == 0) {
      return false;
    }
    for (unsigned long t = 3; t <= x / t; t += 2) {
      if (x % t == 0) {
        return false;
      }
    }
    return true;
  }
  return x >= 2;
}

Advanced: See Lucas–Lehmer primality test for quick prime test of Mersenne numbers


The below code works for all but the 10th perfect number as code must test for isprime(267 - 1) and I should leave something for OP to do.

static void buff_mul(char *buff, unsigned power_of_2) {
  unsigned long long m = 1ull << power_of_2;
  size_t len = strlen(buff);
  unsigned long long carry = 0;
  for (size_t i = len; i > 0;) {
    i--;
    unsigned long long sum = (buff[i] - '0') * m + carry;
    buff[i] = sum % 10 + '0';
    carry = sum / 10;
  }
  while (carry) {
    memmove(buff + 1, buff, ++len);
    buff[0] = carry % 10 + '0';
    carry /= 10;
  }
}

void print_perfext(unsigned p) {
  // 2**(p-1) * (2**p - 1)
  assert(p > 1 && p <= 164);
  char buff[200] = "1";
  buff_mul(buff, p);
  buff[strlen(buff) - 1]--; // Decrement, take advantage that the LSDigit is never 0
  buff_mul(buff, p - 1);
  puts(buff);
  fflush(stdout);
}

//unsigned next_prime(unsigned first_numeber_to_test_if_prime) {
#include <stdio.h>

int main() {
  unsigned p = 0;
  for (unsigned i = 0; i < 9; i++) {
   // If p prime && 2**p − 1 is prime, then 2**(p − 1) * (2**p − 1) is a perfect number.
    while (!isprime(p) || !isprime((1uLL << p) - 1))
      p++;
    printf("%2u ", p);
    print_perfext(p);
    p++;
  }
  return 0;
}

Output

 2 6
 3 28
 5 496
 7 8128
13 33550336
17 8589869056
19 137438691328
31 2305843008139952128
61 2658455991569831744654692615953842176

Upvotes: 1

cdlane
cdlane

Reputation: 41905

The integer overflow issue mentioned by several folks is significant, but secondary. Even if we fix your broken logic, and adjust it to handle larger, fixed sized integers:

#include <stdio.h>

int main() {
    unsigned long long number;
    printf("Enter any number \n");
    scanf("%llu", &number);
    printf("The perfect numbers are:\n");

    int total = 0;

    while (total < 10) { 
        unsigned long long sum = 1, divisor = 2;

        while (divisor <= number / 2) {
            if (number % divisor == 0) {
                sum += divisor;
            }
            divisor++;
        }

        if (sum == number) {
            printf("%llu\n", number);
            total++;
        }

        number += 1;
    }

    return 0;
}

You still wouldn't get past the first four perfect numbers in any reasonable amount of time:

> ./a.out
Enter any number 
2
The perfect numbers are:
6
28
496
8128

The primary issue is you're using a bad algorithm. Read about Mersenne primes, and their relationship to perfect numbers, as well as the Lucas-Lehmer test. This approach takes more thought, but surprisingly, not much more code. And will produce more results faster (though eventually bog down as well.)

Upvotes: 3

prhmma
prhmma

Reputation: 953

You have to put the counter after you find a perfect number, so increasing c must happen in the if statement that checks the perfect number, like this:

if(sum==n){
    printf("%d",n);
    c++;
}

After this you need to increase the number, called n, like this:

n++;

and based on the numbers, @Jonathan Leffler is right, you should use proper variables.

Upvotes: 2

Maqcel
Maqcel

Reputation: 509

From output you wrote I belive that u want to show 10 first perfect numbers Now u are only showing 6 because u show them from 1 to 10. In this range there is only 6. I wrote sth like this:

#include <stdio.h>
int isperfect(int input) {
int sum = 0, value = input / 2;
do {
    if (input % value == 0) sum += value;
    value--;
} while (value);
if (input == sum) return 1;
else return 0;
}
int main() {
int i;
int count;
for (i = 2, count = 0; count < 4; i++) {
    if (isperfect(i) == 1) {
        count++;
        printf("%d\n", i);
    }
}
return 0;
}

But I don't recomend counting more than 4 because its gonna take too much time

Upvotes: 1

Related Questions