大作业题(一)

作业题(一),题目描述:

有理数运算

问题描述

有理数是一个可以化为一个分数的数,例如2/3,533/920,-12/49都是有理数,而就为无理数。在C++中,并没有预先定义有理数,需要时可以定义一个有理数类,将有理数的分子和分母分别存放在两个整型变量中。对有理数的各种操作都可以用重载运算符来实现。

基本要求

定义并实现一个有理数类,通过重载运算符+、-、*、/对有理数进行算术运算,通过重载运算符==实现判定两个有理数是否相等。写一个优化函数,它的作用是使有理数约去公分母,也即是使保存的有理数分子和分母之间没有公约数(除去1以外)。此外,还要定义一个将有理数转换为实数的函数,再加上构造函数和有理数输出函数。

测试数据

在应用程序中,创建若干有理数对象,通过带参数的构造函数使得各有理数对象值各不相同,然后分别进行各类运算,输出运算结果,检验其正确性。

实现提示

设有两个有理数a/b和c/d,则有:

(1) 有理数相加 分子=ad+bc;分母=b*d

(2) 有理数相减 分子=ad-bc;分母=b*d

(3) 有理数相乘 分子=ac; 分母=bd

(4) 有理数相除 分子=ad; 分母=bc

(5) 重载插入(<<)和提取(>>)运算符,使得对有理数可以直接输入输出。设有理数输入格式为:

整数1 整数2 //整数1为分子,整数2为分母

有理数输出格式为:

分子/分母

优化函数在创建有理数对象时应执行,在执行其它各种运算之后也需执行它,这样可保证所存储的有理数随时都是最优的。对于判断两个有理数是否相等,由于在对有理数进行各种运算后都对其进行优化,所以判定两个有理数是否相等只需判定它们两个的分子和分母分别相等即可。

