0

i need to write a program to calculate fractions, here is my header file:

#ifndef FRACTION_H
#define FRACTION_H
#include <iostream>
#include <string>
using namespace std;

class Fraction {

    private:
        int *numer;
        int *denom;
        int gcd(int, int);
    public:
        void reduce();
        int getNum();
        int getDen();
        Fraction();
        Fraction(int numerator);
        Fraction(int num, int den);
        Fraction(string s);  // take string parameter of the form of "numerator/defnominator
        Fraction(Fraction &other);  // copy constructor
        Fraction & operator=(Fraction & rhs);
        ~Fraction();
        // overloading arithematic operation
        Fraction & operator+ (Fraction & rhs);
        Fraction & operator- (Fraction & rhs);
        Fraction & operator* (Fraction & rhs);
        Fraction & operator/ (Fraction & rhs);
        bool operator > (Fraction & rhs);
        bool operator >= (Fraction & rhs);
        bool operator == (Fraction & rhs);
        bool operator < (Fraction & rhs);
        bool operator <= (Fraction & rhs);
        bool operator!=(Fraction & rhs);
        Fraction & operator++();
        Fraction & operator++(int);
        Fraction & operator--();
        Fraction & operator--(int);

        Fraction & operator+=(Fraction & rhs);
        Fraction & operator-=(Fraction & rhs);
        Fraction & operator*=(Fraction & rhs);
        Fraction & operator/=(Fraction & rhs);

        // Exponentiation 
        Fraction & operator^(int n);

        bool isZero();
        bool isProper();  // a fracton is proper if abs(numerator) < (denominator)
        bool isNegative();
        bool isPositive();

        operator string();
        operator double();

        string toString();
        string toProperString();   // properString format of 15/4   is  3 3/4

        friend ostream & operator <<  (ostream & out, Fraction & rhs);
        friend istream & operator >> (istream & in, Fraction &rhs);
};

#endif

for the Fraction.cpp file:

I have the function that converts the faction format to string, here's what i have, but not sure if it is correct. Here is what i got now:

#include <iostream>
#include<cmath>
#include <cassert>
#include <string>
#include<iomanip>
#include <stdlib.h>
#include "Fraction.h"
#include <sstream>

using namespace std;

Fraction::Fraction()
{
    numer = new int(0);
    denom = new int(1);
    //cout<<"construtor"<<endl;
}
int Fraction::getNum()
{
    return *numer;

}
int Fraction::getDen()
{
    return *denom;
}
int Fraction::gcd(int n, int d)      //moving sign to numerator
{
    //assert((n > 0 && d > 0));         //ensuring numerator and demominator have no common divisors 
    //while (n != d)                    // return the greatest common divisor 
    //{
    //  if (n < d)
    //      d = d - n;
    //  else
    //      n = n - d;
    //}
    //return n;
    if(n<0)
        n=-n;
    if(d<0)
        d=-d;
    if(n<d)
        return gcd(d,n);
    if(d==0)
        return n;
    return gcd(d,n%d);

}
Fraction::Fraction(int numerator)
{
    numer = new int(numerator);
    denom= new int (1);
    //printf("Fraction::Fraction(int numerator) \n");
}

Fraction::Fraction(int num, int den)
{
    assert (den != 0);

    numer = new int(num);
    denom = new int(den);
    reduce();

    //cout<<"reduce function"<<endl;
}
void Fraction::reduce()
{
    int sign = 1;
    if (*numer < 0)
    {
        sign = -1;
        *numer = -*numer;
    }
    if (*numer< 0)
    {
        sign = -1;
        *denom = -*denom;
    }
    assert(*denom != 0);
    int d = 1;
    if (*numer>0)
    {
        d= gcd(*numer, *denom);
        *numer = sign*(*numer / d);
        *denom = *denom / d;
    }
}

Fraction::Fraction(string s)
{
    string delimiter = "/";
    string n = s.substr(0, s.find(delimiter));
    string d=s.substr(s.find(delimiter)+1,s.length());

    numer = new int (atoi(n.c_str()));
    denom = new int(atoi(d.c_str()));   //every first time using pointer in constructor 
    cout << n << d << endl;
    //constructor 
}
Fraction::Fraction(Fraction &other)
{
    numer = new int( other.getNum());     
    denom = new int(other.getDen());
    //cout<<"copy construtor"<<endl;
}

