Search code examples
cprimesgoldbach-conjecture

Goldbach conjecture exercise (c)


My professor asked me to do a program to test the Goldbach conjecture. I am wondering if I should consider 1 as a prime. This is my code that prints the first combination of prime numbers:

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

int main()
{
    int n, i, j, k, l;    
    char prime, prime1;
    do   //check if n is even and greater than 2
    {
        printf("Give me an even natural number greater than 2:\n\n>");
        scanf("%d", &n);
    }
    while (n % 2 != 0 && n >= 2);
    for (i = 1; i < n ; i++) 
    {                   
        prime = 1;     
        for (k = 2; k < i; k++)  
            if (i % k == 0)
                prime = 0;
        if (prime)
        {
            for (j = 1; j < n; j++)
            {
                prime1 = 1;
                for (l = 2; l < j; l++)
                    if (j % l == 0)
                        prime1 = 0;
                if (prime1)
                    if (i + j == n)
                    {
                        printf("\n\n%d and %d are the first two prime numbers that add up to %d.\n", i, j, n);
                        return 0;
                    }
            }
        }
    }
}

I checked the internet and almost everyone says that 1 is not a prime. What should i do? Keep the program as it is or change it so that it won't consider 1 as a prime? And how do I do that? :P


Solution

  • you can consider 1 a prime number, as Goldbach did, or not as is the more common usage, it makes almost no difference regarding the conjecture.

    Considering 1 as a prime number has this effect:

    • there is a solution for 2: 1 + 1.
    • the first pair for 4 is 1 + 3 instead of 2 + 2
    • the first solution for higher even numbers may involve 1 if the value is a prime number plus one, but no known even number greater than 2 can only be expressed as p + 1.

    Note that there are problems in your code:

    • you do not check the return value of scanf(), so inputing a string that is not a number will cause undefined behavior (the first time as n is uninitialized) or an infinite loop as n is no longer modified.

    • the test while (n % 2 != 0 && n >= 2); is incorrect: it should be:

      while (n <= 2 || n % 2 != 0);
      
    • the first loop could iterate half as long with a test i <= n / 2

    • the second loop could iterate much less with a test k * k <= i

    • you could exit the second loop when you detect that i is not prime

    • there is no need for a third loop, you just need to test if n - i is prime

    • the same improvements are possible for the second primary test, better move this to a separate function.

    • you should have a message and return statement for the remote possibility that you find a counter-example to the Goldbach conjecture ;-)

    Here is an improved version:

    #include <stdio.h>
    
    #define PRIME_MASK ((1ULL <<  2) | (1ULL <<  3) | (1ULL <<  5) | (1ULL <<  7) |\
                        (1ULL << 11) | (1ULL << 13) | (1ULL << 17) | (1ULL << 19) | \
                        (1ULL << 23) | (1ULL << 29) | (1ULL << 31) | (1ULL << 37) | \
                        (1ULL << 41) | (1ULL << 43) | (1ULL << 47) | (1ULL << 53) | \
                        (1ULL << 59) | (1ULL << 61))
    
    int isprime(unsigned long long n) {
        if (n <= 63)
            return (PRIME_MASK >> n) & 1;
        if (n % 2 == 0)
            return 0;
        for (unsigned long long k = 3; k * k <= n; k += 2) {
            if (n % k == 0)
                return 0;
        }
        return 1;
    }
    
    int main(void) {
        unsigned long long n, i;
        int r;
    
        for (;;) {
            printf("Give me an even natural number greater than 2:\n>");
            r = scanf("%llu", &n);
            if (r == 1) {
                if (n % 2 == 0 && n > 2)
                    break;
            } else
            if (r == EOF) {  /* premature end of file */
                return 1;
            } else {
                scanf("%*[^\n]%*c");  /* flush pending line */
            }
        }
    #ifdef ONE_IS_PRIME
        i = 1;    /* start this loop at 1 if you want to assume 1 is prime */
    #else
        i = (n == 4) ? 2 : 3;
    #endif
        for (; i <= n / 2; i += 2) {
            if (isprime(i) && isprime(n - i)) {
                printf("%llu = %llu + %llu\n", n, i, n - i);
                return 0;
            }
        }
        printf("Goldbach was wrong!\n"
               " %llu cannot be written as the sum of two primes\n", n);
        return 0;
    }