分数运算符

时间:2014-02-26 21:31:16

标签: c++ string class operator-keyword

我需要编写一个程序来计算分数,这是我的头文件:

#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

表示Fraction.cpp文件:

我有一个将派系格式转换为字符串的函数,这是我所拥有的,但不确定它是否正确。 这是我现在得到的:

#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; 
}

这是主程序

#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;
}

由于没有人愿意帮助我,所以我在这里为所有人发布所有代码。 我花了一些时间在TA的帮助下完成了这个项目。

1 个答案:

答案 0 :(得分:5)

  1. 在您正在使用的各个地方

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

    这需要

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

    或者您实际上只会传递this->getDen()*rhs.getDen()How does the Comma Operator work)。另外见子弹3。

  2. Fraction & Fraction::operator=(Fraction & rhs)无法在所有情况下返回值(删除else

  3. 这不是JAVA。不要new int(1)。只是:int(1)。为您节省内存管理(What is The Rule of Three?

  4. 的头痛
  5. 不要using namespace std;。当然不在头文件(Why is "using namespace std" considered bad practice?)中。另外见bullet 19.

  6. 优先于C库标题上的C ++ 11标题(例如<cstdlib>) (<stdlib.h>

  7. 您的toString方法使用非标准itoa。此外,它在每次调用时泄漏了几个char缓冲区...尝试c ++样式:

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

    请参阅?一条线,没有更多的泄漏。没有更多NUL终止临时。不再是strcat废话。只是商业逻辑。 (当然还需要修复早期子弹中提到的其他事情)

  8. 哦,尽可能让会员const

    string Fraction::toString() const
    
  9. 它必须是int main(),而不是void。至少对于符合标准的/便携式代码。

  10. 复制构造函数必须带有const&个参数。

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

    复制赋值运算符相同。

    的以下行应该在符合标准的编译器上编译:

    rhs = Fraction(n, d);
    

    原因是,临时(rhs)不能(合法地)绑定到非const引用参数。 注意这再次使您将getNum()getDen()标记为const非常重要,否则您将无法在参数

  11. 按惯例的运算符返回引用具有const语义,违反最低惊喜原则,因此被视为有害:

    • Fraction& Fraction::operator+(Fraction&)应按值返回
    • Fraction& Fraction::operator-(Fraction&)应按值返回
    • Fraction& Fraction::operator*(Fraction&)应按值返回
    • Fraction& Fraction::operator/(Fraction&)应按值返回
    • postfix Fraction& Fraction::operator++(int)应该返回Fraction
    • postfix Fraction& Fraction::operator--(int)应该返回Fraction

    使用这些运算符的结果非常容易,并且完全出乎意料。鉴于const - 正确性,问题会减少,但运营商仍然没有那么有用。

  12. 除非你知道自己在做什么,否则不要混用doublefloat(提示:你没有:Floating point inaccuracy examples

      

    时间过去 ...

    好的,我已经清理了一下。 new的所有用途都被完全误导(抱歉)。可以通过重复使用来简化批次代码。

  13. 不要if (cond) return true; else return false;。而只是return cond;

  14. 您的构造函数已经reduce()。因此,让您的操作员只需依靠它而不是进行多余的减少:

     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);
     }
    
  15. 析构函数现在是多余的(没有更多指针!)

  16. 构造函数已归纳为三个:

     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
    
  17. 构造函数使用初始化列表:

     Fraction::Fraction(int numerator, int den) : numer(numerator), denom(den)
     {
         assert(denom != 0);
         reduce();
     }
    
  18. gcd可以是静态的(并且不需要是类成员。只需在实现文件中将其设置为静态文件)

  19. 某些“测试用例”和输出相当无用,例如

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

    不会打印与表达式相关的任何。我已将它们更新为更有用:

         b *= a;     cout << "b *= a; // "     << b  << endl; 
         b ^= 2u;    cout << "b ^= 2; // "     << b  << endl;
    
  20. 您在cout

  21. 中意外使用了out而不是operator<<
  22. 不要做浮点平等,即使在operator>=<=中(请参阅上文关于floatdouble请参见项目符号11。
  23. 不用多说,这是我的版本。 免责声明我没有检查太多逻辑。我刚刚回顾了编码问题和风格。

    输出:

    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
    

    查看 Live On Coliru

    请注意,代码会干净地编译并启用所有警告:-Wall -pedantic -Wextra -Werror -Weffc++

    代码清单

    #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";
    }