Search code examples
cperfect-numbers

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.


Solution

  • 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