Rational.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#ifndef _RATIONAL_H
#define _RATIONAL_H
#include <iostream>
using std::ostream;
using std::istream;
using std::cout;
using std::cin;
using std::endl;
class Rational { //有理数类
private:
int Down; //整数类型的分母
int Up; //整数类型的分子
public:
Rational(); //默认构造函数
Rational(int); //带一个参数的构造函数
Rational(int, int); //带两个参数的构造函数
Rational(const Rational&); //复制构造函数
void Print() const; //有理数的输出函数
void Optimise(); //有理数的优化函数
friend Rational operator +(Rational, Rational); //重载加号(+)运算符
friend Rational operator -(Rational, Rational); //重载减号(-)运算符
friend Rational operator *(Rational, Rational); //重载乘号(*)运算符
friend Rational operator /(Rational, Rational); //重载除号(/)运算符
friend bool operator ==(Rational, Rational); //重载判断相等(==)运算符
friend ostream & operator <<(ostream &, const Rational &); //重载提取(<<)运算符
friend istream & operator >>(istream &, Rational &); //重载插入(>>)运算符
operator double(); //将有理数类转化为实数的类型转换函数
};
#endif
Rational::Rational() { //默认构造函数,默认构造为0
Down = 1;
Up = 0;
}
Rational::Rational(int u) { //带一个参数的构造函数,参数为分子,分母默认为1
Down = 1;
Up = u;
}
Rational::Rational(int u, int d) { //带参数的构造函数,第一个参数为分子,第二个为分母
Down = d;
Up = u;
Optimise();
}
Rational::Rational(const Rational &r) { //复制构造函数
Down = r.Down;
Up = r.Up;
Optimise();
}
void Rational::Print() const{ //有理数的输出函数
cout << Up << '/' << Down;
}
void Rational::Optimise() { //有理数的优化函数
if (Down == 0) { //如果分母是0,输出提示,重新输入
cout << "错误,分母不能为0" << endl;
cout << "请重新输入分子和分母:";
cin >> *this;
}
if (Up == 0) { //如果这个有理数为0,那么分子不变,分母为1
Down = 1;
return; //函数结束
}
int p = Down, q = Up, t;
bool a = 0; //a作为一个判断有理数是否为负数的标志,默认a为假
if (p*q < 0) { //如果有理数为负数
a = 1; //a赋值为真
p = p > 0 ? p : (-p); //判断是否p为负数,如果是,将其变为相反数
q = q > 0 ? q : (-q); //同理判断q
}
if (p < q) { //欧几里得算法计算分子分母的最大公约数
t = q;
q = p;
p = t;
}
while (t = p % q, t != 0) {
p = q;
q = t;
} //欧几里得算法结束,q为最大公约数
Down /= q; //分子除以q
Up /= q; //分母除以q
Down = Down > 0 ? Down : (-Down);//判断分子是否为负,如果是,将其变为相反数
Up = Up > 0 ? Up : (-Up); //同理判断分母
if (a) Up = -Up; //如果有理数为负数,在分子前加符号
return; //函数结束
}
Rational operator +(Rational t, Rational r) { //重载加号(+)运算符
//不添加优化函数的原因是调用复制构造函数的时候会自动调用优化函数,不用特意添加
//不使用对象的引用的原因是想让有理数类可以直接和整数做运算
//定义为类的友元是为了满足和整数的交换律
return Rational(t.Up*r.Down+t.Down*r.Up, t.Down*r.Down);
}
Rational operator -(Rational t, Rational r) { //重载减号(-)运算符
return Rational(t.Up*r.Down-t.Down*r.Up, t.Down*r.Down);
}
Rational operator *(Rational t, Rational r) { //重载乘号(*)运算符
return Rational(t.Up*r.Up, t.Down*r.Down);
}
Rational operator /(Rational t, Rational r) { //重载除号(/)运算符
return Rational(t.Up*r.Down, t.Down*r.Up);
}
bool operator ==(Rational r1, Rational r2) { //重载判断相等(==)运算符
if (r1.Down == r2.Down&&r1.Up == r2.Up) return true;
else return false;
}
istream & operator>>(istream &in, Rational &r) { //重载插入(>>)运算符
int d, u;
in >> u >> d;
r.Down = d;
r.Up = u;
r.Optimise();
return in;
}
ostream & operator<<(ostream &out, const Rational &r) { //重载提取(<<)运算符
//使用常引用的原因是为了直接返回临时对象的值,比如两个有理数做运算之后的临时对象
out << r.Up << '/' << r.Down;
return out;
}
Rational::operator double() {
return double(Up) / double(Down);
}

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include "Rational.h"
using std::cout;
using std::cin;
using std::endl;
int main() {
cout << "--------------欢迎使用第八组的有理数程序!--------------" << endl;
cout << "------------------------测试开始------------------------" << endl;
cout << "------------第一项,测试构造、优化和输出函数------------" << endl;
cout << endl;
cout << "构造一个有理数r1,构造方式为r1(6,3)" << endl;
Rational r1(6,3);
cout << "使用Print函数输出r1,期望的结果是2/1" << endl;
r1.Print();
cout << endl;
cout << "构造一个有理数r2,构造方式为r2=7" << endl;
Rational r2 = 7;
cout << "使用Print函数r2,期望的结果是7/1" << endl;
r2.Print();
cout << endl;
cout << "构造一个有理数r3,构造方式为r3" << endl;
Rational r3;
cout << "使用Print函数r3,期望的结果是0/1" << endl;
r3.Print();
cout << endl << endl;
cout << "---------------------第一项测试完成---------------------" << endl;
cout << endl;
cout << "-----------------第二项,测试运算符的重载---------------" << endl;
cout << endl;
cout << "构造一个有理数r4,使用插入运算符录入分子分母" << endl;
Rational r4;
cin >> r4;
cout << "使用提取运算符输出r4的值" << endl;
cout << r4 << endl;
cout << "输出r4的实数值,若为超过六位的小数保留六位:" << double(r4) << endl;
cout << "使用提取运算符输出r1+r4的值" << endl;
cout << r1+r4 << endl;
cout << "使用提取运算符输出r1-r4的值" << endl;
cout << r1-r4 << endl;
cout << "给r1赋值为r4,计算r2*r1,r2/r1的值,并使用提取运算符输出" << endl;
r1 = r4;
cout << "r2*r1=" << r2*r1 << endl;
cout << "r2/r1=" << r2/r1 << endl;
cout << "判断r1和r4是否相等,若相等为1,不相等为0:" << (r1==r4) << endl;
cout << "---------------------第二项测试完成---------------------" << endl;
cout << "---------------------第三项测试开始---------------------" << endl;
cout << "请输入一个有理数:";
cin >> r1;
cout << "它的实数形式为(若为超过六位的小数保留六位):" << double(r1) << endl;
cout << "请输入另一个有理数";
cin >> r2;
cout << "它的实数形式为(若为超过六位的小数保留六位):" << double(r2) << endl;
cout << "两者相加的值为" << r1 + r2 << endl;
cout << "两者相减(前减后)的值为" << r1 - r2 << endl;
cout << "两者相乘的值为" << r1 * r2 << endl;
cout << "两者相除(前除以后)的值为" << r1 / r2 << endl;
cout << "---------------------第三项测试完成---------------------" << endl;
cout << "------------------------测试结束------------------------" << endl;
system("pause");
return 0;
}

作者

Uchiha Kakashi

发布于

2019-01-23

更新于

2019-11-26

许可协议