Thread: Fraction Class

  1. #1
    Registered User
    Join Date
    Jul 2013
    Posts
    6

    Fraction Class

    Assignment:
    Design a fraction class.

    A fraction is a number made up of a numerator and a denominator. Design a class to implement this.

    Obviously we’d like to be able to use the normal operators for mathematical operations (+,-,*, /), comparison operations(==, !=, and <), incrementation, decrementation, input and output.

    We don’t need to worry about reducing the fraction. In other words, 4/2 is fine, there’s no need to runt hat into 2/1.

    Incrementation and decrementation should add or subtract (as appropriate) 1/1 to the object. Input is in the form of “num denom”. Output is in the form “num/denom”

    Code:
    #include <iostream>
    #include <string>
    using namespace std;
    
    
    class fraction {
    private:
        int numerator;
        int denominator;
    
    
    public:
        int getNum() {return numerator;}
        int getDenom() {return denominator;}
        fraction();
        fraction(int,int);
        //fraction(int num = 1, int denom = 1):numerator(num), denominator(denom) {}
        fraction operator+(fraction);
        fraction operator-(fraction);
        fraction operator*(fraction);
        fraction operator/(fraction);
        fraction& operator++();
        fraction& operator--();
        bool operator==(fraction);
        bool operator!=(fraction);
        bool operator<(fraction);
        friend ostream& operator<<(ostream &out, const fraction& value);
        friend istream& operator>>(istream &in, fraction& value);
        string print();
    };
    
    
    fraction::fraction(int num, int denom){
        numerator = num;
        denominator = denom;
    }
    
    
    fraction fraction::operator+(fraction Frac){
        if(numerator == 0 || Frac.getNum() == 0){
            if (numerator != 0){
                return fraction(numerator,denominator);
            }
            else{
            return fraction(Frac.getNum(),Frac.getDenom());
            }
        }
        else{ 
            return fraction((numerator*Frac.getDenom()) + (denominator*Frac.getNum()), denominator*Frac.getDenom());
            }
        
    }
    
    
    fraction fraction::operator-(fraction Frac){
        if(numerator == 0 || Frac.getNum() == 0){
            if (numerator != 0){
                return fraction(numerator,denominator);
            }
            else{
            return fraction(Frac.getNum(),Frac.getDenom());
            }
        }
        else{ 
            return fraction((numerator*Frac.getDenom()) - (denominator*Frac.getNum()), denominator*Frac.getDenom());
            }
        
    }
    
    
    fraction fraction::operator*(fraction Frac){
        return fraction((Frac.getNum()*numerator), (Frac.getDenom()*denominator));
    }
    
    
    fraction fraction::operator/(fraction Frac){
        return fraction((Frac.getNum()*denominator), (Frac.getDenom()*numerator));
    }
    
    
    bool fraction::operator==(fraction Frac){
    return((Frac.getNum() == numerator) && (Frac.getDenom() == denominator));
    }
    
    
    bool fraction::operator!=(fraction Frac){
    return((Frac.getNum() != numerator) || (Frac.getDenom() != denominator));
    }
    
    
    bool fraction::operator<(fraction Frac){
    double first, second;
        if(denominator != 0){
            first = numerator/ (double) denominator;
        }
        else{
            first = 0.0;
        }
        if(Frac.getDenom() != 0){
            second = Frac.getNum()/ (double) Frac.getDenom();
        }
        else{
            second = 0.0;
        }
        return(first < second);
    }
    
    
    fraction& fraction::operator++(){
        if(denominator != 0){
            numerator += denominator;
            return *this;
        }
        else{
            cout<< "Enter a proper fraction!";
        }
    
    
    }
    
    
    fraction& fraction::operator--(){
        if(denominator != 0){
            numerator -= denominator;
            return *this;
        }
        else{
            cout<< "Enter a proper fraction!";
        }
    
    
    }
    
    
    ostream &operator<<(ostream& out, const fraction& value){
        out<< value.numerator<<"/"<<value.denominator;
        return out;
    }
    
    
    istream& operator>>(istream &in, fraction& value){
        int num, denom;
        in>>num>>denom;
        value = fraction(num, denom);
        return in;
    }
    
    
    int main(){
        int Num2, Denom2;
        fraction f1,f2;
    
    
        cout<< "Enter the first numerator: ";
        cin>> Num2;
        cout<< "Enter the first denominator: ";
        cin>> Denom2;
        f1(Num2,Denom2);
        cout<<"The first fraction is: "<<f1.print()<<endl;
    
    
        cout<< "Enter the second numerator: ";
        cin>> Num2;
        cout<< "Enter the second denominator: ";
        cin>> Denom2;
        f2(Num2,Denom2);
        cout<<"The second fraction is: "<<f1.print()<<endl;
    
    
        cout<<"The following operations were performed:"<<endl;
    
    
        fraction f3 = f1 + f2;
        cout<<"Addition: "<<f1.print() << " + " << f2.print() << " = " << f3.print()<<endl;
    
    
        f3 = f1 - f2;
        cout<<"Subtraction: "<<f1.print() << " - " << f2.print() << " = " << f3.print()<<endl;
    
    
        f3 = f1 * f2;
        cout<<"Multiplication: "<<f1.print() << " * " << f2.print() << " = " << f3.print()<<endl;
    
    
        f3 = f1 / f2;
        cout<<"Division: "<<f1.print() << " ÷ " << f2.print() << " = " << f3.print()<<endl;
    
    
        ++f1;
        cout<<"Incrementation: "<<f1.print() << " ++ " << " = " << f1.print()<<endl;
    
    
        --f2;
        cout<<"Decrementation: "<<f2.print() << " -- " << " = " << f2.print()<<endl;
    
    
    }
    I keep getting an error: error C2064: term does not evaluate to a function taking 2 arguments.
    This is in reference to line 158 and 166
    Any ideas on what I'm doing wrong? Does the code make sense in general?
    Last edited by pochta; 07-07-2013 at 08:57 PM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Looking at:
    Code:
    f1(Num2,Denom2);
    My guess is that you want to create f1 by calling its constructor with the two arguments. If so, you should write:
    Code:
    fraction f1(Num2,Denom2);
    In fact, variables should be declared near first use, so doing this is good practice. The same goes for f2.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Jul 2013
    Posts
    6
    That got rid of those two errors but gave me two new ones, and two warnings:

    Warning 1 warning C4715: 'fraction:: operator++' : not all control paths return a value
    Warning 2 warning C4715: 'fraction:: operator--' : not all control paths return a value
    Error 3 error LNK2019: unresolved external symbol "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall fraction:rint(void)" (?print@fraction@@QAE?AV?$basic_string@DU?$char_tr aits@D@std@@V?$allocator@D@2@@std@@XZ) referenced in function _main
    And...

    Error 4 error LNK1120: 1 unresolved externals

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    The warnings about "not all control paths return a value" just means that there is a condition in which the function has no return statement that will be executed, yet it is declared as returning a value. In this case, an appropriate solution is to throw an exception instead of just printing an error message.

    As for the error: you did not implement the print member function yet you called it several times. In fact, since you overloaded operator<< you don't need the print member function to begin with.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Jul 2013
    Posts
    6
    Okay, it works. Thank you!!

  6. #6
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    You may have fixed the compiler errors, but you have several other issues, including but not limited to:

    Not implementing both pre and post increment / decrement.
    Lack of const-correctness.
    having cout statements inside the increment/decrement. (Consider exceptions instead)
    With the absense of reducing the fraction, you should be doing some extra work to ensure that the fractions 4/2 and 2/1 compare equal, for example.
    The far better way to implement operator less-than is to rearrange the use of division into a multiplication.
    Operator >> does not mirror operator << (it does not skip the slash).
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  7. #7
    Registered User
    Join Date
    Jul 2013
    Posts
    6
    Quote Originally Posted by iMalc View Post
    You may have fixed the compiler errors, but you have several other issues, including but not limited to:

    Not implementing both pre and post increment / decrement.
    Lack of const-correctness.
    having cout statements inside the increment/decrement. (Consider exceptions instead)
    With the absense of reducing the fraction, you should be doing some extra work to ensure that the fractions 4/2 and 2/1 compare equal, for example.
    The far better way to implement operator less-than is to rearrange the use of division into a multiplication.
    Operator >> does not mirror operator << (it does not skip the slash).
    I only wrote the pre increment/decrement operators because the assignment did not explicitly state to implement post. I dont quite understand what you're talking about in reference to the "<" operator. Thank you for the advice!

  8. #8
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    (a/b < c/d)
    will be the same as

    (a*d < c*b)

    but the second expression is quicker
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  9. #9
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by vart View Post
    (a/b < c/d)
    will be the same as

    (a*d < c*b)

    but the second expression is quicker
    Yes, and it avoids the need to test for zero demoninators first since it cant divide by zero. Pretty much turns it into a one-liner.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by iMalc View Post
    Yes, and it avoids the need to test for zero denominators first since it cant divide by zero. Pretty much turns it into a one-liner.
    Oh one word of warning with this, you may need to enforce the strict policy that the denominator can never be negative, though oviously the numerator can. So 1 / -2 must always be stored as -1 / 2.

    Further hint: The same multiplication instead of division change also solves your equality and inequality issues.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  12. #12
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    having cout statements inside the increment/decrement. (Consider exceptions instead)
    O_o

    If he wishes his class to consider a denominator of zero to be an error, entirely reasonable, he shouldn't allow an instance of the fraction class to exist which has a zero denominator in the first place.

    This check should be in the constructor/stream operators signalling, preferably, with an exception and setting `ios' flags.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  13. #13
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Once all of this is basically working, you may consider reducing the fraction produced by an operator by the greatest common divisor. The Euclid method would probably easiest to implement. Wiki article:

    Euclidean algorithm - Wikipedia, the free encyclopedia

  14. #14
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by phantomotap View Post
    O_o

    If he wishes his class to consider a denominator of zero to be an error, entirely reasonable, he shouldn't allow an instance of the fraction class to exist which has a zero denominator in the first place.

    This check should be in the constructor/stream operators signalling, preferably, with an exception and setting `ios' flags.

    Soma
    Yes that is certainly the better option.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. class Fraction Operator
    By jeroconde in forum C++ Programming
    Replies: 17
    Last Post: 07-31-2011, 08:31 PM
  2. Replies: 18
    Last Post: 03-26-2008, 09:01 AM
  3. Help with methods of a fraction class
    By NebulousMenace in forum C++ Programming
    Replies: 10
    Last Post: 04-02-2003, 12:36 AM
  4. fraction help
    By abrege in forum C++ Programming
    Replies: 4
    Last Post: 12-12-2002, 05:44 PM
  5. Help with Fraction class
    By cheeisme123 in forum C++ Programming
    Replies: 0
    Last Post: 06-04-2002, 07:48 AM