Presentation is loading. Please wait.

Presentation is loading. Please wait.

Case Study - Fractions Timothy Budd Oregon State University.

Similar presentations


Presentation on theme: "Case Study - Fractions Timothy Budd Oregon State University."— Presentation transcript:

1 Case Study - Fractions Timothy Budd Oregon State University

2 2 Objectives To easily create new instances of the rational number abstraction. To manipulate rational numbers using arithmetic operations, yielding new rational number results. It should be possible to mix rationals and other arithmetic quantities in the same expression. It should be possible to assign a rational number value to a rational number variable. The modification forms of assignment should be supported. To compare one rational number to another. It should be possible to perform input and output operations with rational numbers.

3 3 Example of Rational Numbers // probability one is 1 in 8 rational p1 (1,8); // probability two is 2 in 3 rational p2 (2, 3); // probably of both together is their product rational p3 = p1 * p2; // probably of either independent is their sum rational p4 = p1 + p2; // what is this probability? cout << "combined probability is " << p3 << endl; cout << "independent probability is " << p4 << endl

4 4 Definition of Operations on Rational Numbers

5 5 //class rational //rational number data abstraction class rational { public: // constructors rational () : top(0), bottom(1) { } rational (int t) : top(t), bottom(1) { } rational (int t, int b) : top(t), bottom(b) { normalize(); } rational (const rational & r) : top(r.top), bottom(r.bottom) { } // accesser functions int numerator () const { return top; } int denominator () const { return bottom; } // assignments void operator = (const rational & r) {top = r.top; bottom = r.bottom;} void operator += (const rational &); // other operations operator double () const { return top / (double) bottom; } const rational & operator++() { top += bottom; return this; } const rational operator++(int); private: int top; // data areas int bottom; void normalize (); // operation used internally };

6 6 Interface and Implementation The code associated with a component is separated into two files. –The interface file describes how to use the component. –The implementation file contains the actual code to perform the actions. The class description is divided into two parts. –Public: behaviors and data fields that users of the data abstraction can access. –Private: behavior and fields that are accessible only within the component and are off-limits to other users.

7 7 Constructors Every class should define a default constructor. Use initializes whenever possible. The declaration that uses an empty parentheses list is not syntactically incorrect; simply not doing what the programmer expects. Every class should define a copy constructor.

8 8 Member Function An accessor function provides access to the internal state of an object. left.numerator() * right.denominator() + right.numerator() * left.denominator() A function defined as part of the behavior of a class is called a member function. The const keyword in C++ is not the same as the final keyword in Java.

9 9 Operators In C++, operators can potentially have overloaded meanings. Requirement: the definition must not require arguments that match any existing definition. Can be achieved if one or both arguments are a new data type, since no existing definition can be using these types.

10 10 Operators const rational operator + (const rational & left, const rational & right) { // return sum of two rational numbers rational result ( left.numerator() * right.denominator() + right.numerator() * left.denominator(), left.denominator() * right.denominator()); return result; } The address operator in the argument list indicates that the left and right values will be passed by reference.

11 11 Operators A list of prototypes for the arithmetic operations. // prototypes for arithmetic operations, including unary negation const rational operator + (const rational &, const rational &); const rational operator - (const rational &, const rational &); const rational operator * (const rational &, const rational &); const rational operator / (const rational &, const rational &); const rational operator - (const rational &); bool operator < (const rational &, const rational &); bool operator == (const rational &, const rational &);

12 12 Unary Negation Operator const rational operator - (const rational & val) { // return negation of argument value return rational (- val.numerator(), val.denominator()); }

13 13 Comparison Operators bool operator < (const rational & left, const rational & right) { // less than comparison of two rational numbers return left.numerator() * right.denominator() < right.numerator() * left.denominator(); } bool operator == (const rational & left, const rational & right) { return left.numerator() * right.denominator() == right.numerator() * left.denominator(); }

14 14 Increment and Decrement The variable this is a value in Java but is a pointer in C++. class rational {... const rational & operator ++ () { top += bottom; return *this;}... }; const rational rational::operator++ (int) { // increment fraction, but return original value, make clone rational clone(*this); top += bottom; // make change return clone; // return clone }

15 15 Functions Functions cannot access the internal (private) structure of any class, unless declared as a friend. const rational abs (const rational & num) { // return the absolute value of a rational number int newtop; int newbottom = num.denominator(); // get non-negative numerator part if (num.numerator() < 0) newtop = - num.numerator(); else newtop = num.numerator(); // create and return result return rational(newtop, newbottom); }

16 16 Member Function Operators void rational::operator += (const rational & right) { // modify by adding right hand side top = top * right.denominator() + bottom * right.numerator(); bottom *= right.denominator(); // normalize the result, ensuring lowest denominator form normalize(); }

17 17 void rational::normalize() { // normalize rational by (a) moving sign to numerator : // b) making sure numerator and denominator have no common divisors int sign = 1;// sign is 1 if non-negative, -1 if negative if (top < 0) { sign = -1; top = - top; } if (bottom < 0) { sign = - sign; bottom = - bottom; } // make sure we are not dividing by zero if (bottom == 0) throw range_error("fraction with zero numerator"); // find greatest common divisor int d = gcd(top, bottom); // move sign to top and divide by gcd top = sign * (top / d); bottom = bottom / d; }

18 18 Member Function Operators try {... // computation involving rationals } catch (range_error & e) { printf("got exception %s", e.what()); }

19 19 Conversion Operations Constuctors are also used implicitly. rational x, y;... x = y * 3; Temporary values can also be created directly by the programmer, by invoking the constructor as if it were an ordinary function. x = y * rational(3, 4);

20 20 Conversion Operations Conversions the other direction, from an object type to another type, are defined using a conversion operator. A conversion operator is an operator whose name is a type. class rational {... operator double () const { return top / (double) bottom; } };

21 21 Conversion Operations Avoid cast if possible, but if unavoidable use a static or dynamic cast. rational x(3, 4); cout << "3/4 of pi is " << (3.14 * double(x)) << '\n';

22 22 Input and Output Streams Output is easily accommodated by redefining the left shift operator <<, and providing a new meaning. ostream & operator << (ostream & out, const rational & value) { // print representation of rational number on // an output stream out << value.numerator() << '/' << value.denominator(); return out; }

23 23 Input and Output Streams Predefined precedence is low enough to allow arithmetic expressions to appear in output without using parenthesis, as in: cout << "a + b * c is " << a + b * c << '\n'; The left shift operator with its conventional meaning can be used in an output statement, by surrounding it with parenthesis: cout << " a left shift by 3 is " << (a << 3) << '\n';

24 24 Stream Input A loop that would read values repeatedly from the input until end of file could be written as: while (cin >> intval) { // process intval... } // reach this point on end of input... An easy way to remember, the stream I/O operations is to visualize them as arrows. The input operator, >> x, points data into x, while the output operator, << x, copies data out of x.

25 25 istream & operator >> (istream & in, rational & r) { // read a rational number from an input stream int t, b; // read the top in >> t; // if there is a slash, read the next number char c; in >> c; if (c == '/') in >> b;// read bottom part else { in.putback(c); b = 1; } // do the assignment rational newValue(t, b); r = newValue; // return the stream return in; }


Download ppt "Case Study - Fractions Timothy Budd Oregon State University."

Similar presentations


Ads by Google