C ++分数类

时间:2011-04-17 00:42:45

标签: c++

我必须创建一个名为 Fractions 的类,其中包含2个私有字段 Numerator,Denominator 。还有一个公共构造函数,默认情况下将Numerator和Denominator设置为1。我在我的分数课程中包含了4个成员函数:Sum,Difference,Product,Division。

然后我不知道下一步该做什么。为什么书显示分数等价?我该怎么办?我想一个非常重要的问题是我的会员功能应该采用什么参数?

同样禁止0分母的好方法是什么?抛出异常或强制它等于1?

Problem #5

以下是问题#5和#6(未显示)的完整源代码,经过几天的努力解决问题。 问题#6要求实现最大公约数函数以简化形式返回分数。所以这里是......

如果您认为有一种方法可以优化此代码,我们很乐意听取您的回复!

#include <iostream>
using namespace std;

class Fraction
{
private:
    int numerator, denominator; 
public:
    Fraction()
    {
        numerator = 1;
        denominator = 1;
    }
    Fraction(int n, int d)
    {
        numerator = n;
        if (d==0) 
        {
            cout << "ERROR: ATTEMPTING TO DIVIDE BY ZERO" << endl;
            exit(0); // will terminate the program if division by 0 is attempted
        }
        else
            denominator = d;
    }
    /*In the following functions I am dividing both numerator and denominator by the gcd function.
    GCD function accepts both numerator and denominator values. If we had 2 fractions, 1/2 and 1/4
    and we passed it into the Sum, the result would be n=6 and d=8. These are the values that GCD
    function will accept, find greatest common divisor and return the integer value of 2. In my case 
    am diving both numerator and denominator on the same line by the greatest common divisor. Although 
    it probably would be more efficient to create a local int variable and store GCD value in it, but
    for such small program it shouldn't make any difference.*/
    Fraction Sum(Fraction otherFraction)
    {
        int n = numerator*otherFraction.denominator+otherFraction.numerator*denominator;
        int d = denominator*otherFraction.denominator;
        return Fraction(n/gcd(n,d),d/gcd(n,d));
    }
    Fraction Difference(Fraction otherFraction)
    {
        int n = numerator*otherFraction.denominator-otherFraction.numerator*denominator;
        int d = denominator*otherFraction.denominator;
        return Fraction(n/gcd(n,d),d/gcd(n,d));
    }
    Fraction Product(Fraction otherFraction)
    {
        int n = numerator*otherFraction.numerator;
        int d = denominator*otherFraction.denominator;
        return Fraction(n/gcd(n,d),d/gcd(n,d));
    }
    Fraction Division(Fraction otherFraction)
    {
        int n = numerator*otherFraction.denominator;
        int d = denominator*otherFraction.numerator;
        return Fraction(n/gcd(n,d),d/gcd(n,d));
    }
    // I got the GCD algorithm from the following source:
    // Source C#: http://www.ww.functionx.com/csharp2/examples/gcd.htm
    int gcd(int n, int d)
    {
        int remainder;
        while (d != 0)
        {
            remainder = n % d;
            n = d;
            d = remainder;
        }
        return n;
    }
    void show() // Display method
    {
        if (denominator == 1) // e.g. fraction 2/1 will display simply as 2
            cout << numerator << endl;
        else
            cout << numerator << "/" << denominator << endl;
    }
};

int main()
{
    Fraction a(1,2);
    Fraction b(1,4);
    Fraction c;

    c = a.Sum(b); // Result: 3/4
    c.show();

    c = a.Difference(b); // Result: 1/4
    c.show();

    c = a.Product(b); // Result: 1/8
    c.show();

    c = a.Division(b); // Result: 2
    c.show();

    return 0;
}

7 个答案:

答案 0 :(得分:2)

  

同样禁止0分母的好方法是什么?抛出异常或强制它等于1?

这完全是一个风格问题,没有可证明的正确答案......

但是......我会有例外。再次,这只是风格。默默地改变价值将继续默默地前进,做了除了呼叫者要求之外的

另一种选择是允许0分母,但有办法告知用户当前的总值a / b是NaN或无穷大,或者你想要定义的任何“特殊值”。

无论如何,请仔细记录,以便班级用户做出明智的选择。

答案 1 :(得分:2)

您的分数构造函数应该将分子和分母作为参数(或整数)。运算符重载可以很容易地解决整个问题。

是的,the best way to handle failed constructors is via exceptions。当你将两个分数分开并且分母的分子为零时,不要忘记抛出相同的division_by_zero异常。

