Goldbach conjecture
Contents
6.5. Goldbach conjecture#
In this section, we will write a longer program that checks for a given number if the Goldbach conjecture is verified or rejected.
6.5.1. Problem Statement#
A conjecture is a proposition/opinion/observation that is not proven yet. For example, the Goldbach conjecture states:
Every even integer greater than \(2\) can be written as the sum of two prime numbers.
A prime number is a number divisible only by two distinct numbers: 1 and itself. For example, \(2\), \(3\), \(5\), \(7\), \(11\), \(13\), \(17\). Keep in mind that \(1\) is not a prime number because it is divisible by \(1\) only, not two distinct numbers.
Let’s write a program that asks for the user to input a number that is even and greater than \(2\), and then checks if this number verifies or rejects the Goldbach conjecture.
6.5.2. Divide Problem into sub-problems#
Let’s list the tasks to be done by this program:
Take input number from the user
Verify if the number is even and greater than \(2\)
Test the Goldbach conjecture
Print if the number verifies or rejects the conjecture
Next, we tackle each task and decide if we can put it in a separate function or if it requires multiple functions. This helps us in easily managing a larger piece of software.
6.5.2.1. Take input from the user#
As we take input from the user, we need to validate that it is even and greater than \(2\) before proceeding with testing the Goldbach conjecture.
Loop type. As we discussed in Do-while loop vs. while loop, taking input from the user and validating it requires repetition until a valid input is made. Doing so requires that we first take the input from the user then validating it. This is what a do-while loop is best fit for. This is because a do-while loop will run its statements before checking the condition. Similarly, we want to take input from the user before checking it is even and greater than \(2\).
Function prototype. The following code is a function that takes the address of an int
variable, i.e. int*
, then the value at that address is changed to the input of the user. This is why we received a pointer int*
to the function and return void
.
Code in-progress
1void getUserInput(int *number) {
2 // Get user input from the keyboard
3 // and validates it is even and greater than 2
4
5 do {
6 printf("Enter a number to test the Goldbach conjecture: ");
7 scanf("%d", number);
8 } while (*number <= 2 || *number % 2 != 0);
9}
Important!
In line 6, we are using scanf
without an &
because number
is already an address to the int
we want to change.
In line \(8\), we are referring to the int
variable that number
has it’s address. This is why we dereference number
to get to the int
it is pointing to.
Test with main function
#include <stdio.h>
void getUserInput(int *);
int main(void) { int num; getUserInput(&num); return 0; }
void getUserInput(int *number) { // Get user input from the keyboard // and validates it is even and greater than 2
do { printf("Enter a number to test the Goldbach conjecture: "); scanf("%d", number); } while (*number <= 2 || *number % 2 != 0); }
Currently, the prompt message is not telling the user why is their first and second input invalid. To have a clarifying prompt message after the user enters an invalid input, we can have a bool
variable that indicates if it is the first time the user enters an input. We can use this bool
variable to better explain to the user what is the expected input. The modified function is shown below. We added lines \(17\), \(19\) – \(22\).
Improved getUserInput
function
#include <stdbool.h> #include <stdio.h>
void getUserInput(int*);
int main(void) { int num; getUserInput(&num); return 0; }
void getUserInput(int *number) { // Get user input from the keyboard // and validates it is even and greater than 2 bool firstEntry = true; do { if (firstEntry) { printf("Enter a number to test the Goldbach conjecture: "); firstEntry = false; } else { printf("Your input was invalid, please enter another even number > 2: "); } scanf("%d", number); } while (*number <= 2 || *number % 2 != 0); }
6.5.2.2. Test the Goldbach conjecture#
Step 1: Toy example. For example, if the user enters \(12\). Logically, we can think that 12 can be written as \(12 = 5 + 7\).
Step 2: Think of a solution and decompose into steps! The user entered \(12\) which is a sum of two int
prime numbers, x
and y
, i.e. \(12 = x + y\). To find x
and y
, we can
Get the first prime number in
x
, which is \(2\).Then get
y
, which is \(y = 12 - x\).Check if
y
is prime.If
y
, is not prime, we incrementx
to the next prime number.Then we repeat steps \(2\) – \(4\)
We stop repeating till we find
y
is prime or if the conjecture is rejected. When is the conjecture rejected?
For example, in Fig. 6.14, we show the steps/iterations to verify the Goldbach conjecture for \(12\). The conjecture gets rejected when we continue looking for x
and y
, but realize they will never be both prime numbers. This happens when x
prime numbers start to surpass the values of y
. This is also around when x
becomes greater than the half of \(12\), which is the number we are testing.
Summary! We stop iterating and looking for x
and y
prime numbers either: (i) when the conjecture is verified (x
and y
are prime) or (ii) when x
becomes greater than y
and we have never verified the conjecture before!
Step 3: Write a pseudo-code. We can write the pseudo-code of the above steps. Pseudo-code is an informal language used to write code. It is intended to simplify a piece of code by writing it in plain English language mixed with a program language too. For example, we can translate the above steps to the following pseudo-code.
Pseudo-code
// first prime number x = 2 while(not verified and not rejected){ // look for x and y // N is user input y = N - x if(y is Prime){ conjecture is verified }else if (x > y){ conjecture is rejected }else{ x is advanced to the next prime number } }
Step 5: Write the code. There are two tasks in the previous pseudo-code that require a few lines of code to accomplish. These are: (i) if y is prime, and (ii) to get the next prime number after x
. These two will be completed by different functions. We can define their function prototypes before proceeding with writing the code for testing Goldbach conjecture.
Check if a number is prime. This can be a function that returns
true
is a number is prime andfalse
if the number is not prime. The only input this function requires is theint
value it will check. This makes the function prototype:bool isPrime(int);
Get the next prime number. There are many ways to advance to the next prime number. All what you need is to pass the address of
x
to that function, and the function will change the value ofx
and returnvoid
. This makes the function prototype:void nextPrimeNumber(int*);
In the following code, we convert the pseudo-code to a function written in C programming language.
1bool testGoldbach(int N) {
2 // Tests the Goldbach conjecture and
3 // returns true if verified or false if rejected
4 int x = 2, y;
5 bool rejected = false;
6 bool verified = false;
7 while (!rejected && !verified) {
8 y = N - x;
9 if (isPrime(y)) {
10 verified = true;
11 } else if (y < x) {
12 rejected = true;
13 } else {
14 nextPrimeNumber(&x);
15 }
16 }
17 return verified;
18}
In line \(7\), we check if rejected and verified are both false
. This is by adding a !
before rejected
and !
before verified
and ANDing them: !rejected && !verified
.
In line \(9\), we immediately use isPrime
as we know it returns either true
if y
is a prime number or false
otherwise: isPrime(y)
.
In line \(14\), we use nextPrimeNumber
by passing the address of x to it, and inside the function we will shortly implement the advancement of x
to the next prime number: nextPrimeNumber(&x)
.
6.5.2.3. Get the Next Prime Number#
To implement void nextPrimeNumber(int*);
, we need to first think of how to find the next prime number.
Step 1: Toy example. For example, the next prime number after \(3\) is \(5\).
Step 2: Think of a solution and decompose into steps. The next number after \(3\) is \(4\), but it is not prime number. We can continue advancing to \(5\) and then checking if it is prime! Given that, the steps to get the next prime number are
Add \(1\) to that value
Check if it is prime
Repeat \(1\) – \(2\) till value becomes a prime number
Step 3: Write the code. The following code implements the steps discussed. Caution! We are receiving the address of a int
, which is int*
.
1void nextPrimeNumber(int *px) {
2 // We will look for the numbers after *pFrist one by one
3 // until we find the next prime number
4 int value = *px + 1;
5 while (!isPrime(value)) {
6 value += 1;
7 }
8 *px = value;
9}
In line \(5\), we check if value
is prime or not using isPrime
function, which we know it will return true
if value is prime and false
otherwise. !isPrime(value)
is true
as long as value
is not prime. Once value
is prime, !isPrime(value)
becomes false
, and we exit the loop.
In line \(8\), we are not returning any values because nextPrimeNumber
does not return any number. Instead, we change the value at address px
to the prime number we found next.
Step 4: Test your code in isolation. You should be testing your code when called only by the main
function to see if it works.
6.5.2.4. Find If a Number Is Prime or Not#
To implement bool isPrime(int);
, we need to first think of how to know if a number is prime.
Step 1: Toy example. For example, \(12\) is not a prime number.
Step 2: Think of a solution and decompose into steps. We know that a prime number num
is divisible only by \(1\) and num
. This means that between \(2\) and the num - 1
there are no divisibles of num
. We can do the following steps to see if num
is prime:
Denominator
denom
is set to \(2\)Find if
num
/ \(2\) gives no remainder, i.e.num % denom == 0
If
num % denom == 0
, thennum
is not prime, because it is divisible bydenom
.Otherwise, add \(1\) to
denom
Repeat \(2\) – \(4\), until either you found out
num
is not prime, or whennum % denom == 0
has been checked on alldenom
values from \(2\) tonum - 1
and was nevertrue
. This is whennum
istrue
.
Step 4: Write pseudo-code.
Pseudo-code
// We can start with good intentions that a number is prime if (number is less than 2){ number is not prime }else{ denom = 2 while(denom < num -1 and number is still prime) if (num % denom == 0){ number is not prime }else{ denom = denom + 1 } } }
Step 3: Write the code. To implement the bool isPrime(int);
, we will convert the pseudo-code into code.
Code
1bool isPrime(int num) {
2 // check if num is prime, by checking the remainder of num / all numbers from
3 // 2 to num - 1
4 bool prime = true;
5 if (num < 2) {
6 prime = false;
7 } else {
8 for (int denom = 2; denom <= num - 1 && prime; denom++) {
9 if (num % denom == 0) {
10 prime = false;
11 }
12 }
13 }
14 return prime;
15}
Step 4: Test your function in isolation. Think of numbers to test your function. Numbers less than, greater than or equal to 2.
Does the function work with numbers less than 2? Yes. Line \(6\) will set
prime
tofalse
.Does the function work with 2? In line \(8\),
denom
starts from \(2\), and thendenom
is checked withnum - 1
. The conditiondenom <= num - 1
is false ifnum
is set to \(2\). Hence, the function will return the preset value ofprime
, which istrue
.Does the function work with numbers above 2? In lines \(8\) – 10, the function will set
prime
tofalse
ifnum
is divisible by another number between \(2\) andnum - 1
. It will exist the loop because this conditiondenom <= num - 1 && prime
becomesfalse
. The function will not changeprime
value if the loop tries over alldenom
values from \(2\) tonum - 1
and does not findnum
to be divisible. Hence,prime
will continue to betrue
.
6.5.2.5. Print If the Conjecture Is Verified#
We need a function that prints if the Goldbach conjecture is verified or rejected! This function can simply call testGoldbach
. If testGoldbach
returns true
, the function prints the number verifies the conjecture, and prints the number rejects the conjecture otherwise.
These simple steps can be written as follows:
Code
void printConjResult(int number){
//Call a function to verify the conjecture and prints the result
bool verified = testGoldbach(number);
if(verified){
printf("Goldbach conjecture is verified.\n");
}
else{
printf("Goldbach conjecture not verified.\n");
}
}
6.5.3. Integrate all pieces/functions#
In the previous sections, we have divided the steps into two main ones: getting input through getUserInput
and printing if the conjecture is verified through printConjResult
.
This eases the task of writing the main
function. The main
function should only call getUserInput
and printConjResult
. This is shown in the following code.
Code
int main(void){
int number;
getUserInput(&number);
printConjResult(number);
return 0;
}
Output1
Enter a number to test the Goldbach conjecture: 9 Your input was invalid, please enter another number > 2: 8 Goldbach conjecture is verified.
Please refer to goldbach-conjecture.c
if you want to view the entire program and test it yourself.
Quiz
0 Questions
- 1
Inputs to programs are in bold.