Fraction::~Fraction()
{
    delete numer;
    numer = 0;           //if (numer) if(denom) 
    delete denom;
    denom = 0;
}

Fraction & Fraction::operator=(Fraction & rhs)
{  
    if (this != &rhs)
    {                          //do i need delete pointer here? 
        *numer = rhs.getNum();
        *denom = rhs.getDen();
    }
    else
        return *this;
}
Fraction & Fraction::operator+ (Fraction & rhs)
{
    Fraction *result = new Fraction(this->getNum()*rhs.getDen() + this->getDen()*rhs.getNum(), this->getDen()*rhs.getDen());
    result->reduce();
    return *result;
}

Fraction & Fraction::operator- (Fraction & rhs)
{
    Fraction *result=new Fraction((this->getNum()*rhs.getDen() - this->getDen()*rhs.getNum(), this->getDen()*rhs.getDen()));
    result->reduce();
    return *result;
}

Fraction & Fraction::operator*(Fraction & rhs)
{
    Fraction *result=new Fraction((this->getNum()*rhs.getNum(), this->getDen()*rhs.getDen()));
    result->reduce();
    return *result;

}

Fraction & Fraction::operator/(Fraction & rhs)
{
    Fraction *result=new Fraction((this->getNum()*rhs.getDen(), this->getDen()*rhs.getNum()));
    result->reduce();
    return *result;
}

bool Fraction::operator > (Fraction & rhs)
{
    if (((float)getNum() / getDen())>((float)rhs.getDen() / rhs.getNum()))
        return true;
    else
        return false;
}

bool Fraction::operator >= (Fraction & rhs)
{
    if (((float)getNum() / getDen()) >= ((float)rhs.getDen() / rhs.getNum()))
        return true;
    else
        return false;
}

bool Fraction::operator == (Fraction & rhs)
{
    if (getNum()*rhs.getDen() == getDen()*rhs.getNum())
        return true;
    else
        return false;

}
bool Fraction::operator < (Fraction & rhs)
{
    if (((float)getNum() / getDen())<((float)rhs.getDen() / rhs.getNum()))
        return true;
    else
        return false;
}
bool Fraction::operator <= (Fraction & rhs)
{
    if (((float)getNum() / getDen()) <= ((float)rhs.getDen() / rhs.getNum()))
        return true;
    else 
        return false;
}

bool Fraction::operator!=(Fraction & rhs)
{
    if (getNum()*rhs.getDen() == getDen()*rhs.getNum())
        return false;
    else
        return true;

}

Fraction & Fraction::operator++()  //pre fix 
{
    *numer += *denom;
    reduce();
    return *this;
}

Fraction & Fraction::operator++(int inInt)  //post fix
{

    Fraction *temp = new Fraction (*this);
    *numer += *denom;
    reduce();
    return *temp;

}

Fraction & Fraction::operator--()
{
    *numer -= *denom;
    reduce();
    return *this;
}

Fraction & Fraction::operator--(int)
{
    Fraction *temp = new Fraction(*this);
    *numer -= *denom;
    reduce();
    return *temp;
}

Fraction & Fraction::operator+=(Fraction & rhs)
{
    *numer = (*numer)*rhs.getDen() + (*denom)*rhs.getNum();
    *denom = (*denom)*rhs.getDen();
    reduce();
    return *this;

}
Fraction & Fraction::operator-=(Fraction & rhs)
{
    *numer = (*numer)*rhs.getDen() - (*denom)*rhs.getNum();
    *denom = (*denom)*rhs.getDen();
    reduce();
    return *this;
}
Fraction & Fraction::operator*=(Fraction & rhs)
{
    *numer=(*numer)*rhs.getNum();
    *denom=(*denom)*rhs.getDen();
    reduce();
    return *this;
}