答案 2 :(得分:2)

您可能只想从第一部分开始,创建具有两个构造函数的类,一个如果它们给出两个数字,一个默认为1

然后,编写四个函数,赋值很好,可以给出方程式。

如果分母总是等于零,那么我会抛出异常,因为这是用户可能能够解决的问题。如果你可以显示导致它为零的东西,例如,如果它们除以(1/2)/(0/4),那么你的分母为零,这应该是一个错误条件。

你要看的一个问题是,如果这是不可变的,那么,如果我有(1/2)和(2/3)并且我做了一个操作,它应该返回一个新的数字,而不是修改我传入的两个。在这种情况下,你的检查总是在构造函数中为零,但是你应该解释哪个操作导致了这个错误。

答案 3 :(得分:1)

您的方法可能是(假设您的班级被命名为“Fraction”):

Fraction Fraction::sum(Fraction &otherFraction)
Fraction Fraction::difference(Fraction &otherFraction)
Fraction Fraction::product(Fraction &otherFraction)
Fraction Fraction::division(Fraction &otherFraction)

(使用您描述的方法名称 - 我可能会寻找不同的方法)

每个都会返回一个包含结果的新Fraction对象。

使用运算符重载并重新定义+ - / *的含义时,您将获得奖励积分。

答案 4 :(得分:1)

一个问题中有这么多问题!让我为你回答一个(对):

  

为什么书显示分数   等价?我需要做什么   那个?

考虑Fraction类的这种用法:

TEST(FractionsAreEquivalent)
{
    const Fraction one_over_two(1, 2); // 0.5
    const Fraction two_over_four(2, 4); // 0.5

    const bool equivalent = (one_over_two == two_over_four);

    CHECK(equivalent);
}

这使用bool Fraction::operator ==(const Fraction& rhs) const

答案 5 :(得分:0)

我是一个新人,如果我的代码看起来很菜,我很抱歉:P

    #include<iostream>
    using namespace std;

    class Fraction
    {
    private :
    int x;//NUMERATOR
    int y;//DENOMINATOR
    public :    
    Fraction(int tx = 0, int ty = 1)
    {
    if(ty == 0)
    { 
    x = 0; 
    y = 1;
    exit(0);                        
    }else
    {
    x = tx;
    y = ty;
    }
    }
    void simplify()
    {
    for(int i = x; i >1;i--)
    {
    if(x%i == 0 && y%i == 0)
    {   
    x = x/i;
    y = y/i;
    } 
    }
    }
    void Input()
    {
    cout<<"Input NUMERATOR: ";
    cin>>x;
    cout<<"Input DENOMINATOR: ";
    cin>>y; 
    if(y==0)
    {
    cout<<"ERROR";
    exit(0);    
    }   
    }
    void Display()
    {
    cout<< x << "/" << y <<endl;
    }
    Fraction operator + (Fraction f){
    Fraction temp;
    temp.x = x * f.y + y * f.x;
    temp.y = y * f.y;
    return temp; 
    }
    Fraction operator - (Fraction f){
    Fraction temp;
    temp.x = x * f.y - y * f.x;
    temp.y = y * f.y;
    return temp; 
    }
    Fraction operator * (Fraction f){
    Fraction temp;
    temp.x = x * f.x ;
    temp.y = y * f.y;
    return temp; 
    }
    Fraction operator / (Fraction f){
    Fraction temp;
    temp.x = x * f.y ;
    temp.y = y * f.x;
    return temp; 
    }
    };
    int main ()
    {   
   
    Fraction f1;
    f1.Input();
    cout<<"Fraction: ";
    f1.simplify();
    f1.Display();
    Fraction f2;    
    f2.Input();
    cout<<"Fraction: ";
    f2.simplify();
    f2.Display();
    Fraction f3,f4,f5,f6;
    f3 = f1 + f2;
    f4 = f1 - f2;
    f5 = f1 * f2;   
    f6 = f1 / f2;
    cout<<"Sum"<<endl;
    f3.simplify();
    f3.Display();
    cout<<"Difference"<<endl;
    f4.simplify();
    f4.Display();
    cout<<"Product"<<endl;
    f5.simplify();
    f5.Display();
    cout<<"Division"<<endl;
    f6.simplify();
    f6.Display();           
    return 0;
    }
<块引用>

块引用

答案 6 :(得分:0)

我创建了这个 Fractions 类的一个版本,虽然我的编码很糟糕,但它应该可以工作。请注意,我定义了 C++20 中引入的 <=> 运算符,并自动定义了 <, >, <=, >=。如果你没有,你可以使用 std::rel_ops 或者只是一一定义它们。

