Department of Computer and Information Science School of

  • Slides: 28
Download presentation
Department of Computer and Information Science, School of Science, IUPUI Abstract Data Type Fraction

Department of Computer and Information Science, School of Science, IUPUI Abstract Data Type Fraction Example Dale Roberts, Lecturer Computer Science, IUPUI E-mail: droberts@cs. iupui. edu Dale Roberts

Abstract Data Type Example An Abstract Data Type is a data type that is

Abstract Data Type Example An Abstract Data Type is a data type that is defined by the programmer, not the language. Like any data type, it is a set of values with operations that act on those values. Working with ADTs involves three different components: 1. The public interface, or specification, defines the ADT and how it is used. 2. The implementation, implements the ADT in code. 3. The client uses the ADT to perform a task. Dale Roberts

Defining an ADT Within C++, you define an ADTs public interface with a header

Defining an ADT Within C++, you define an ADTs public interface with a header file. #include “fraction. h” main() { Fraction x, y; … } User-defined ADTs are typically capitalized to distinguish them from intrinsic data types. Dale Roberts

ADT Operations 1. 2. 3. 4. Several classes of operations are required in order

ADT Operations 1. 2. 3. 4. Several classes of operations are required in order to effectively used ADT. Constructors – used to create instances of the data type. Destructors – used to destroy an instance of the data type Accessors – used to access attributes of the data type. (Such as “get” functions) Modifiers – used to modify attributes of the data type. (Such as “set” functions) Object-oriented languages provide some of this functionality within the language. In C you must do it yourself. Dale Roberts

Fraction ADT Specification The specification for the Fraction ADT requires a discussion of what

Fraction ADT Specification The specification for the Fraction ADT requires a discussion of what operations are required. Constructors: Fraction() creates a new variable of type Fraction with the default value of 0/1. Fraction(int n, int d) creates a new variable of type Fraction with the default value of n/d. Note that you need to handle all combinations of positive and negative for n and d in order to determine the sign of the fraction. Dale Roberts

Fraction ADT (Cont) Destructors: ~Fraction() – frees Fraction variable. Copy: Fraction g = f;

Fraction ADT (Cont) Destructors: ~Fraction() – frees Fraction variable. Copy: Fraction g = f; – creates a new Fraction g, whose values are copied from f. C++ provides a default copy constructor, or you may write your own: Fraction(const Fraction &) You don’t need to provide you own Accessors: copy constructor if you don’t use new. i = f. get. Numerator(); i = f. get. Denominator(); c = f. get. Sign(); Dale Roberts

Fraction ADT (cont) Modifiers: f. reduce. Fract() – reduces a fraction to lowest terms.

Fraction ADT (cont) Modifiers: f. reduce. Fract() – reduces a fraction to lowest terms. Notice that this is a modifier, and cannot be used in an expression. set. Numerator(int); set. Denominator(int); set. Sign(char); Dale Roberts

Fraction ADT Operations These Operations are designed to be used in an expression. They

Fraction ADT Operations These Operations are designed to be used in an expression. They never modify their arguments. They always return type Fraction. f = Fraction: : negate. Fract(f) // returns -f s = Fraction: : add. Fract(f 1, f 2) // returns f 1 + f 2 d = Fraction: : sub. Fract(f 1, f 2) // returns f 1 – f 2 p = Fraction: : mul. Fract(f 1, f 2) // returns f 1 * f 2 q = Fraction: : div. Fract(f 1, f 2) // returns f 1 / f 2 i = Fraction: : compare. Fract(f 1, f 2) // f 1 < f 2 returns -1, // f 1 = f 2 returns 0, // f 1 > f 2 returns 1 Dale Roberts

Fraction ADT I/O Input/Output: Fraction: : get. Fract(istream, f) – return 1 if OK,

Fraction ADT I/O Input/Output: Fraction: : get. Fract(istream, f) – return 1 if OK, 0 if invalid, EOF if end of file. int Fraction: : put. Fract(ostream, f) – writes out fractions with correct sign, does not print denominator if 1 Dale Roberts

Design While we’ve defined an ADT interface, we can’t just start coding quite yet.

Design While we’ve defined an ADT interface, we can’t just start coding quite yet. There are more design decisions to be made before writing code for the implementation. A common error among programmers is to not place enough emphasis on the design step. This is the difference between a “programmer” and an “analyst”. Dale Roberts

