7/12/2014

C/++ PROGRAMMING Rational Numbers Lab Assignment Discussion

Copyright © 2014 Dan McElroy

Rational Numbers – List of Topics • What are Rational Numbers? • Rational Number Lab Assignment • How to use Rational Numbers + - * / • Sample use of Rational + Rational • Sample use of Rational += Rational • Helper functions • Recursive GCD function • Default values for functions and constructors • add vs. operator+ member methods • operator+ vs. operator+= • casting to double • friend function << vs. display( )

1 7/12/2014

What are Rational Numbers Integers are expressed as whole numbers, without any digits past the decimal place. C and C++ define an integer with the int . Real numbers are also called floating point numbers and can have digits past the decimal point. C and C++ define real numbers with the float or double data type. Rational numbers are expressed in fractional format with a numerator and denominator. Examples include: 1/2 2/3 -5/8 5/2 (which is 2.5 in floating point). C and C++ do not have a Rational data type.

Addition Using Rational Numbers Find the numerators by cross- multiplying the numerator by 2 3 8 15 23 the opposite denominator + = + = 5 4 20 20 20 Find the common denominator by multiplying the two denominators 1 1 4 2 6 3 + = + = = Reduce the fraction by finding the 2 4 8 8 8 4 lowest common divisor (LCD)

between 6 and 8 The code for addition of two Rational numbers is already provided in the sample code for the lab assignment.

2 7/12/2014

Subtraction Using Rational Numbers Find the numerators by cross- multiplying the numerator by 2 3 8 15 -7 the opposite denominator ̶ = − = 5 4 20 20 20 Find the common denominator by multiplying the two denominators 1 1 4 2 2 1 ̶ = − = = Reduce the fraction by finding the 2 4 8 8 8 4 lowest common divisor (LCD)

between 2 and 8 You need to complete the program for subtraction. The code for subtraction is almost the same as the code for addition. Just substitute a minus for the plus.

Multiplication Using Rational Numbers

Find the numerator by multiplying 2 3 6 3 both numerators * = = 5 4 20 10 Find the denominators by multiplying both denominators

Reduce the fraction by finding the lowest common divisor (LCD) between 3 and 10 You need to complete the program for multiplication. The code for multiplication is probably the easiest part of the project.

3 7/12/2014

Division Using Rational Numbers Find the numerator by multiplying the numerator of the first number 2 3 2 4 8 by the denominator of the second ÷ = = number 5 4 5 * 3 15 Find the denominator by

multiplying the denominator of the

first number by the numerator of Flip the numerator and denominator the second number of the second number and multiply.

You need to complete the program for division. The code for division is similar to multiplication except for multiplying numerator by #2's denominator and the denominator by #2's numerator.

Rational Number Lab Assignment Since the C and C++ languages do not have a Rational data type, a user data type can be provided. In the C language, it would be provided by a collection of functions. In C++ it would be provided by creating a Rational class and then objects of the Rational class can be created from the Rational class. class Rational int main (int argc, char *argv[ ]) { { // code for Rational numbers Rational num1; }; Rational num2 (2, 3); // process num1 and num2 };

4 7/12/2014

Rational Number Project Files Three files make up the Rational number project: 1) Rational.h – defines the Rational number class 2) Rational.cpp – provides the code for the member methods for the Rational class. Since the code is in a different file from the class definition (Rational.h), it is necessary to use the scope resolution operator :: to connect the code in Rational.cpp to the class 3) RationalTest.cpp – The main( ) program is in this file. It is used to create objects from the Rational class, put different values in the objects and test the new student created code for subtraction, multiplication and division.