分数.h:

#include <memory>
#include <numeric>
#include <string>

class Fraction
{
private: 
    long long num{ 1 };
    long long denom{ 1 };

    inline void simplify() {
        auto gcd{ std::make_unique<long long>(std::gcd(num, denom)) };
        num /= *gcd;
        denom /= *gcd;
        gcd.reset();
        if (denom < 0) {
            num = -num;
            denom = -denom;
        }
    }

public:
    Fraction(double numerator = 1, double denominator = 1);
    Fraction(double numerator, double denominator, int integer_part);
    Fraction(const Fraction& f);

    long long numerator() const;
    long long denominator() const;
    auto setnumerator(long long nv);
    auto setdenominator(long long nv);

    double value() const;

    Fraction reciprocal() const;

    std::string str(size_t mode = 0) const;

    bool operator==(const Fraction& f) const;
    auto operator<=>(const Fraction& f) const;
    bool operator==(size_t s) const;
    auto operator<=>(size_t s) const;
    friend bool operator== (size_t s, Fraction& f);
    friend auto operator<=> (size_t s, Fraction& f);
    bool operator==(double d) const;
    auto operator<=>(double d) const;
    friend bool operator== (double d, Fraction& f);
    friend auto operator<=> (double d, Fraction& f);

    Fraction operator+(const Fraction& f) const;
    Fraction operator+(size_t s) const;
    Fraction operator+(double d) const;
    friend Fraction operator+(size_t s, const Fraction& f);
    friend Fraction operator+(double d, const Fraction& f);

    Fraction operator-(const Fraction& f) const;
    Fraction operator-(size_t s) const;
    Fraction operator-(double d) const;
    friend Fraction operator-(size_t s, const Fraction& f);
    friend Fraction operator-(double d, const Fraction& f);

    Fraction operator*(const Fraction& f) const;
    Fraction operator*(size_t s) const;
    Fraction operator*(double d) const;
    friend Fraction operator*(size_t s, const Fraction& f);
    friend Fraction operator*(double d, const Fraction& f);

    Fraction operator/(const Fraction& f) const;
    Fraction operator/(size_t s) const;
    Fraction operator/(double d) const;
    friend Fraction operator/(size_t s, const Fraction& f);
    friend Fraction operator/(double d, const Fraction& f);

    Fraction operator%(const Fraction& f) const;
    Fraction operator%(size_t s) const;
    Fraction operator%(double d) const;
    friend size_t operator%(size_t s, const Fraction& f);
    friend double operator%(double d, const Fraction& f);

    Fraction& operator+=(const Fraction& f);
    Fraction& operator+=(size_t s);
    Fraction& operator+=(double d);
    friend size_t operator+=(size_t s, Fraction& f);
    friend double operator+=(double d, Fraction& f);

    Fraction& operator-=(const Fraction& f);
    Fraction& operator-=(size_t s);
    Fraction& operator-=(double d);
    friend size_t operator-=(size_t s, Fraction& f);
    friend double operator-=(double d, Fraction& f);

    Fraction& operator*=(const Fraction& f);
    Fraction& operator*=(size_t s);
    Fraction& operator*=(double d);
    friend size_t operator*=(size_t s, Fraction& f);
    friend double operator*=(double d, Fraction& f);

    Fraction& operator/=(const Fraction& f);
    Fraction& operator/=(size_t s);
    Fraction& operator/=(double d);
    friend size_t operator/=(size_t s, Fraction& f);
    friend double operator/=(double d, Fraction& f);

    Fraction& operator%=(const Fraction& f);
    Fraction& operator%=(size_t s);
    Fraction& operator%=(double d);
    friend size_t operator%=(size_t s, Fraction& f);
    friend double operator%=(double d, Fraction& f);

    Fraction& operator++();
    Fraction operator++(int);
    Fraction& operator--();
    Fraction operator--(int);

    Fraction operator+();
    Fraction operator-();
    long long operator[](int i);
};

分数.cpp:

#include "Fraction.h"
#include <limits>
#include <sstream>

Fraction::Fraction(double numerator, double denominator)
{
    double tsn{ numerator }, tsd{ denominator };
    while ((static_cast<long long>(tsn) != tsn || static_cast<long long>(tsd) != tsd) && std::numeric_limits<long long>::max() / 10 > tsn && std::numeric_limits<long long>::max() / 10 > tsd) {
        tsn *= 10;
        tsd *= 10;
    }
    num = tsn;
    denom = tsd;
    simplify();
}

