1.简介
我用C++做了一个分数类,实现了加减乘除、比较大小、约分、通分等功能,其中比较大小用到了C++20的新特性之一——三路比较运算符。下面与大家分享一下代码(VS2019,C++20编译通过)。
注:此是旧版本的分数类,新版本代码点击查看。
2.代码
代码不难理解,用到的都是一些数学原理。
//CFraction.h
#pragma once
#include<stdexcept>
class CFraction
{
private:
typedef long long type;
type numerator;//分子
type denominator;//分母
static type GCD(type x, type y);
static type LCM(type x, type y);
public:
CFraction();
CFraction(type, type)
CFraction(const CFraction&);
CFraction(long double);
type GetNumerator()const;
type GetDenominator()const;
long double GetFractionalValue()const;
void SetNumerator(type);
void SetDenominator(type);
void Assign(type, type);
void Assign(long double);
void Assign(const CFraction&);
void ReductionOfTheFraction();//约分
void ReductionOfTheFractionToACommonDenominator(CFraction&);//通分
CFraction Reciprocal();//倒数
CFraction operator=(const CFraction&);
CFraction operator=(long double);
type Compare(CFraction)const;
friend bool operator==(CFraction, CFraction);
friend bool operator!=(CFraction, CFraction);
/*
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, CFraction);
//使用三路比较运算符代替4种比较运算符(需要C++20)
friend CFraction operator+(CFraction, CFraction);
friend CFraction operator-(CFraction, CFraction);
friend CFraction operator*(CFraction, CFraction);
friend CFraction operator/(CFraction, CFraction);
friend CFraction operator+=(CFraction&, const CFraction&);
friend CFraction operator-=(CFraction&, const CFraction&);
friend CFraction operator*=(CFraction&, const CFraction&);
friend CFraction operator/=(CFraction&, const CFraction&);
bool IsIrreducibleFraction()const;//是否为最简分数
bool CanItBeAFiniteDecimal()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(type x, type y)
{
return x * y / GCD(x, y);
}
CFraction::CFraction()
{
numerator = 1;
denominator = 1;
}
CFraction::CFraction(type n, type d = 1)
{
Assign(n, d);
}
CFraction::CFraction(const CFraction& fraction)
{
Assign(fraction);
}
CFraction::CFraction(long double d)
{
Assign(d);
}
CFraction::type CFraction::GetNumerator()const
{
return numerator;
}
CFraction::type CFraction::GetDenominator()const
{
return denominator;
}
long double CFraction::GetFractionalValue() const
{
return (static_cast<long double>(numerator)/denominator);
}
void CFraction::SetNumerator(type n)
{
numerator = n;
}
void CFraction::SetDenominator(type d)
{
if (d == 0)
throw std::invalid_argument("分母为0!");
denominator = d;
}
void CFraction::Assign(type n, 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 - static_cast<long double>(static_cast<type>(d)) > 1e-15)
{
d *= 10;
i *= 10;
}
this->numerator = static_cast<type>(d);
this->denominator = i;
this->ReductionOfTheFraction();
}
void CFraction::Assign(const CFraction& fraction)
{
this->numerator = fraction.numerator;
this->denominator = fraction.denominator;
}
void CFraction::ReductionOfTheFraction()
{
type i = GCD(numerator, denominator);
numerator /= i;
denominator /= i;
}
void CFraction::ReductionOfTheFractionToACommonDenominator(CFraction& fraction)
{
this->ReductionOfTheFraction();
fraction.ReductionOfTheFraction();
type lcm = LCM(this->denominator, fraction.denominator);
this->numerator *= (lcm / this->denominator);//分母乘几,分子也乘几
fraction.numerator *= (lcm / fraction.denominator);
this->denominator = lcm;//分母等于最小公倍数
fraction.denominator = lcm;
}
CFraction CFraction::operator=(const CFraction& fraction)
{
Assign(fraction);
return *this;
}
CFraction CFraction::operator=(long double d)
{
Assign(d);
return *this;
}
CFraction CFraction::Reciprocal()
{
return CFraction(this->denominator,this->numerator);
}
CFraction::type CFraction::Compare(CFraction fraction)const
{
CFraction t(*this);
t.ReductionOfTheFractionToACommonDenominator(fraction);
return (t.numerator - fraction.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);
}
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;
}
CFraction operator+(CFraction f1, CFraction f2)
{
f1.ReductionOfTheFractionToACommonDenominator(f2);
f1.numerator += f2.numerator;
f1.ReductionOfTheFraction();
return f1;
}
CFraction operator-(CFraction f1, CFraction f2)
{
f1.ReductionOfTheFractionToACommonDenominator(f2);
f1.numerator -= f2.numerator;
f1.ReductionOfTheFraction();
return f1;
}
CFraction operator*(CFraction f1, CFraction f2)
{
f1.ReductionOfTheFraction();
f2.ReductionOfTheFraction();
//先约分,防止溢出
CFraction::type tmp=f1.numerator;
f1.numerator = f2.numerator;
f2.numerator = tmp;
f1.ReductionOfTheFraction();
f2.ReductionOfTheFraction();
/*
交换分子后再约分,防止溢出。例如,计算(10000000000/10000000001)*(10000000001/10000000000)时
直接计算会溢出,交换分子后约分变成(1/1)*(1/1),不会溢出。
*/
f1.numerator *= f2.numerator;
f1.denominator *= f2.denominator;
return f1;//已是最简分数,无需约分
}
CFraction operator/(CFraction f1, CFraction f2)
{
return operator*(f1, f2.Reciprocal());//除以一个数等于乘这个数的倒数
}
CFraction operator+=(CFraction& f1, const CFraction& f2)
{
f1.Assign(f1 + f2);
return f1;
}
CFraction operator-=(CFraction& f1, const CFraction& f2)
{
f1.Assign(f1 - f2);
return f1;
}
CFraction operator*=(CFraction& f1, const CFraction& f2)
{
f1.Assign(f1 * f2);
return f1;
}
CFraction operator/=(CFraction& f1, const CFraction& f2)
{
f1.Assign(f1 / f2);
return f1;
}
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;
}
}
}
//main.cpp
#include<iostream>
#include<iomanip>
#include"CFraction.h"
using namespace std;
void ShowFraction(CFraction f, string name, int i = 15)//i为输出精度
{
cout << name << '=' << f.GetNumerator() << '/' << f.GetDenominator() << '\t'
<< "分数值=" << setprecision(i) << f.GetFractionalValue() << endl;
}
int main()
{
try {
CFraction f1(15, 75);
ShowFraction(f1, "分数1");
f1.ReductionOfTheFraction();
ShowFraction(f1, "约分后,分数1");
ShowFraction(f1 / CFraction(1, 3), "(分数1)/(1/3)");
if (f1 < 0.25)
cout << "分数1<0.25" << endl;
f1.Assign(10000000000, 10000000001);
f1 *= CFraction(10000000001, 10000000000);
ShowFraction(f1, "(10000000000/10000000001)*(10000000001/10000000000)");
if (CFraction(165, 375).CanItBeAFiniteDecimal())
cout << "165/375可以化成有限小数" << endl;
else
cout << "165/375不能化成有限小数" << endl;
if (CFraction(7, 49).CanItBeAFiniteDecimal())
cout << "7/49可以化成有限小数" << endl;
else
cout << "7/49不能化成有限小数" << endl;
}
catch (invalid_argument except) {
cout << "出现参数无效异常!异常信息:" << except.what();
}
catch (...) {
cout << "出现其它类型异常!" << endl;
}
system("pause");
return 0;
}
程序运行结果如下: