Title: Fraction ADT in C++
1Department of Computer and Information
Science,School of Science, IUPUI
CSCI 265
Fraction Abstract Data Type
Dale Roberts, Lecturer Computer Science,
IUPUI E-mail droberts_at_cs.iupui.edu
2Abstract 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 - The public interface, or specification, defines
the ADT and how it is used. - The implementation, implements the ADT in code.
- The client uses the ADT to perform a task.
3Defining an ADT
- Within C, you define an ADTs public interface
with a header file. - include fraction.hmain() Fraction x, y
- User-defined ADTs are typically capitalized to
distinguish them from intrinsic data types.
4ADT Operations
- 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.
5Fraction 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.
6Fraction ADT (Cont)
- Destructors
- fraction(f) frees Fraction variable f.
- 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 ) - Accessors
- i f.getNumerator()
- i f.getDenominator()
- c f.getSign()
You dont need to provide you own copy
constructor if you dont use new.
7Fraction ADT (cont)
- Modifiers
- f.reduceFract() reduces a fraction to lowest
terms. Notice that this is a modifier, and
cannot be used in an expression. - setNumerator(int)
- setDenominator(int)
- setSign(char)
8Fraction ADT Operations
- These Operations are designed to be used in an
expression. They never modify their arguments.
They always return type Fraction. - f FractionnegateFract(f) // returns -f
- s FractionaddFract(f1,f2) // returns f1 f2
- d FractionsubFract(f1,f2) // returns f1 f2
- p FractionmulFract(f1,f2) // returns f1 f2
- q FractiondivFract(f1,f2) // returns f1 / f2
- i FractioncompareFract(f1,f2) // f1 lt f2
returns -1, // f1 f2 returns 0, // f1 gt f2
returns 1
9Fraction ADT I/O
- Input/Output
- Fraction FractiongetFract(istream, f) return
1 if OK, 0 if invalid, EOF if end of file. - int FractionputFract(ostream, f) writes out
fractions with correct sign, does not print
denominator if 1
10Design
- While weve defined an ADT interface, we cant
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.
11Fraction ADT Design Data
- 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 SignType
- class Fraction
- private
- // data members
- int numerator / numerator and denominator
are declared as / - int denominator / int to simplify the
algorithms, but they / - SignType sign / will always be stored gt
0 / - public
- // member functions would follow
- private
- // utility functions would follow
-
- All operations must preserve these
rules.
12Fraction ADT Variables
- Now that weve decided how to represent the value
of a fraction, how are we going to declare
variables whose values are fractions? - Fraction f1, f2
13Fraction ADT Algorithms
- You are responsible for designing algorithms that
implement all the operations. What process must
you follow to implement the operations?
then, reduce
then, reduce
Subtraction involves adding the opposite, and
Division involves multiplying by the reciprocal.
14Fraction ADT Algorithms
- Reducing a fraction involves finding the Greatest
Common Factor, and then dividing all the terms by
that amount. - Euclids Algorithm
- if x lt y, then swap x and y
- While y is not zero
- remainder x mod y
- x y
- y remainder
- When youre done, x is the GCF.
15Fraction 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. Well need to move back and forth
between arithmetic representation of the sign
and standard. - Fractions may not have zero in the denominator.
Dividing by zero is not allowed, even though 0/1
is valid. - Different values of zero will not reduce using
reduceFract(). Special coding is required to
reduce 0/5 to 0/1.
16ADT Specification
- In C, the ADT Specification resides in a header
file, names like fraction.h.
/ Constructors, Destructors, and Clone
/ Fraction Fraction() / returns 0/1
/ Fraction Fraction( int n, int d ) / returns
n/d / // void Fraction( Fraction f )
Implementation not needed // Fraction(const
Fraction ) Implementation not needed
17Accessors
- / Accessors /
- int getNumerator()
- int getDenominator()
- char getSign()
18Modifiers
- / Modifiers /
- void setNumerator(int)
- void setDenominator(int)
- void setSign(char)
- void reduceFract()
19Operations
- / Fraction Operations /
- static Fraction negateFract( const Fraction f1)
- static Fraction addFract(
- const Fraction f1, const Fraction f2 )
- static Fraction subFract(
- const Fraction f1, const Fraction f2 )
- static Fraction mulFract(
- const Fraction f1, const Fraction f2 )
- static Fraction divFract(
- const Fraction f1, const Fraction f2 )
- static int compareFract(
- const Fraction f1, const Fraction f2 )
- / returns -1 if f1 lt f2
- 0 if f1 f2
- 1 if f1 gt f2
- /
20Input/Output
- / I/O /
- static int getFract(
- 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 putFract(
- ostream outfile, const Fraction f )
21Allowing for multiple includes
- ifndef FRACTION_H
- define FRACTION_H
- include ltiostreamgt
- include "boolean.h"
-
- endif
22Sample Client - Declarations
- include ltiostreamgt
- include "fraction.h"
- include "boolean.h"
- using stdcout
- using stdendl
- int main()
-
- Fraction f, g, half(1,2), sum, diff, prod,
- quotient, neg, answer
- Boolean done FALSE
- int readResult, cmpResult
- ... code would follow
-
23Sample Client Creating Fractions
- cout ltlt "Enter your first fraction gt "
- readResult FractiongetFract( cin, f )
- if (readResult 0 )
-
- cout ltlt "Error entering fraction" ltlt endl
-
- else if ( f.getNumerator() 9999 )
-
- done TRUE
-
- else
-
- cout ltlt "Enter another fraction gt "
- readResult FractiongetFract(cin, g)
- if ( readResult 0 )
-
- cout ltlt "Error enterering fraction" ltlt
endl -
- else
24Sample Client Manipulating Fractions
- // Perform Calculations
- neg FractionnegateFract(f)
- sum FractionaddFract(f,g)
- diff FractionsubFract(f,g)
- prod FractionmulFract(f,g)
- quotient FractiondivFract(f,g)
- cmpResult FractioncompareFract( f, g )
- / (f g) - ( f -(1/2) ) /
- answer FractionsubFract(
FractionaddFract( f,g ),
FractionmulFract( - f,FractionnegateFract(half)))
25Sample Client Displaying Output
- / Display output /
- cout ltlt endl
- cout ltlt "F1 " FractionputFract(cout, f)
cout ltlt endl - cout ltlt "F2 " FractionputFract(cout, g)
cout ltlt endl - cout ltlt "Neg " FractionputFract(cout,neg)
cout ltlt endl - cout ltlt "Sum " FractionputFract(cout,sum)
- cout ltlt " Diff " FractionputFract(cout,diff)
- cout ltlt " Prod " FractionputFract(cout,prod)
- cout ltlt " Quot " FractionputFract(cout,quoti
ent) cout ltlt endl - if ( cmpResult 0 )
- cout ltlt "equal" ltlt endl
- else if (cmpResult lt 0 )
- cout ltlt "less" ltlt endl
- else
- cout ltlt "Greater" ltlt endl
- cout ltlt "Try one nested " ltlt endl
- out ltlt "(f g) - ( f -(1/2) ) "
- FractionputFract(cout,answer) cout ltlt endl
- cout ltlt "
" ltlt endl
26Sample 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 freeFract() function. - Creating a Fraction does not require explicit use
of a pointer or malloc(). You create a Fraction
simply by declaring a Fraction variable. Even
using new is not required.
int function(int x, y) int z z xy
return z // return is pass-by-value (copy)
Fraction function(Fraction x, y) Fraction
z z fractionaddfract(x,y) return
z // return is pass-by-value (copy)
27Sample Execution
- To enter a fraction enter two integers separated
by one space. - To indicate end of data enter 9999 for the
numerator - of the first fraction. Use any denominator.
- Enter your first fraction gt 5 6
- Enter another fraction gt 3 4
- F1 5/6
- F2 3/4
- Neg -5/6
- Sum 19/12 Diff 1/12 Prod 5/8 Quot 10/9
- Greater
- Try one nested
- (f g) - ( f -(1/2) ) 2
28Acknowledgements
- The specification for this Fraction ADT comes
from Fecteau Kirchherr. - The implementation is my own.