Procedural/Structured Programming: Fraction Case Study
Apply procedural/structured programming principles to implement our fraction case study in C++.
We'll cover the following
- Case study: Mixed fraction arithmetic calculator
- Finding out the memory requirement
- Implementing the add() function
- Flow of the add() function
- Step 1: Convert the given mixed fractions into improper fractions
- Step 2: Making the denominators the same
- Step 3: Computing the resulting fraction
- Step 4: Simplifying the resulting fraction (converting to reduced form)
- Step 5: Convert to a mixed fraction
- Printing the resulting mixed fraction
- Complete code
Let’s develop a solid foundation in procedural/structured programming by solving a mixed fraction arithmetic calculator case study.
Case study: Mixed fraction arithmetic calculator
We’ll tackle our case study by breaking it down into manageable tasks, called functions, and then use them to write the complete flow (the sequence) of the program. We’ll discuss each step of the coding process and learn how to derive other arithmetic operations from the structure of our addition function. Let’s solve this case study!
We already know how to compute arithmetic operations on mixed fractions mathematically (as we did in the “Chapter Overview” lesson). How can we implement it in code?
Finding out the memory requirement
First, we need something that can store our mixed fraction and let us access its individual components (whole number, numerator, and denominator) to perform our arithmetic operations.
For that, we’ll use variables as shown below:
int w; //whole numberint n; //numeratorint d; //denominator
We declare three int
variables (w
, n
, and d
) for the whole number, numerator, and denominator, respectively. For the entire calculator (testing program), we need three fractions. Let’s classify them as left and right fractions for simplicity, where the variables starting with l_
represent the left fraction's components and r_
the right. The result of the addition, subtraction, multiplication, and division will be stored inside another final fraction, which has three more variables starting with f_
.
We’ll use these three fractions in our main()
function and later pass them to the functions for arithmetic operations (addition, subtraction, multiplication, and division).
int f_w, f_n, f_d; //Final fractionint l_w, l_n, l_d; //Left fractionint r_w, r_n, r_d; //Right fraction
To get started with the calculator, let’s begin by implementing the addition operation.
Implementing the add()
function
Since we want to compute the sum of two mixed fractions, we need six variables as parameters or operands. Here’s the prototype of the add()
function:
void add(int l_w, int l_n, int l_d, // left fractionint r_w, int r_n, int r_d, // right fractionint &f_w, int &f_n, int &f_d);// final fraction
Notice the extra three int
variables (&f_w
, &f_n
, and &f_d
)?
The add()
function receives three variables by reference (preceded by &
), meaning any modifications made to these variables within the function will be reflected in the variables passed as arguments. Specifically, the last three variables passed to the function will hold the resulting sum of the left and right fractions. Since the function can’t return more than one value, we use this approach to update the value of our final fraction components in the context where the function is called.
Flow of the add()
function
For a holistic view of what we eventually want to do in this add()
function, the following code snippet is given, showing all the steps translated from the mathematical steps we learned in the “Chapter Overview” lesson for adding two mixed fractions.
void add(int l_w, int l_n, int l_d,int r_w, int r_n, int r_d,int &f_w, int &f_n, int &f_d){/*Step 1:Convert the two fractions L and R to improper fractionvoid improper_fraction(int w, int n, int d, int &new_n, int &new_d);Example: w = 2, n = 3, d = 4,The function will store in: new_n = 11, new_d = 4*/int new_l_n, new_l_d;int new_r_n, new_r_d;improper_fraction(l_w, l_n, l_d, new_l_n, new_l_d);improper_fraction(r_w, r_n, r_d, new_r_n, new_r_d);//Addition Operations///*Step 2: Make same denominator for both fractionvoid same_denominator(int &new_l_n, int &new_l_d,int &new_r_n, int &new_r_d);new_l_n = 2, new_l_d = 3 --> new_l_n = 4, new_l_d = 6new_r_n = 1, new_r_d = 2 --> new_r_n = 3, new_r_d = 6*/same_denominator(new_l_n, new_l_d, new_r_n, new_r_d);/*Step 3: Computing the resultant fractionnew_l_n = 4, new_l_d = 6new_r_n = 3, new_r_d = 6f_w = 0;f_n = 4 + 3 = 7;f_d = 6;*/f_w = 0, f_n = new_l_n + new_r_n, f_d = new_l_d;/*Step 4: Reducing the Resultant fraction (GCD)f_n = 8;f_d = 6; GCD = 2f_n = 8/2 = 4; and f_d = 6/2 = 3;*/int gcd = GCD(f_n, f_d);f_n /= gcd, f_d /= gcd;//Step 5: Convert back to Mixed Fraction & Print// Given: void mixed_fraction(int &f_w, int &f_n, int &f_d);mixed_fraction(f_w, f_n, f_d);}
We don’t need to understand the code yet; we’ll return to it later. For now, let’s try to understand its flow by paying attention to parameters, arguments, and the return types of the functions. Let’s look at each of these steps in detail.
Step 1: Convert the given mixed fractions into improper fractions
As we’ve sent two mixed fractions (one for the left and one for the right) to the add()
function, converting them into improper fractions is necessary before we can carry out the addition operation. Therefore, our initial mathematical step will be to convert them into improper fractions.
Here’s the function for the conversion from a mixed to an improper fraction:
void improper_fraction(int w, int n, int d, int &new_n, int &new_d){// 1: Calculating the new numerator of the fractionint temp_numerator = improper_fraction_numerator(w, n, d); //calculates the new numerator// 2: Assigning a sign to the fractiontemp_numerator *= compute_sign(w, n, d); //Assigns sign// 3: Assigning the denominator valueint temp_denominator = d; //denominator for both fraction remains the samenew_n = temp_numerator;new_d = temp_denominator;return;}
The improper_fraction()
has a total of five parameters. The first three (int w
, int n
, and int d
) are the components of the mixed fraction sent to be converted, whereas int &new_n
and int &new_d
are the improper fraction components sent by reference that need to be updated.
Note: There is no whole number variable for improper fraction. Hence, only two variables (
new_n
andnew_d
) for numerator and denominator, respectively, are passed.
There are a total of three steps involved in this conversion:
Calculating the new numerator of the fraction
Assigning a sign to the fraction
Assigning a denominator value
1. Calculating the numerator
This is achieved using the improper_fraction_numerator()
helper function, given below:
int improper_fraction_numerator(int w, int n, int d){return abs(d) * abs(w) + abs(n);}
This helper function calculates and returns the new numerator of the improper fraction. Notice how we used the abs()
function for each component before calculating the new numerators. The abs()
function returns the absolute value of its parameter.
2. Assigning the fraction sign
After calculating the new numerator, it is important to reassign the sign to the fraction, as the new numerator is computed based on the absolute values of the components. So, to do that, we use the compute_sign()
helper function as shown in the following code:
int compute_sign(int w, int n, int d){int sign_w, sign_n, sign_d;if (w <0)sign_w = -1;elsesign_w = 1;if (n <0)sign_n = -1;elsesign_n = 1;if (d <0)sign_d = -1;elsesign_d = 1;return sign_w * sign_n * sign_d;}
The sign is associated with the whole fraction, not its components. So, we need to normalize each component and compute its overall sign. Imagine, in any fraction, if we have a negative sign in the whole number and the numerator. What do you think would be the overall fraction sign?
Negatives will cancel out to give a positive sign to the overall fraction, a simple mathematical formula. So, whenever we need to compute the overall sign of the fraction, we’ll call the compute_sign()
function just like we did in the improper_fraction()
function.
We pass the final numerator and denominator to the compute_sign()
function, which returns the resultant sign bit for the fraction to be multiplied by temp_numerator
. The code for this function is given below:
temp_numerator *= compute_sign(w, n, d);
3. Assigning the fraction denominator
Since the denominator for the improper fraction remains the same as the mixed fraction, we already have our improper fraction: new_n
/ d
.
int temp_denominator = d; //denominator for both fractions remains the same
Note: We didn't include the reduction of the fraction step while calculating the improper fraction. We'll return to it after we have a final output of the addition operation.
Now that we have a function that can convert mixed fractions to improper ones, we’ll call it for both left and right fractions.
int new_l_n, new_l_d; //left fractionint new_r_n, new_r_d; //right fractionimproper_fraction(l_w, l_n, l_d, new_l_n, new_l_d);improper_fraction(r_w, r_n, r_d, new_r_n, new_r_d);
Here, new_l_n
and new_l_d
are the new numerator and denominator for left, respectively, and new_r_n
and new_r_d
are the new numerator and denominator for the right fraction.
Since we’ve got our fractions converted into the improper form, let’s move to the next step: making the denominators the same for the two fractions.
Step 2: Making the denominators the same
We need to update the denominators to add improper fractions. To achieve that, we write the following helper function:
//Making d same - Step 1void same_denominator(int &new_l_n, int &new_l_d, int &new_r_n, int &new_r_d){// 1: left n = left numerator * right denominatorint temp_l_n = new_l_n * new_r_d;// 2: left n = right numerator * left denominatorint temp_r_n = new_r_n * new_l_d;// 3: Denominator calulationint temp_d = new_l_d * new_r_d;// 4: Assigning valuesnew_l_n = temp_l_n, new_l_d = temp_d;new_r_n = temp_r_n, new_r_d = temp_d;return;}
We pass components of both improper fractions by reference to this function because we want to update multiple variables. We update the left fraction’s numerator new_l_n
by multiplying it with the denominator of the right fraction, new_r_d
. We repeat the same for the right numerator. Finally, we multiply the denominators of both fractions together—this will be the new denominator for both left and right fractions.
Step 3: Computing the resulting fraction
Since we now have the same denominator, the next step is to add the new numerators and assign the denominator to the final fraction. Here’s the code to do just that:
// Step 3: Compute resulting fractionf_w = 0; // whole number 0f_n = new_l_n + new_r_n; //addition of numeratorf_d = new_l_d; // can be either new_l_d or new_r_d
Step 4: Simplifying the resulting fraction (converting to reduced form)
Next, we need to reduce the fraction to its simplest form before converting it back to the mixed fraction form. To do that, we calculate the GCD for the numerator and denominator of the final obtained fraction. Here’s the helper function to calculate that:
//GCD Helper functionint GCD(int a, int b){while (a % b != 0){int r = a % b;a = b;b = r;}return b;}
Note: We don't need to go into the details of how this function works as this is not the main focus of our lesson.
We’ll pass our numerator and denominator to this function, and it will return their GCD to us. It’s implemented in our code as follows:
//Reduce the fraction (GCD) - Step 3int gcd = GCD(f_n, f_d);f_n /= gcd;f_d /= gcd;
Line 2: We call our helper function and pass
f_n
(numerator) andf_d
(denominator) as its parameters.Lines 3–4: We reduce the fraction by dividing the numerator and denominator by their GCD.
Step 5: Convert to a mixed fraction
Now that we have our final reduced answer in the improper form, we need to convert it back to a mixed fraction. To do that, we use the mixed_fraction()
helper function implemented below:
// Simplify fractionvoid mixed_fraction(int &f_w, int &f_n, int &f_d){// Compute Signint sign_mf = compute_sign(f_w, f_n, f_d);// Convert to Mixed Fractionf_w = abs(f_n) / abs(f_d);f_n = abs(f_n) % (f_d);// Attach sign with the respective non-zero numberif (f_w)f_w *= sign_mf;elsef_n *= sign_mf;}
Line 5: As mentioned earlier, the sign is associated with the whole fraction, not its components. So, we need to normalize each component and compute its overall sign. The first step is to calculate the sign for the fraction. So, we’ll again compute the sign of our resulting fraction by calling the
compute_sign()
function.Lines 8–9: To convert the result back to a mixed fraction, we divide the dividend (numerator) by the divisor (denominator). The quotient becomes the new whole number, the remainder becomes the new numerator, and the denominator remains the same. Since
/
(division) of an integer in C++ removes the decimal part (remainder), we obtain the quotient (new whole number) and store it inf_w
. Likewise, we use%
(percent) to calculate the remainder and store it inf_n
, our new numerator.Lines 12–15: For the last step, we assign the sign to the final mixed fraction. We check if the whole number exists since there could be a case where the whole number becomes
0
. If it exists, the sign is multiplied by the whole number; otherwise, the sign is multiplied by the fraction’s numerator.
Printing the resulting mixed fraction
In the last step, let’s print the mixed fraction in our main()
function using the following command:
print ("L + R = ", f_w, f_n, f_d);
Note: We made a special
print()
helper function to print the fraction in mixed form. The details of that function are outside the scope of this course.
Complete code
Here’s what the complete code looks like:
#include <iostream>using namespace std;//GCD helper functionint GCD(int a, int b){while (a % b != 0){int r = a % b;a = b;b = r;}return b;}//Improper fraction numerator calculator helper functionint improper_fraction_numerator(int w, int n, int d){return abs(d) * abs(w) + abs(n);}//Compute sign for the final Mixed Fractionint compute_sign(int w, int n, int d){int sign_w, sign_n, sign_d;if (w <0)sign_w = -1;elsesign_w = 1;if (n <0)sign_n = -1;elsesign_n = 1;if (d <0)sign_d = -1;elsesign_d = 1;return sign_w * sign_n * sign_d;}//Print helper functionvoid print(string msg, int l_w, int l_n, int l_d){cout<< msg <<" = " << l_w << "<" << l_n << "/" << l_d << ">\n";}//Convert Mixed fraction to Improper fractionvoid improper_fraction(int w, int n, int d, int &new_n, int &new_d){int temp_numerator = improper_fraction_numerator(w, n, d);temp_numerator *= compute_sign(w, n, d);int temp_denominator = d;new_n = temp_numerator;new_d = temp_denominator;}//Make the Improper Fractions' denominator samevoid same_denominator(int &new_l_n, int &new_l_d, int &new_r_n, int &new_r_d){// 1: left n = left n * right dint temp_l_n = new_l_n * new_r_d;// 2: left n = right n * left dint temp_r_n = new_r_n * new_l_d;// 3: Denominator calulationint temp_d = new_l_d * new_r_d;//Assigning valuesnew_l_n = temp_l_n, new_l_d = temp_d;new_r_n = temp_r_n, new_r_d = temp_d;}//Convert back to Mixed fractionvoid mixed_fraction(int &f_w, int &f_n, int &f_d){// Simplify fraction// Compute Signint sign_mf = compute_sign(f_w, f_n, f_d);// Convert to Mixed Fractionf_w = abs(f_n) / abs(f_d);f_n = abs(f_n) % (f_d);// Attach sign with the respective non-zero numberif (f_w)f_w *= sign_mf;elsef_n *= sign_mf;}//ADDITION OPERATIONvoid add(int l_w, int l_n, int l_d, int r_w, int r_n, int r_d,int &f_w, int &f_n, int &f_d){//Step 1: Convert to Improper Fraction //int new_l_n, new_l_d;int new_r_n, new_r_d;improper_fraction(l_w, l_n, l_d, new_l_n, new_l_d);improper_fraction(r_w, r_n, r_d, new_r_n, new_r_d);//Addition////Step 2: Making d samesame_denominator(new_l_n, new_l_d, new_r_n, new_r_d);//Step 3: Compute resulting fractionf_w = 0;f_n = new_l_n + new_r_n;f_d = new_l_d;//Step 4: Reduce the fraction (GCD)int gcd = GCD(f_n, f_d);f_n /= gcd;f_d /= gcd;//Step 5: Convert to Mixed Fraction & Printmixed_fraction(f_w, f_n, f_d);}int main(){int f_w, f_n, f_d ; //final fractionint l_w = -2, l_n = 1, l_d = 2; //left fractionint r_w = 0, r_n = 1, r_d = 2; //right fractionprint ("Left",l_w, l_n, l_d);print ("Right",r_w, r_n, r_d);add(l_w, l_n, l_d,r_w, r_n, r_d,f_w, f_n, f_d);print ("Left + Right", f_w, f_n, f_d);return 0;}
That’s it! We just wrote the code for a mixed fraction addition calculator. Play around with this code widget by trying different values and see how the addition calculator works.