Fraction & Fraction::operator/=(Fraction & rhs)
{
    *numer=(*numer)*rhs.getDen();
    *denom=(*denom)*rhs.getNum();
    reduce();
    return *this;

}

Fraction & Fraction::operator^(int n)
{
    *numer = (double)pow((float)*numer, n);

    *denom = (double)pow((float)*denom, n);
    reduce();
    return *this;
}

bool Fraction::isZero()
{
    return (*numer) == 0;
}

bool Fraction::isProper()
{
    if (abs(*numer)<abs(*denom))
        return true;
    else 
        return false; 
}

bool Fraction::isNegative()
{
    if (*numer<0)
        return true;
    else
        return false;
}

bool Fraction::isPositive()
{
    if (*numer>0)
        return true;
    else
        return false;
}

Fraction::operator string()
{
    return this->toString();
}
Fraction::operator double()
{
    return ((double)(*numer) / (*denom));
}

string Fraction::toString()
{
    char num[100], deom[100];
    char *s = new char[50];
    itoa(*numer, num, 10);
    itoa(*denom, deom, 10);

    char * delimiter = new char[2];
    delimiter[0] = '\/';
    delimiter[1] = '\0';   //stops copying delimiter 

    strcpy(s, num);
    strcat(s, delimiter);
    //  strcat(s,'\0');
    strcat(s, deom);
    //  strcat(s,'\0');

    return s;

}
string Fraction::toProperString()
{
    int a = *(this->numer) / *(this->denom);
    int num = *(this->numer) % *(this->denom);
    ostringstream ostr;
    ostr <<a << " " << num << "/" << *(this->denom);
    return ostr.str();

}

ostream & operator <<  (ostream & out, Fraction & rhs)
{
    if(rhs.getDen()!=1)
    {
        out << rhs.getNum() << "/" << rhs.getDen();
    }
    else
        cout<<rhs.getNum();
    return out;
}

istream & operator >> (istream & in, Fraction &rhs)
{
    int n, d;
    in >> n;
    char c;
    in >> c;
    if (c == '/')
        in >> d;
    else
    {
        in.putback(c);
        d = 1;
    }
    rhs = Fraction(n, d);
    return in; 
}

And here's the main program

#include "Fraction.h"

void main()
{
    Fraction a1;
    Fraction a(1,2);
    Fraction b(4,5);
    Fraction c(6,8);
    Fraction d(b);
    Fraction g(-4,8);
    Fraction g1(4,-10);
    Fraction z(7,5);

    cout << a1 << endl;
    cout << a  << endl;
    cout << b  << endl;
    cout << c  << endl;
    cout << d  << endl;
    cout << g  << endl;
    cout << g1 << endl;

    string s  = "3/4";
    string s1 = "2/-3";
    Fraction b1(s);
    Fraction b2(s1);

    cout << b1 << endl;
    cout << b2 << endl;

    a1 = b + c; cout << a1 << endl;
    a1 = b-c  ; cout << a1 << endl;
    a1 = b*c  ; cout << a1 << endl;
    a1 = b / c; cout << a1 << endl;

    b += a; cout << b << endl; 
    b -= a; cout << b << endl; 
    b /= a; cout << b << endl; 
    b++   ; cout << b << endl; 
    ++b   ; cout << b << endl; 
    b--   ; cout << b << endl; 
    --b   ; cout << b << endl; 
    b /= a; cout << b << endl; 
    b *a  ; cout << b << endl; 
    b^2   ; cout << b << endl; 

    cout << a.toString()       << endl;
    cout << z.toProperString() << endl;

    Fraction f1(-4,5);
    Fraction f2(0,1);
    cout << "is f1 negative?"             << f1.isNegative() << endl;
    cout << "is f2 zero?"                 << f2.isZero()     << endl;
    cout << "is f1 a proper fraction?"    << f1.isProper()   << endl;
    cout << "is f1 a positive fraction? " << f1.isPositive() << endl;

    a = Fraction(9, 8);
    b = Fraction(7, 8);

    if (a < b)
        cout << "a is smaller than b"   << endl;
    else
        cout << " a is larger than b"   << endl;

    if(a==b)
        cout << "a is equal to b"       << endl;
    else
        cout << "a does not equal to b" << endl;
}

