1.简介
该博文是C++分数类的姊妹篇。那篇博文中type对应的类型是long long,虽然范围很大,但还是可能溢出。我最近做了一个大整数类,理论上可以保存无限大的整数,于是,我把这两个类结合了起来,并添加了一些新功能,就成了这个版本的分数类。
注:由于大整数类不存在溢出现象,但运算速度慢,尤其是约分(求最大公约数),需要进行多次取模运算,所以在前一个版本的分数类中一些牺牲时间来防止溢出的代码被删除了,简化了代码的同时提高了效率(如乘法原来需要4次约分、3次复制,现在只需1次约分,同样的程序运行时间由125毫秒降至78毫秒)。
2.代码
改进后的分数类代码如下:(测试代码见第一篇博客)
CFraction.h:
#pragma once
#include<stdexcept>
#include"CBigInt.h"
class CFraction
{
private:
typedef CBigInt type;
type numerator;//分子
type denominator;//分母
static type GCD(type x, type y);
static type LCM(const type& x, const type& y);
public:
CFraction();
CFraction(type n, type d = 1);
CFraction(const CFraction& fraction);
CFraction(long double d);
const type& GetNumerator()const noexcept;
const type& GetDenominator()const noexcept;
long double GetFractionalValue()const;
void SetNumerator(const type& n);
void SetDenominator(const type& d);
void Assign(const type& n, const type& d);
void Assign(long double d);
void Assign(const CFraction& fraction);
void ReductionOfTheFraction();//约分
void ReductionOfTheFractionToACommonDenominator(CFraction& fraction);//通分
void ReductionOfTheFractionToACommonDenominatorQuickly(CFraction& fraction);//通分,分母不是最小公倍数,而是分母之积,数大时效率高
CFraction Reciprocal()const;//倒数
CFraction operator=(const CFraction& fraction);
CFraction operator=(long double d);
/*
friend bool operator>(CFraction, CFraction);
friend bool operator<(CFraction, CFraction);
friend bool operator>=(CFraction, CFraction);
friend bool operator<=(CFraction, CFraction);
*/
friend std::strong_ordering operator<=>(CFraction f1, CFraction f2);
//使用C++20中的三路比较运算符
friend bool operator==(const CFraction& f1, const CFraction& f2);
friend bool operator!=(const CFraction& f1, const CFraction& f2);
friend CFraction operator+(CFraction f1, CFraction f2);
friend CFraction operator-(CFraction f1, CFraction f2);
friend CFraction operator*(CFraction f1, CFraction f2);
friend CFraction operator/(CFraction f1, CFraction f2);
CFraction& operator+=(const CFraction& f2);
CFraction& operator-=(const CFraction& f2);
CFraction& operator*=(const CFraction& f2);
CFraction& operator/=(const CFraction& f2);
CFraction operator-()const;
bool IsIrreducibleFraction()const;//是否为最简分数
bool CanItBeAFiniteDecimal()const;//能否化成有限小数
type Floor()const;
type Ceil()const;
};
CFraction.cpp:
#include "CFraction.h"
CFraction::type CFraction::GCD(type x, type y)
{
type t;
while (y != 0)
{
t = x % y;
x = y;
y = t;
}
return x;
}
CFraction::type CFraction::LCM(const type& x, const type& y)
{
return x * y / GCD(x, y);
}
CFraction::CFraction()
{
numerator = 1;
denominator = 1;
}
CFraction::CFraction(type n, type d)
{
Assign(n, d);
}
CFraction::CFraction(const CFraction& fraction)
{
Assign(fraction);
}
CFraction::CFraction(long double d)
{
Assign(d);
}
const CFraction::type& CFraction::GetNumerator()const noexcept
{
return numerator;
}
const CFraction::type& CFraction::GetDenominator()const noexcept
{
return denominator;
}
long double CFraction::GetFractionalValue() const
{
return (numerator.ToLongDouble() / denominator.ToLongDouble());
}
void CFraction::SetNumerator(const type& n)
{
numerator = n;
}
void CFraction::SetDenominator(const type& d)
{
if (d == 0)
throw std::invalid_argument("分母为0!");
denominator = d;
}
void CFraction::Assign(const type& n, const type& d)
{
if (d == 0)
throw std::invalid_argument("分母为0!");
numerator = n;
denominator = d;
}
void CFraction::Assign(long double d)
{
if (d == 0)
throw std::invalid_argument("参数为0!");
type i = 1;
while (d - floorl(d) > 1e-15)
{
d *= 10;
i *= 10;
}
std::string str = std::to_string(d);
this->numerator =
str.substr(0, str.find('.'));
this->denominator = i;
this->ReductionOfTheFraction();
}
void CFraction::Assign(const CFraction& fraction)
{
this->numerator = fraction.numerator;
this->denominator = fraction.denominator;
}
void CFraction::ReductionOfTheFraction()
{
const type i = GCD(numerator, denominator);
numerator /= i;
denominator /= i;
}
void CFraction::ReductionOfTheFractionToACommonDenominator(CFraction& fraction)
{
this->ReductionOfTheFraction();
fraction.ReductionOfTheFraction();
const type lcm = LCM(this->denominator, fraction.denominator);
this->numerator *= (lcm / this->denominator);//分母乘几,分子也乘几
fraction.numerator *= (lcm / fraction.denominator);
this->denominator = lcm;//分母等于最小公倍数
fraction.denominator = lcm;
}
void CFraction::ReductionOfTheFractionToACommonDenominatorQuickly(CFraction& fraction)
{
this->numerator *= fraction.denominator;
fraction.numerator *= this->denominator;
this->denominator *= fraction.denominator;
fraction.denominator = this->denominator;
}
CFraction CFraction::operator=(const CFraction& fraction)
{
Assign(fraction);
return *this;
}
CFraction CFraction::operator=(long double d)
{
Assign(d);
return *this;
}
CFraction CFraction::Reciprocal()const
{
return CFraction(this->denominator,this->numerator);
}
/*
bool operator>(CFraction f1, CFraction f2)
{
return (f1.Compare(f2) > 0);
}
bool operator<(CFraction f1, CFraction f2)
{
return (f1.Compare(f2) < 0);
}
bool operator>=(CFraction f1, CFraction f2)
{
return (f1.Compare(f2) >= 0);
}
bool operator<=(CFraction f1, CFraction f2)
{
return (f1.Compare(f2) <= 0);
}
*/
std::strong_ordering operator<=>(CFraction f1, CFraction f2)
{
//f1.ReductionOfTheFractionToACommonDenominator(f2);
//return f1.numerator <=> f2.numerator;
f1 /= f2;
return f1.numerator <=> f1.denominator;
}
bool operator==(const CFraction& f1, const CFraction& f2)
{
return ((f1 <=> f2) == std::strong_ordering::equivalent);
}
bool operator!=(const CFraction& f1, const CFraction& f2)
{
return ((f1 <=> f2) != std::strong_ordering::equivalent);
}
CFraction operator+(CFraction f1, CFraction f2)
{
//f1.ReductionOfTheFractionToACommonDenominator(f2);
f1.ReductionOfTheFractionToACommonDenominatorQuickly(f2);
f1.numerator += f2.numerator;
f1.ReductionOfTheFraction();
return f1;
}
CFraction operator-(CFraction f1, CFraction f2)
{
//f1.ReductionOfTheFractionToACommonDenominator(f2);
f1.ReductionOfTheFractionToACommonDenominatorQuickly(f2);
f1.numerator -= f2.numerator;
f1.ReductionOfTheFraction();
return f1;
}
CFraction operator*(CFraction f1, CFraction f2)
{
f1.numerator *= f2.numerator;
f1.denominator *= f2.denominator;
f1.ReductionOfTheFraction();
return f1;
}
CFraction operator/(CFraction f1, CFraction f2)
{
return operator*(f1, f2.Reciprocal());//除以一个数等于乘这个数的倒数
}
CFraction& CFraction::operator+=(const CFraction& f2)
{
this->Assign(*this + f2);
return *this;
}
CFraction& CFraction::operator-=(const CFraction& f2)
{
this->Assign(*this - f2);
return *this;
}
CFraction& CFraction::operator*=(const CFraction& f2)
{
this->Assign(*this * f2);
return *this;
}
CFraction& CFraction::operator/=(const CFraction& f2)
{
this->Assign(*this / f2);
return *this;
}
CFraction CFraction::operator-() const
{
return CFraction(-numerator, denominator);
}
bool CFraction::IsIrreducibleFraction() const
{
return (GCD(numerator, denominator) == 1);
}
bool CFraction::CanItBeAFiniteDecimal() const
{
CFraction t(*this);
t.ReductionOfTheFraction();
while (1)//化成最简分数后判断分母是否只有2和5这两个因数
{
if (t.denominator % 2 == 0)
t.denominator /= 2;
else if (t.denominator % 5 == 0)
t.denominator /= 5;
else
{
if (t.denominator == 1)
return true;
return false;
}
}
}
CFraction::type CFraction::Floor() const
{
return numerator / denominator;
}
CFraction::type CFraction::Ceil() const
{
CBigInt rem;
CBigInt&& result = CBigInt::Division(numerator, denominator, rem);
result += (rem > 0);
return result;
}