Rational Number Project Files Rational.h class Rational { // definition here }; Rational.cpp RationalTest.cpp Rational::Rational( int n, int d) int main (int argc, char *argv[ ]) { { // constructor Rational number1; } Rational number2 (2, 3); // process number1 and number2 and other member methods }; Both Rational.cpp and RationalTest.cpp need to use #include "Rational.h" to have access to the Rational class definition. You should have a copy of all three files for reference during the remainder of this discussion.

5 7/12/2014

Rational.h - Part 1

# ifndef RATIONAL_H // if this macro is not defined #define RATIONAL_H // then define it so this file will not be processed again

// all of the code to define the Rational class goes here

#endif

Most header files start with a #ifndef and a modified version of the header file's name. In this file if RATIONAL_H has not been defined, this means that this header file has not been read yet while compiling the program. If RATIONAL_H has been defined, the rest of the header file is skipped. The RATIONAL_H symbol is then defined to prevent the class from being defined twice.

Rational.h - Part 2

class Rational { // Friend functions are actually declared outside the scope of the // class but have the right to access public and private data and // member function members that belong to the class. The friend // function below gives the << operator for ostreams (including cout) // the ability to output a Rational object by accessing its member data. friend ostream &operator<< (ostream &out, Rational const &r);

A friend function named &operator<< is defined to provide access for cout and other output operators. The friend function will provide specific to the Rational class so that cout and other ostream operators can process << similar for displaying integers, floats, strings, etc.

6 7/12/2014

Rational.h - Part 3

public: Rational (int num=0, int denom=1); // also provides default constructor Rational add (Rational right); Rational operator+ (Rational right); // + addition operator Rational operator+= (Rational right); // += addition assignment operator void display(); operator double() const; // convert Rational to double

The public: area of the Rational class permits these functions (and member data if provided) to be accessed by the main program. These functions will be described in more detail.

Rational.h - Part 4

private: int numerator; int denominator; // helper functions are private and not accessible by the main program int LCD(int v1, int v2); void setRational (int n, int d);

The private: area of the Rational class permits contains the declaration for the data that belongs to the class. It also contains the definitions (function prototypes) for any of the 'helper' functions that are used internally by other functions within the Rational class. These private functions can not be used by the main program.

7 7/12/2014

Rational.h - Part 5

};

#endif

Each class definition ends with a curly-brace and a semi-colon.

The #endif is used to complete the #ifndef statement that was at the top of the header file.

Rational.cpp - Part 1 ::

// Constructor for the Rational class Rational ::Rational (int num, int denom) { setRational(num,denom); // numerator and denominator, fix the sign } Notice the scope resolution operator :: Since the code for the function is not provided inside the Rational.h header file, it is necessary to provide Rational:: for each of the functions in Rational.cpp to identify that they belong to the Rational class.

8 7/12/2014

Rational.cpp - Part 2, constructor // Constructor for the Rational class Rational::Rational (int num, int denom) { setRational(num,denom); // set numerator and denominator, fix the sign } Some languages require that you write separate constructors when there are different number of parameters possible. Rational number1; // gives 0/1 which is zero Rational number2(5); // gives 5/1 which is 5 Rational number3(3,4); // gives ¾ Refer to the definition of the Rational constructor in Rational.h. Rational (int num=0, int denom=1); It provides default values of 0 and 1 if any of the parameters are missing, starting from right to left.

Rational.cpp - Part 3, setRational( ) // Constructor for the Rational class Rational::Rational (int num, int denom) { setRational(num,denom); // set numerator and denominator, fix the sign } The constructor could just as easily entered the values for numerator and denominator directly into these class variables, but there is an advantage of calling a set function which can validate the numbers.

9 7/12/2014

void Rational::setRational (int n, int d) // helper function { numerator = n; Rational.cpp - Part 4a denominator = d; // if denominator == 0 then set it = 1 if (denominator == 0) denominator = 1; if ( denominator < 0 ) // if denominator is neg, multiply num and denom by -1 { numerator = -numerator; // fix sign of numerator +/- denominator = -denominator; // denominator always + } int lcd = LCD(numerator, denominator); if (denominator != 0) { numerator /= lcd; denominator /= lcd; } }

Force the denominator to non-zero

void Rational::setRational (int n, int d) // helper function { numerator = n; Rational.cpp - Part 4b denominator = d; // if denominator == 0 then set it = 1 if (denominator == 0) denominator = 1; if ( denominator < 0 ) // if denominator is neg, multiply num and denom by -1 { numerator = -numerator; // fix sign of numerator +/- denominator = -denominator; // denominator always + } int lcd = LCD(numerator, denominator); if (denominator != 0) { numerator /= lcd; denominator /= lcd; } } Keep the denominator positive: 2 becomes -2 -2 becomes 2 -5 5 -5 5

10 7/12/2014

void Rational::setRational (int n, int d) // helper function { numerator = n; Rational.cpp - Part 4c denominator = d; // if denominator == 0 then set it = 1 if (denominator == 0) denominator = 1; if ( denominator < 0 ) // if denominator is neg, multiply num and denom by -1 { numerator = -numerator; // fix sign of numerator +/- denominator = -denominator; // denominator always + } int lcd = LCD(numerator, denominator); if (denominator != 0) { numerator /= lcd; denominator /= lcd; } } Call the LCD helper function to get the lowest common divisor 3 becomes 1 26 becomes 2 12 4 39 3

Rational.cpp - Part 5 LCD( ) // find the lowest common divisor using a recursive function int Rational::LCD(int v1, int v2) { if (v2==0) return v1; else return LCD (v2, v1%v2); } LCD is a recursive function that finds the lowest common divisor. Recursive means that the function calls itself. LCD(v1, v2) v1 v2 v1%v2 LCD(259, 111) 259 111 37 LCD(111, 37) 111 37 0 LCD(37, 0) 37 0 Not computed return 37

11 7/12/2014

Rational.cpp - Part 6, add() Rational Rational::add (Rational right) { int newNumerator; int newDenominator;

newNumerator = numerator*right.denominator + right.numerator*denominator; newDenominator = denominator * right.denominator;

// create a new Rational object and return it return Rational(newNumerator, newDenominator); }

Using the add function in main requires that you supply an object, a dot and the function name. A second Rational object needs to be provided as an argument within the parentheses. Rational v1(1,2); Rational v2(1,4); Rational v3 = v1.add(v2); // add v2 to v1 and return result

Rational.cpp - Part 7, operator+ Rational Rational::operator+ (Rational right) { int newNumerator; int newDenominator;

newNumerator = numerator*right.denominator + right.numerator*denominator; newDenominator = denominator * right.denominator;

// create a new Rational object and return it return Rational(newNumerator, newDenominator); }

It would be nice to use the + symbol to add two Rational numbers instead of being required to call the add function. Rational v1(1,2); Rational v2(1,4); Rational v3 = v1.operator+(v2); // add v2 to v1 and return result Rational v3 = v1 + v2; // same execution as the line above

12 7/12/2014

Rational.cpp - Part 8, operator+= Rational Rational::operator+ (Rational right) { int newNumerator; int newDenominator;

// since this is an assignment operator, modify the original object's data numerator = numerator*right.denominator + right.numerator*denominator; denominator = denominator * right.denominator;

// create a new Rational object and return it return Rational(newNumerator, newDenominator); } Do the addition and store the answer back in the first object's data. Rational v1(1,2); Rational v2(1,4); v1 += v2; // same as v1 = v1 + v2

Rational.cpp - Part 9, double( ) Rational::operator double() const // convert Rational to double and return { return double(numerator) / double(denominator); }

Cast (convert to a different data type) a Rational number into a double. This is done by converting both numerator and denominator from integers into double, dividing and returning the result as a double.

const prevents any of the original data from being modified.

13 7/12/2014

Rational.cpp - Part 9, display( ) void Rational::display() { cout << numerator << '/' << denominator; }

The display( ) function uses cout to display the value of the numerator, the '/' symbol and then the denominator.

It is necessary to provide the name of a Rational object, a dot and then display( ) to call this function. Example: Rational n1(2,3); cout << "The value of n1 is: "; n1.display( ); cout << endl;

Rational.cpp - Part 10, friend ostream &operator<< (ostream &out, Rational const &r) { out << r.numerator << '/' << r.denominator; return out; } 1) The friend function prototype was for operator<< was declared in the Rational.h header file. Although the code for the operator<< is placed in the Rational.cpp file, it is not part of the Rational class. Therefore, it is necessary to provide the ostream object and the Rational object as '& references' in the operator<< function call. 2) The &out ostream object could be a cout or any output object. 3) The r. is used to select the member data from the Rational object that is part of the << sequence. 4) The out object is being returned so that other objects and data can continue to flow to cout Rational v1(1,2); cout << "The value of v1 is " << v1 << " which is correct" << endl;

14