Since no one was willing to help me, so I post all the codes here for everyone. I took me a while to finish this project with the help of my TA.

sehe
  • 374,641
  • 47
  • 450
  • 633
Kunlin
  • 33
  • 4
  • 9
  • Is the header file part of the asignment or did you write it? Why pointers for numer and denom? – deviantfan Feb 26 '14 at 21:35
  • it's part of the assignment. No one likes pointers. – Kunlin Feb 26 '14 at 21:41
  • Yes i do :) Can you maybe show the full C part? – deviantfan Feb 26 '14 at 21:44
  • yea, but the main function is incomplete tho. – Kunlin Feb 26 '14 at 22:18
  • @deviantfan: What do you mean by "full C part"? The code is C++, not C. – Keith Thompson Feb 26 '14 at 22:20
  • `string` and `double` operators? I'm confused... I think there's maybe been an error copying something down? Those functions don't make any sense to me. – aardvarkk Feb 26 '14 at 22:24
  • @KeithThompson: Sorry, i meant C++. – deviantfan Feb 26 '14 at 22:28
  • @aardvarkk those are conversion operators, used to convert to the given types automatically. – Mark Ransom Feb 26 '14 at 22:29
  • Can you guys help me out here? I don't know what to do with these conversion operators. – Kunlin Feb 26 '14 at 22:42
  • @MarkRansom Crazy -- I don't think I've encountered those before. Learn something new every day, thanks! – aardvarkk Feb 26 '14 at 23:17
  • @user3285116 I'd just implement one in terms of the other, e.g. `Fraction::operator string() { return toString(); }` – Mark Ransom Feb 26 '14 at 23:42
  • 2
    `operator^` is a bad choice for exponentiation, since it has an unexpected precendence. Implicit conversion functions (especially `operator double`, which loses precision) are generally a bad idea, since they can happen when you don't expect them. And the use of pointers rather than integer members is just insane. I hope this is presented as an example of how *not* to design a class; otherwise, you're being taught some very bad habits. – Mike Seymour Feb 26 '14 at 23:55
  • @Mike Seymour whats the better way to do that? And i will send your quote to my professor, lol – Kunlin Feb 27 '14 at 00:18
  • 2
    Also, `operator+` and the like must return a value, not a reference. Returning a reference to a local variable (which has been destroyed by the time the function has returned) isn't just a bad idea; it's categorically wrong. The better way to do this is to drop your course and invest in a [good book](http://stackoverflow.com/questions/388242) instead. – Mike Seymour Feb 27 '14 at 00:25
  • @MikeSeymour oh well,that's the option i don't have. But can you teach me how to do it the right way? Just for the conversion functions – Kunlin Feb 27 '14 at 02:47
  • 2
    Um, your post doesn't actually ask a question. It just is a wall of code. Please put a question in the post. – Raymond Chen Mar 08 '14 at 20:52
  • @Kunlin If you "don't have the option to learn the basics correctly", why should we spend time teaching you? – sehe Mar 08 '14 at 20:52
  • since no one was willing or able to help me, so I post all the codes here for everyone. I took me a while to finish this project with the help of my TA. – Kunlin Mar 08 '14 at 21:00

1 Answers1

5
  1. In various spots you're using

    Fraction *result=new Fraction((this->getNum()*rhs.getDen() - this->getDen()*rhs.getNum(), this->getDen()*rhs.getDen()));
    

    This needs to be

    Fraction *result=new Fraction(this->getNum()*rhs.getDen() - this->getDen()*rhs.getNum(), this->getDen()*rhs.getDen());
    

    or you'll actually be passing only this->getDen()*rhs.getDen() (How does the Comma Operator work). Also see bullet 3.

  2. Fraction & Fraction::operator=(Fraction & rhs) fails to return a value in all cases (drop the else)

  3. THIS ISN'T JAVA. Don't do new int(1). Just: int(1). Saves you the head-ache of memory management (What is The Rule of Three?)

  4. Don't do using namespace std;. Certainly not in header files (Why is "using namespace std" considered bad practice?). Also see bullet 19.

  5. Prefer the C++11 headers (e.g. <cstdlib>) over the C library headers (<stdlib.h>)

  6. Your toString method uses non-standard itoa. Also, it leaks several char buffers on each invocation... Try c++ style:

    string Fraction::toString()
    {
        return std::to_string(*numer) + '/' + std::to_string(*denom);
    }
    

    See? A single line, no more leaks. No more NUL-terminating temporaries. No more strcat nonsense. Just business logic. (Still need to fix the other things mentioned in earlier bullets, of course)

  7. Oh, and make members const when possible

    string Fraction::toString() const
    
  8. It needs to be int main(), not void. At least for standard-conforming/portable code.

  9. Copy constructors must take const& arguments.

    Fraction(Fraction const& other);  // copy constructor
    

    Same for the copy-assignment operator.

    The following line should not have compiled on a standards-conforming compiler:

    rhs = Fraction(n, d);
    

    Reason is, the temporary (rhs) cannot (legally) bind to a non-const reference parameter. Note this again makes it important that you mark getNum() and getDen() as const, or you won't be able to call them on the argument

  10. Returning references from operators that by convention have const semantics, violates Principle Of Least Surprise and is hence considered harmful:

    • Fraction& Fraction::operator+(Fraction&) should return by value
    • Fraction& Fraction::operator-(Fraction&) should return by value
    • Fraction& Fraction::operator*(Fraction&) should return by value
    • Fraction& Fraction::operator/(Fraction&) should return by value
    • postfix Fraction& Fraction::operator++(int) should return Fraction
    • postfix Fraction& Fraction::operator--(int) should return Fraction

    It's very easy to use the results of these operators and get something wholly unexpected. Given const-correctness, the problem is lessened, but the operators are still less useful than they could be.

  11. Don't mix double and float unless you know what you're doing (hint: you don't: Floating point inaccuracy examples)

    time passes...

    Okay, I've cleaned up a bit more. All uses of new were completely misguided (sorry). A lot of code could be simplified by reuse.

  12. don't if (cond) return true; else return false;. Instead just return cond;

  13. your constructor already does reduce(). So, make your operators just rely on that instead of doing redundant reductions:

     Fraction Fraction::operator*(Fraction const& rhs) const {
         return Fraction(numer*rhs.numer, denom*rhs.denom);
     }
    
     Fraction& Fraction::operator*=(Fraction const& rhs) {
         return *this = (*this * rhs);
     }
    
  14. the destructor is now redundant (no more pointers!)

  15. the constructors have been summarized into three:

     Fraction(int num = 0, int den = 1);
     Fraction(std::string const& s);  // take string parameter of the form of "numerator/defnominator
     Fraction(Fraction const& other);  // copy constructor
    
  16. constructors use initializer lists:

     Fraction::Fraction(int numerator, int den) : numer(numerator), denom(den)
     {
         assert(denom != 0);
         reduce();
     }
    
  17. gcd could be static (and doesn't need to be a class member. Just make it file static in the implementation file)

  18. some "test cases" and output are rather useless, e.g.

         b *a  ; cout << b << endl; 
         b^2u  ; cout << b << endl; 
    

    doesn't print anything related to the expressions. I've updated them to be more useful:

         b *= a;     cout << "b *= a; // "     << b  << endl; 
         b ^= 2u;    cout << "b ^= 2; // "     << b  << endl;
    
  19. you accidentally used cout instead of out in operator<<

  20. don't do floating point equality, even in operator>=,<= (see above about float and double, see bullet 11.)

Without further ado, here's my version. Disclaimer I didn't check much of the logic. I just reviewed coding problems and style.

Output:

a1: 0
a : 1/2
b : 4/5
c : 3/4
d : 4/5
g : -1/2
g1: 2/-5
b1: 3/4
b2: 2/-3
a1 = b + c; // 31/20
a1 = b-c  ; // 1/20
a1 = b*c  ; // 3/5
a1 = b / c; // 16/15
b += a; // 13/10
b -= a; // 4/5
b /= a; // 8/5
b++   ; // 13/5
++b   ; // 18/5
b--   ; // 13/5
--b   ; // 8/5
b /= a; // 16/5
b *= a; // 8/5
b ^= 2; // 64/25
1/2
1 2/5
is f1 negative? true
is f2 zero? true
is f1 a proper fraction? true
is f1 a positive fraction? false
a is not smaller than b
a is not equal to b

See it Live On Coliru

Note that the code compiles cleanly with all warnings enabled: -Wall -pedantic -Wextra -Werror -Weffc++

Code Listing

#ifndef FRACTION_H
#define FRACTION_H
#include <iostream>
#include <string>
#include <stdexcept>
#include <limits>

class Fraction {

    private:
        int numer;
        int denom;
        // static int gcd(int, int);
    public:
        void reduce();
        int getNum() const;
        int getDen() const;
        Fraction(int num = 0, int den = 1);
        Fraction(std::string const& s);  // take string parameter of the form of "numerator/denominator
        Fraction(Fraction const& other);  // copy constructor
        Fraction& operator=(Fraction const& rhs);
        // overloading arithematic operation
        Fraction  operator+  (Fraction const& rhs) const;
        Fraction  operator-  (Fraction const& rhs) const;
        Fraction  operator*  (Fraction const& rhs) const;
        Fraction  operator/  (Fraction const& rhs) const;
        bool      operator>  (Fraction const& rhs) const;
        bool      operator>= (Fraction const& rhs) const;
        bool      operator== (Fraction const& rhs) const;
        bool      operator<  (Fraction const& rhs) const;
        bool      operator<= (Fraction const& rhs) const;
        bool      operator!= (Fraction const& rhs) const;
        Fraction& operator++ ();
        Fraction& operator-- ();
        Fraction  operator++ (int);
        Fraction  operator-- (int);

        Fraction& operator+=(Fraction const& rhs);
        Fraction& operator-=(Fraction const& rhs);
        Fraction& operator*=(Fraction const& rhs);
        Fraction& operator/=(Fraction const& rhs);

        // Exponentiation
        Fraction operator^(unsigned n) const;
        Fraction& operator^=(unsigned n);

        bool isZero()     const;
        bool isProper()   const; // a fracton is proper if abs(numerator) < (denominator)
        bool isNegative() const;
        bool isPositive() const;

        operator std::string() const;
        operator double() const;

        std::string toString() const;
        std::string toProperString() const; // properString format of 15/4   is  3 3/4

        friend std::ostream& operator<< (std::ostream& out, Fraction const& rhs);
        friend std::istream& operator>> (std::istream& in, Fraction& rhs);
};

#endif

// for the Fraction.cpp file:

#include <iostream>
#include<cmath>
#include <cassert>
#include <string>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <sstream>

int Fraction::getNum() const
{
    return numer;
}

int Fraction::getDen() const
{
    return denom;
}

static int gcd(int n, int d)      //moving sign to numerator
{
    if(n<0)
        n=-n;
    if(d<0)
        d=-d;
    if(n<d)
        return gcd(d,n);
    if(d==0)
        return n;
    return gcd(d,n%d);
}

Fraction::Fraction(int numerator, int den) : numer(numerator), denom(den)
{
    assert(denom != 0);
    reduce();
}

void Fraction::reduce()
{
    int sign = 1;
    if (numer < 0)
    {
        sign = -1;
        numer = -numer;
    }
    if (numer< 0)
    {
        sign = -1;
        denom = -denom;
    }
    assert(denom != 0);
    int d = 1;
    if (numer>0)
    {
        d     = gcd(numer, denom);
        numer = sign*(numer / d);
        denom = denom / d;
    }
}

Fraction::Fraction(std::string const& s)
    : Fraction()
{
    std::istringstream iss(s);

    char delimiter = 0;

    if (
            (iss >> numer)
         && (iss >> delimiter)
         && (delimiter == '/')
         && (iss >> denom))
    {
        assert(denom != 0);
        reduce();
    } else
    {
        throw std::runtime_error("invalid conversion to Fraction");
    }
}

Fraction::Fraction(Fraction const& other)
    : numer(other.numer), denom(other.denom)
{
}

Fraction& Fraction::operator=(Fraction const& rhs)
{
    if (this != &rhs)
    {
        numer = rhs.numer;
        denom = rhs.denom;
    }
    return *this;
}

Fraction Fraction::operator+ (Fraction const& rhs) const
{
    return Fraction(numer*rhs.denom + denom*rhs.numer, denom*rhs.denom);
}

Fraction Fraction::operator- (Fraction const& rhs) const
{
    return Fraction(numer*rhs.denom - denom*rhs.numer, denom*rhs.denom);
}

Fraction Fraction::operator*(Fraction const& rhs) const
{
    return Fraction(numer*rhs.numer, denom*rhs.denom);
}

Fraction Fraction::operator/(Fraction const& rhs) const
{
    return Fraction(numer*rhs.denom, denom*rhs.numer);
}

bool Fraction::operator > (Fraction const& rhs) const
{
    return static_cast<double>(*this) > rhs;
}

bool Fraction::operator >= (Fraction const& rhs) const
{
    return (*this == rhs) || static_cast<double>(*this) > rhs;
}

bool Fraction::operator == (Fraction const& rhs) const
{
    return (1l*numer*rhs.denom == 1l*denom*rhs.numer);
}

bool Fraction::operator < (Fraction const& rhs) const
{
    return static_cast<double>(*this) < rhs;
}

bool Fraction::operator <= (Fraction const& rhs) const
{
    return (*this == rhs) || static_cast<double>(*this) < rhs;
}

bool Fraction::operator!=(Fraction const& rhs) const
{
    return !(*this == rhs);
}

Fraction& Fraction::operator++()  //prefix
{
    numer += denom;
    reduce();
    return *this;
}

Fraction Fraction::operator++(int) //postfix
{
    Fraction temp = *this;
    numer += denom;
    reduce();
    return temp;
}

Fraction& Fraction::operator--()
{
    numer -= denom;
    reduce();
    return *this;
}

Fraction Fraction::operator--(int)
{
    Fraction temp = *this;
    numer -= denom;
    reduce();
    return temp;
}

Fraction& Fraction::operator+=(Fraction const& rhs)
{
    return *this = (*this + rhs);
}

Fraction& Fraction::operator-=(Fraction const& rhs)
{
    return *this = (*this - rhs);
}

Fraction& Fraction::operator*=(Fraction const& rhs)
{
    return *this = (*this * rhs);
}

Fraction& Fraction::operator/=(Fraction const& rhs)
{
    return *this = (*this / rhs);
}

// utility
template <typename T>
T int_pow(T x, unsigned exponent)
{
    static_assert(std::is_integral<T>(), "only supports integral types");

    intmax_t base = x, result = 1;

    while (exponent != 0)
    {
        // TODO protect against overflows
        if (exponent % 2)
            result *= base;

        exponent /= 2;
        base *= base;
    }

    assert(result <= std::numeric_limits<T>::max()); // value too large to be represented
    assert(result >= std::numeric_limits<T>::min()); // value too small to be represented
    return static_cast<T>(result);
}

Fraction Fraction::operator^(unsigned n) const
{
    return Fraction(int_pow(numer, n), int_pow(denom, n));
}

Fraction& Fraction::operator^=(unsigned n)
{
    return *this = (*this ^ n);
}

bool Fraction::isZero() const
{
    return numer == 0;
}

bool Fraction::isProper() const
{
    return abs(numer)<abs(denom);
}

bool Fraction::isNegative() const
{
    return numer<0;
}

bool Fraction::isPositive() const
{
    return numer>0;
}

Fraction::operator std::string() const
{
    return toString();
}

Fraction::operator double() const
{
    return (static_cast<double>(numer) / denom);
}

std::string Fraction::toString() const
{
    return std::to_string(numer) + '/' + std::to_string(denom);
}

std::string Fraction::toProperString() const
{
    int a   = numer / denom;
    int num = numer % denom;

    std::ostringstream ostr;
    ostr << a << " " << Fraction(num, denom);
    return ostr.str();
}

std::ostream& operator <<  (std::ostream& out, Fraction const& rhs)
{
    if(rhs.denom!=1)
        return out << rhs.getNum() << "/" << rhs.denom;
    else
        return out << rhs.getNum();
}

std::istream& operator >> (std::istream& in, Fraction& rhs)
{
    int n, d = 1;
    char c;

    if (in >> n >> c)
    {
        if (c == '/')
        {
            in >> d;
        }
        else
        {
            in.putback(c);
        }
        rhs = Fraction(n, d);
    }
    return in;
}

// And here's the main program

int main()
{
    Fraction a1;
    Fraction a(1,2);
    Fraction b(4,5);
    Fraction c(6,8);
    Fraction d(b);
    Fraction g(-4,8);
    Fraction g1(4,-10);
    Fraction z(7,5);

    std::cout << "a1: " << a1 << "\n";
    std::cout << "a : " << a  << "\n";
    std::cout << "b : " << b  << "\n";
    std::cout << "c : " << c  << "\n";
    std::cout << "d : " << d  << "\n";
    std::cout << "g : " << g  << "\n";
    std::cout << "g1: " << g1 << "\n";

    std::string s  = "3/4";
    std::string s1 = "2/-3";
    Fraction b1(s);
    Fraction b2(s1);

    std::cout << "b1: " << b1 << "\n";
    std::cout << "b2: " << b2 << "\n";

    a1 = b + c; std::cout << "a1 = b + c; // " << a1 << "\n";
    a1 = b-c  ; std::cout << "a1 = b-c  ; // " << a1 << "\n";
    a1 = b*c  ; std::cout << "a1 = b*c  ; // " << a1 << "\n";
    a1 = b / c; std::cout << "a1 = b / c; // " << a1 << "\n";

    b += a;     std::cout << "b += a; // "     << b  << "\n";
    b -= a;     std::cout << "b -= a; // "     << b  << "\n";
    b /= a;     std::cout << "b /= a; // "     << b  << "\n";
    b++   ;     std::cout << "b++   ; // "     << b  << "\n";
    ++b   ;     std::cout << "++b   ; // "     << b  << "\n";
    b--   ;     std::cout << "b--   ; // "     << b  << "\n";
    --b   ;     std::cout << "--b   ; // "     << b  << "\n";
    b /= a;     std::cout << "b /= a; // "     << b  << "\n";
    b *= a;     std::cout << "b *= a; // "     << b  << "\n";
    b ^= 2u;    std::cout << "b ^= 2; // "     << b  << "\n";

    std::cout << a.toString()       << "\n";
    std::cout << z.toProperString() << "\n";

    Fraction f1(-4,5);
    Fraction f2(0,1);
    std::cout << "is f1 negative? "            << std::boolalpha << f1.isNegative() << "\n";
    std::cout << "is f2 zero? "                << std::boolalpha << f2.isZero()     << "\n";
    std::cout << "is f1 a proper fraction? "   << std::boolalpha << f1.isProper()   << "\n";
    std::cout << "is f1 a positive fraction? " << std::boolalpha << f1.isPositive() << "\n";

    a = Fraction(9, 8);
    b = Fraction(7, 8);

    if (a < b)
        std::cout << "a is smaller than b"     << "\n";
    else
        std::cout << "a is not smaller than b" << "\n";

    if(a==b)
        std::cout << "a is equal to b"         << "\n";
    else
        std::cout << "a is not equal to b"     << "\n";
}
Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • itoa works for visual studio 2010 but not 2013, thanks for your tips – Kunlin Mar 08 '14 at 21:22
  • I know. That's why I mentioned standards. I'll be reviewing the rest, and posting a fixed version :) – sehe Mar 08 '14 at 21:23
  • There. I finally reached a point where I considered the review "done" for now. See the edit (starting from ***time passes***). See the resulting code **[Live On Coliru](http://coliru.stacked-crooked.com/a/ca2442bf5b064812)** – sehe Mar 08 '14 at 22:56
  • 1
    Wow! Definitely a +1 for effort. – david.pfx Mar 08 '14 at 23:36