Fraction::Fraction(double numerator, double denominator, int integer_part)
{
    numerator += denominator * integer_part;
    double tsn{ numerator }, tsd{ denominator };
    while ((static_cast<long long>(tsn) != tsn || static_cast<long long>(tsd) != tsd) && std::numeric_limits<long long>::max() / 10 > tsn && std::numeric_limits<long long>::max() / 10 > tsd) {
        tsn *= 10;
        tsd *= 10;
    }
    num = tsn;
    denom = tsd;
    simplify();
}

Fraction::Fraction(const Fraction& f)
{
    num = f.numerator();
    denom = f.denominator();
}

long long Fraction::numerator() const
{
    return num;
}

long long Fraction::denominator() const
{
    return denom;
}

auto Fraction::setnumerator(long long nv)
{
    num = nv;
    simplify();
    return this;
}

auto Fraction::setdenominator(long long nv)
{
    denom = nv;
    simplify();
    return this;
}

double Fraction::value() const
{
    return static_cast<double>(num) / denom;
}

Fraction Fraction::reciprocal() const
{
    return Fraction(denom, num);
}

std::string Fraction::str(size_t mode) const 
{
    std::stringstream ss;
    if (mode == 0) {
        ss << num;
        if (denom != 1) {
            ss << '/' << denom;
        }
    }
    else {
        if (num % denom == 0 || denom == 1) {
            ss << num / denom;
        }
        else {
            if (abs(denom) > abs(num)) {
                ss << num << '/' << denom;
            }
            else if (num < 0) {
                ss << '-' << '(' << (num / denom) << ' ' << -(num % denom) << '/' << denom << ')';
            }
            else {
                ss << (num / denom) << ' ' << num % denom << '/' << denom;
            }
        }
    }
    return ss.str();
}

bool Fraction::operator==(const Fraction& f) const
{
    return value() == f.value();
}

auto Fraction::operator<=>(const Fraction& f) const 
{
    return value() <=> f.value();
}

bool Fraction::operator==(size_t s) const 
{
    return value() == s;
}

auto Fraction::operator<=>(size_t s) const 
{
    return value() <=> s;
}

bool operator==(size_t s, const Fraction& f)
{
    return s == f.value();
}

auto operator<=>(size_t s, const Fraction& f)
{
    return s <=> f.value();
}

bool Fraction::operator==(double d) const
{
    return value() == d;
}

auto Fraction::operator<=>(double d) const
{
    return value() <=> d;
}

bool operator==(double d, Fraction& f)
{
    return f.value() == d;
}

auto operator<=>(double d, Fraction& f)
{
    return f.value() <=> d;
}

Fraction Fraction::operator+(const Fraction& f) const
{
    return Fraction(num * f.denominator() + f.numerator() * denom, denom * f.denominator());
}

Fraction Fraction::operator+(size_t s) const
{
    return Fraction(s * denom + num, denom);
}

Fraction Fraction::operator+(double d) const
{
    return *this + Fraction(d);
}

Fraction operator+(size_t s, const Fraction& f)
{
    return f + s;
}

Fraction operator+(double d, const Fraction& f)
{
    return f + d;
}

Fraction Fraction::operator-(const Fraction& f) const
{
    return Fraction(num * f.denominator() - f.numerator() * denom, denom * f.denominator());
}

Fraction Fraction::operator-(size_t s) const
{
    return Fraction(num - (s * denom), denom);
}

Fraction Fraction::operator-(double d) const
{
    return *this - Fraction(d);
}

Fraction operator-(size_t s, const Fraction& f)
{
    return Fraction(s * f.denom - f.num, f.denom);
}

Fraction operator-(double d, const Fraction& f)
{
    return Fraction(d) - f;
}

Fraction Fraction::operator*(const Fraction& f) const
{
    return Fraction(num * f.numerator(), denom * f.denominator());
}

Fraction Fraction::operator*(size_t s) const
{
    return Fraction(num * s, denom);
}

Fraction Fraction::operator*(double d) const
{
    return Fraction(num * d, denom);
}

Fraction operator*(size_t s, const Fraction& f)
{
    return Fraction(f.numerator() * s, f.denominator());
}

Fraction operator*(double d, const Fraction& f)
{
    return Fraction(f.numerator() * d, f.denominator());
}

Fraction Fraction::operator/(const Fraction& f) const
{
    return (*this) * f.reciprocal();
}

Fraction Fraction::operator/(size_t s) const
{
    return Fraction(num, denom * s);
}