Fraction ADT Design: Data-centric analysis begins with the idea that all the operations will

Fraction ADT Design: Data-centric analysis begins with the idea that all the operations will be acting on Fractions that have some internal representation. The representation shall be shared among all the operations. Each operation is responsible for maintaining your design rules regarding the representation of Fraction information. typedef enum{ POS, NEG } Sign. Type; class Fraction { private: // data members int numerator; /* numerator and denominator are declared as */ int denominator; /* int to simplify the algorithms, but they */ Sign. Type sign; /* will always be stored >= 0 */ public: // member functions would follow private: // utility functions would follow }; All operations must preserve these rules. Dale Roberts

Fraction ADT Variables Now that we’ve decided how to represent the value of a

Fraction ADT Variables Now that we’ve decided how to represent the value of a fraction, how are we going to declare variables whose values are fractions? Fraction f 1, f 2; Dale Roberts

Fraction ADT Algorithms You are responsible for designing algorithms that implement all the operations.

Fraction ADT Algorithms You are responsible for designing algorithms that implement all the operations. What process must you follow to implement the operations? a c ad + bc Sum: + = b d bd Product: a c ac * = b d bd then, reduce Subtraction involves adding the opposite, and Division involves multiplying by the reciprocal. Dale Roberts

Fraction ADT Algorithms Reducing a fraction involves finding the Greatest Common Divisor, and then

Fraction ADT Algorithms Reducing a fraction involves finding the Greatest Common Divisor, and then dividing all the terms by that amount. Euclid’s Algorithm: if x < y, then swap x and y While y is not zero remainder = x mod y x=y y = remainder When you’re done, x is the GCD. Dale Roberts

Fraction ADT Design Issues There are three special situations that require special handling. Negative

Fraction ADT Design Issues There are three special situations that require special handling. Negative fraction have sign = NEG. However, arithmetic expects the sign to be in the numerator. We’ll need to move back and forth between “arithmetic” representation of the sign and “standard”. 2. Fractions may not have zero in the denominator. Dividing by zero is not allowed, even though 0/1 is valid. 3. Different values of zero will not reduce using reduce. Fract(). Special coding is required to reduce 0/5 to 0/1. 1. Dale Roberts

ADT Specification In C++, the ADT Specification resides in a header file, names like

ADT Specification In C++, the ADT Specification resides in a header file, names like fraction. h. /**** Constructors, Destructors, and Clone *****/ Fraction(); /* returns 0/1 */ Fraction( int n, int d ); /* returns n/d */ // void ~Fraction( Fraction f ); Implementation not needed // Fraction(const Fraction &); Implementation not needed Dale Roberts

Accessors /****** Accessors *******/ int get. Numerator(); int get. Denominator(); char get. Sign(); Dale

Accessors /****** Accessors *******/ int get. Numerator(); int get. Denominator(); char get. Sign(); Dale Roberts

Modifiers /***** Modifiers ******/ void set. Numerator(int); void set. Denominator(int); void set. Sign(char); void

Modifiers /***** Modifiers ******/ void set. Numerator(int); void set. Denominator(int); void set. Sign(char); void reduce. Fract(); Dale Roberts

Operations /**** Fraction Operations *****/ static Fraction negate. Fract( const Fraction &f 1); static

Operations /**** Fraction Operations *****/ static Fraction negate. Fract( const Fraction &f 1); static Fraction add. Fract( const Fraction &f 1, const Fraction &f 2 ); static Fraction sub. Fract( const Fraction &f 1, const Fraction &f 2 ); static Fraction mul. Fract( const Fraction &f 1, const Fraction &f 2 ); static Fraction div. Fract( const Fraction &f 1, const Fraction &f 2 ); static int compare. Fract( const Fraction &f 1, const Fraction &f 2 ); /* returns -1 if f 1 < f 2 0 if f 1 == f 2 +1 if f 1 > f 2 */ Dale Roberts

Input/Output /********** I/O **********/ static int get. Fract( istream &infile, Fraction &f); /* returns

Input/Output /********** I/O **********/ static int get. Fract( istream &infile, Fraction &f); /* returns 1 if a valid fraction is read 0 if an invalid fraction is read EOF if end of file is detected */ static void put. Fract( ostream &outfile, const Fraction &f ); Dale Roberts

Allowing for multiple #includes #ifndef FRACTION_H #define FRACTION_H #include <iostream> … #endif Dale Roberts

Allowing for multiple #includes #ifndef FRACTION_H #define FRACTION_H #include <iostream> … #endif Dale Roberts

Sample Client - Declarations #include <iostream> #include "fraction. h" #include "boolean. h" using std:

Sample Client - Declarations #include <iostream> #include "fraction. h" #include "boolean. h" using std: : cout; using std: : endl; int main() { Fraction f, g, half(1, 2), sum, diff, prod, quotient, neg, answer; Boolean done = FALSE; int read. Result, cmp. Result; . . . code would follow } Dale Roberts

Sample Client – Creating Fractions cout << "Enter your first fraction > "; read.

Sample Client – Creating Fractions cout << "Enter your first fraction > "; read. Result = Fraction: : get. Fract( cin, f ); if (read. Result == 0 ) { cout << "Error entering fraction" << endl; } else if ( f. get. Numerator() == 9999 ) { done = TRUE; } else { cout << "Enter another fraction > "; read. Result = Fraction: : get. Fract(cin, g); if ( read. Result == 0 ) { cout << "Error enterering fraction" << endl; } else { // Perform Calculations Dale Roberts

Sample Client – Manipulating Fractions // Perform Calculations neg = Fraction: : negate. Fract(f);

Sample Client – Manipulating Fractions // Perform Calculations neg = Fraction: : negate. Fract(f); sum = Fraction: : add. Fract(f, g); diff = Fraction: : sub. Fract(f, g); prod = Fraction: : mul. Fract(f, g); quotient = Fraction: : div. Fract(f, g); cmp. Result = Fraction: : compare. Fract( f, g ); /* (f + g) - ( f * -(1/2) ) */ answer = Fraction: : sub. Fract( Fraction: : add. Fract( f, g ), Fraction: : mul. Fract( f, Fraction: : negate. Fract(half))); Dale Roberts

Sample Client – Displaying Output /* Display output */ cout << endl; cout <<

Sample Client – Displaying Output /* Display output */ cout << endl; cout << "F 1 = "; Fraction: : put. Fract(cout, f); cout << endl; cout << "F 2 = "; Fraction: : put. Fract(cout, g); cout << endl; cout << "Neg = "; Fraction: : put. Fract(cout, neg); cout << endl; cout << "Sum = "; Fraction: : put. Fract(cout, sum); cout << " Diff = "; Fraction: : put. Fract(cout, diff); cout << " Prod = "; Fraction: : put. Fract(cout, prod); cout << " Quot = "; Fraction: : put. Fract(cout, quotient); cout << endl; if ( cmp. Result == 0 ) cout << "equal" << endl; else if (cmp. Result < 0 ) cout << "less" << endl; else cout << "Greater" << endl; cout << "Try one nested: " << endl; out << "(f + g) - ( f * -(1/2) ) = "; Fraction: : put. Fract(cout, answer); cout << endl; cout << "=====================" << endl; Dale Roberts

Sample Client – Clean Up Unlike C, there is no requirement for cleanup when

Sample Client – Clean Up Unlike C, there is no requirement for cleanup when dealing with the Fractions. When Fractions go out of scope, they are automatically destroyed. There is no need to create and call a free. Fract() function. Creating a Fraction does not require explicit use of a pointer or malloc(). You create a Fraction on the stack simply by declaring a Fraction variable. Using “new” to allocate a fraction on the heap is not required. int function(int x, y) Fraction function(Fraction x, y) { { int z; Fraction z; z = x+y; z = fraction: : addfract(x, y); return z; } // return is pass-by-value (copy) Dale Roberts

Sample Execution To To of enter a fraction enter two integers separated by one

Sample Execution To To of enter a fraction enter two integers separated by one space. indicate end of data enter 9999 for the numerator the first fraction. Use any denominator. Enter your first fraction > 5 6 Enter another fraction > 3 4 F 1 = 5/6 F 2 = 3/4 Neg = -5/6 Sum = 19/12 Diff = 1/12 Prod = 5/8 Greater Try one nested: (f + g) - ( f * -(1/2) ) = 2 Quot = 10/9 Dale Roberts

Acknowledgements The specification for this Fraction ADT comes from Fecteau & Kirchherr. The implementation

Acknowledgements The specification for this Fraction ADT comes from Fecteau & Kirchherr. The implementation is my own. Dale Roberts