Search code examples
clogic

i wrote this code to check whether a number is prime, Armstrong or perfect and for some reason it doesn’t print when i use large numbers


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int CheckNumber(long long int x);
int prime(long long int n);
int armstrong(long long int z);
int perfect(long long int y);

int main()
{
    long long int i;
    long long int x;
    for (i = 1; i > 0; i++)
    {
        long long int n, s;
        printf("\nEnter a number to be checked:");
        scanf("%lld", &n);
        s = CheckNumber(n);
        switch (s)
        {
        case (0):
            printf("\nThis number is Prime");
            break;
        case (1):
            printf("\nThis number is Perfect");
            break;
        case (2):
            printf("\nThis number is Armstrong");
            break;
        case (3):
            printf("\nThis number is Armstrong & Prime");
            break;
        case (4):
            printf("\nThis number is Armstrong & Perfect.");
            break;
        case (5):
            printf("\nThis number is otherwise.");
            break;
        }
        printf("\n\nwant to check another number?\n(1) to continue (0) to close.");
        scanf("%lld", &x);
        if (x == 0)
        {
            break;
        };
    }
    return 0;
}

int prime(long long int n)
{
    long long i, check = 0;
    if (n == 0 || n == 1)
        check = 1;

    for (i = 2; i <= n / 2; ++i)
    {
        if (n % i == 0)
        {
            check = 1;
            break;
        }
    }
    if (check == 0)
    {
        return 0;
    }
    return 1;
}

int perfect(long long int y)
{
    long long int n, i = 1, np = 0;
    n = y;
    do
    {
        if (n % i == 0)
        {
            np = np + i;
        }
        i++;
    } while (i != n);
    if (np == n)
    {
        return 1;
    }
    return 2;
}

int armstrong(long long int z)
{
    long long int  nfi, i, host, sum = 0, y;
    y = z;
    if (z == 0)
    {
        return 2;
    }
    nfi = floor(log10(y) + 1);
    for (i = 1; i <= nfi; i++)
    {
        host = y % 10;
        sum += pow(host, nfi);
        y = y / 10;
    }
    if (z == sum)
    {
        return 2;
    }
    return 3;
}

int CheckNumber(long long int x)
{
    if (x == 0 || x == 1)
    {
        return 2;
    }
    if (prime(x) == 0)
    {
        if (armstrong(x) == 2)
        {
            return 3;
        }
        else
        {
            return 0;
        }
    }
    else if (perfect(x) == 1)
    {
        if (armstrong(x) == 2)
        {
            return 4;
        }
        else
        {
            return 1;
        }
    }
    else if (armstrong(x) == 2)
    {
        return 2;
    }
    else
    {
        return 5;
    }
}

This code has four functions.

  • The prime function checks if a number is prime or not; it returns 0 when it is prime and 1 if it is not.

  • The perfect function checks if a number is perfect or not; it returns 1 if it is perfect and 2 if it is not.

  • The armstrong function checks if a number is Armstrong or not; it returns 2 if Armstrong and 3 if not.

  • The checknumber function checks if the number is a prime, Armstrong, or perfect number. and it returns:

  • 0 if the number is prime.

  • 1 if the number is perfect.

  • 2 if the number is Armstrong.

  • 3 if the number is Armstrong & prime.

  • 4 if the number is Armstrong & perfect.

  • 5 Otherwise.

In the main function, I made an infinite loop to ask the user for the number he wants to check, and after checking it, I asked the user if he wanted to check another number or not. I also made a switch for the checknumber function to print the number that was entered, for example:

The user enters 7, the output is:

 This number is Armstrong & Prime.
 Want to check another number? (1) to continue; (0) to close.

The problem is that when I use this number (28116440335967) to check, the program never produces any output, and I don't know why.


Solution

  • You need a more efficient algorithm to check for prime numbers and perfect numbers: as coded, you iterate up to n / 2 times in the prime() function and n times for the perfect() function.

    Since 28116440335967 is a prime number, prime(x) takes a long time and perfect(x) even longer, which explains the lack of output: the program is just running full speed but takes too long.

    You can reduce the complexity of both functions by iterating only up to the square root of x:

    int prime(long long int n) {
        if (n < 2)
            return 0;
        if (n % 2 == 0)
            return n == 2;
        for (long long i = 3; i <= n / i; i += 2) {
            if (n % i == 0) {
                return 1;
            }
        }
        return 0;
    }
    
    int perfect(long long int n) {
        long long int i, q, np = 1;
    
        for (i = 2; i <= (q = n / i); i++) {
            if (n % i == 0) {
                np = np + i;
                if (q != i)
                    np = np + q;
            }
        }
        if (np == n) {
            return 1;
        } else {
            return 2;
        }
    }
    

    Note also these remarks:

    • it is very confusing for the prime() function to return 0 is the number is prime and 1 otherwise.

    • it would be much more intuitive for prime(), armstrong() and perfect() to return 0 if the number is not prime, Armstrong or perfect respectively and 1 if it is.

    • using a combination of binary indicators for the CheckNumber() return value would make the code both simpler and more readable.

    • it is recommended to use integer arithmetics for the armstrong() function to avoid accuracy issues in functions log10 and pow.

    Here is a modified version:

    #include <stdio.h>
    
    enum { PRIME = 1, ARMSTRONG = 2, PERFECT = 4 };
    
    int checkNumber(long long int x);
    int prime(long long int n);
    int armstrong(long long int n);
    int perfect(long long int n);
    
    int main(void) {
        for (;;) {
            long long int n;
    
            printf("Enter a number to be checked: ");
            if (scanf("%lld", &n) != 1) {
                printf("\n");
                break;
            }
            switch (checkNumber(n)) {
            case PRIME:
                printf("This number is Prime\n");
                break;
            case PERFECT:
                printf("This number is Perfect\n");
                break;
            case ARMSTRONG:
                printf("This number is Armstrong\n");
                break;
            case ARMSTRONG + PRIME:
                printf("This number is Armstrong & Prime\n");
                break;
            case ARMSTRONG + PERFECT:
                printf("This number is Armstrong & Perfect.\n");
                break;
            default:
                printf("This number is otherwise.\n");
                break;
            }
        }
        return 0;
    }
    
    int prime(long long int n) {
        if (n < 2)
            return 0;
        if (n % 2 == 0)
            return n == 2;
        for (long long i = 3; i <= n / i; i += 2) {
            if (n % i == 0) {
                return 0;
            }
        }
        return 1;
    }
    
    int perfect(long long int n) {
        long long int i, q, np = 1;
    
        for (i = 2; i <= (q = n / i); i++) {
            if (n % i == 0) {
                np = np + i;
                if (q != i)
                    np = np + q;
            }
        }
        return np == n;
    }
    
    int armstrong(long long int n) {
        long long int sum;
        long long int x;
        int nfi;
    
        if (n == 0)
            return 0;
        for (nfi = 0, x = n; x; x /= 10)
            nfi++;
        for (sum = 0, x = n; x; x /= 10) {
            long long int digit = x % 10;
            long long int val = digit;
            for (int i = 1; i < nfi; i++) {
                val *= digit;
            }
            sum += val;
        }
        return (n == sum);
    }
    
    int checkNumber(long long int n) {
        return prime(n) * PRIME | perfect(n) * PERFECT | armstrong(n) * ARMSTRONG;
    }