Fraction Fraction::operator/(double d) const
{
    return Fraction(num, denom * d);
}

Fraction operator/(size_t s, const Fraction& f)
{
    return s * f.reciprocal();
}

Fraction operator/(double d, const Fraction& f)
{
    return d * f.reciprocal();
}

Fraction Fraction::operator%(const Fraction& f) const
{
    return ((*this) / f).value() > 0 ? Fraction((*this) - (floor(((*this) / f).value()) * f)) : Fraction((*this) - (ceil(((*this) / f).value()) * f));
}

Fraction Fraction::operator%(size_t s) const
{
    return ((*this) / s).value() > 0 ? Fraction((*this) - (floor(((*this) / s).value()) * s)) : Fraction((*this) - (ceil(((*this) / s).value()) * s));
}

Fraction Fraction::operator%(double d) const
{
    return ((*this) / d).value() > 0 ? Fraction((*this) - (floor(((*this) / d).value()) * d)) : Fraction((*this) - (ceil(((*this) / d).value()) * d));
}

size_t operator%(size_t s, const Fraction& f)
{
    return (f / s).value() > 0 ? ((f) - (floor((s / f).value()) * f)).value() : ((f)-(ceil((s / f).value()) * f)).value();
}

double operator%(double d, const Fraction& f)
{
    return (f / d).value() > 0 ? ((f)-(floor((d / f).value()) * f)).value() : ((f)-(ceil((d / f).value()) * f)).value();
}

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

Fraction& Fraction::operator+=(size_t s)
{
    *this = *this + s;
    return *this;
}

Fraction& Fraction::operator+=(double d)
{
    *this = *this + d;
    return *this;
}

size_t operator+=(size_t s, Fraction& f)
{
    s += round(f.value());
    return s;
}

double operator+=(double d, Fraction& f)
{
    d += f.value();
    return d;
}

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

Fraction& Fraction::operator-=(size_t s)
{
    *this = *this - s;
    return *this;
}

Fraction& Fraction::operator-=(double d)
{
    *this = *this - d;
    return *this;
}

size_t operator-=(size_t s, Fraction& f)
{
    s -= round(f.value());
    return s;
}

double operator-=(double d, Fraction& f)
{
    d -= f.value();
    return d;
}

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

Fraction& Fraction::operator*=(size_t s)
{
    *this = *this * s;
    return *this;
}

Fraction& Fraction::operator*=(double d)
{
    *this = *this * d;
    return *this;
}

size_t operator*=(size_t s, Fraction& f)
{
    s *= round(f.value());
    return s;
}

double operator*=(double d, Fraction& f)
{
    d *= f.value();
    return d;
}

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

Fraction& Fraction::operator/=(size_t s)
{
    *this = *this / s;
    return *this;
}

Fraction& Fraction::operator/=(double d)
{
    *this = *this / d;
    return *this;
}

size_t operator/=(size_t s, Fraction& f)
{
    s /= round(f.value());
    return s;
}

double operator/=(double d, Fraction& f)
{
    d /= f.value();
    return d;
}

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

Fraction& Fraction::operator%=(size_t s)
{
    *this = *this % s;
    return *this;
}

Fraction& Fraction::operator%=(double d)
{
    *this = *this % d;
    return *this;
}

size_t operator%=(size_t s, Fraction& f)
{
    s = s % f;
    return s;
}

double operator%=(double d, Fraction& f)
{
    d = d % f;
    return d;
}

Fraction& Fraction::operator++()
{
    this->num += this->denom;
    return *this;
}

Fraction Fraction::operator++(int)
{
    Fraction copy{ *this };
    this->num += this->denom;
    return copy;
}

Fraction& Fraction::operator--()
{
    this->num -= this->denom;
    return *this;
}

Fraction Fraction::operator--(int)
{
    Fraction copy{ *this };
    this->num -= this->denom;
    return copy;
}

Fraction Fraction::operator+()
{
    return *this;
}

Fraction Fraction::operator-()
{
    return Fraction(-num, denom);
}

long long Fraction::operator[](int i)
{
    return i == 0 ? num : denom;
}

大多数底层只是不同类型的运算符重载,因为我将在 Fraction 对象、size_t 和 double 对象上使用运算符。这应该更加优化,因为它使用了一个简化()函数,而不是像和和差这样的函数,我使用了运算符重载。 Fraction.str() 比上面优化了一点。至于零除法的东西,我认为它会被捕获,编译器至少会发出警告,并且在运行时,它应该给出一个浮点错误。如果您发现代码中的任何错误,请在下方评论!