第一部分 实验题目和要求
1.1 问题描述
密码学分为两类密码:对称密码和非对称密码。对称密码主要用于数据的加/解密,而非对称密码则主要用于认证、数字签名等场合。非对称密码在加密和解密时,是把加密的数据当作一个大的正整数来处理,这样就涉及到大整数的加、减、乘、除和指数运算等,同时,还需要对大整数进行输出。请采用相应的数据结构实现大整数的加、减、乘、除和指数运算,以及大整数的输入和输出。
1.2 基本要求
- 要求采用链表来实现大整数的存储和运算,不允许使用标准模板类的链表类(list)和函数。同时要求可以从键盘输入大整数,也可以文件输入大整数,大整数可以输出至显示器,也可以输出至文件。大整数的存储、运算和显示,可以同时支持二进制和十进制,但至少要支持十进制。大整数输出显示时,必须能清楚地表达出整数的位数。测试时,各种情况都需要测试,并附上测试截图;要求测试例子要比较详尽,各种极限情况也要考虑到,测试的输出信息要详细易懂,表明各个功能的执行正确;
- 要求大整数的长度可以不受限制,即大整数的十进制位数不受限制,可以为十几位的整数,也可以为500多位的整数,甚至更长;大整数的运算和显示时,只需要考虑正的大整数。如果可能的话,请以秒为单位显示每次大整数运算的时间;
- 要求采用类的设计思路,不允许出现类以外的函数定义,但允许友元函数。主函数中只能出现类的成员函数的调用,不允许出现对其它函数的调用。
- 要求采用多文件方式:.h文件存储类的声明,.cpp文件存储类的实现,主函数main存储在另外一个单独的cpp文件中。如果采用类模板,则类的声明和实现都放在.h文件中。
- 不强制要求采用类模板,也不要求采用可视化窗口;要求源程序中有相应注释;
- 要求采用Visual C++ 6.0及以上版本进行调试;
1.3 运行结果与考核要求
【运行结果要求】要求能实现大整数的加、减、乘、除和指数运算,以及大整数的输入和输出,实验报告要求有详细的设计思路、功能测试截图。
【考核要求】要求程序能正常运行,全面完成题目要求。
第二部分 设计思路
2.1 系统总体设计
设计一个双向链表,用来存放大整数,每一个节点至多存放三位数字,一个链表代替一个大整数。要进行运算时读取出数字进行运算,最后将结果压入新的链表中。可以进行键盘输入和文件读取,可以将计算结果保存到文件中。可将计算结果转换为二进制,也支持负的大整数运算,实现了加、减、乘、除和指数运算。
2.3.3 流程图
2.3.3.1 加法
2.3.3.2 减法
2.3.3.3 乘法
2.3.3.4 除法
2.3.3.5 指数运算
2.4 主程序的设计
利用BigInt类中的menu();
其中利用了switch语句让用户选择要实现的功能
先出现第一个界面选择要进行的运算
选择后进入下一个界面,可按要求选择功能,支持二进制输入输出
第三部分 调试分析
3.1 技术难点分析
3.1.1 乘法
进行乘法时若采用最原始的一个个相加加上去要耗费许多时间,程序运行时间较长,采用了列表法进行计算。列出乘法表,将斜线间的数字相加。
如果用无符号长整数(范围0至~4294967295)作为累加变量,在最不利的情况下(两个乘数的所有数字均为9),能够累加约4294967295/(999*999)=4300次,也就是能够准确计算任意两个约不超过12900(每次累加的结果“值”三位,故4300*3=12900)位的整数相乘。如果4位4位地乘,在最不利的情况下,能过累加月4294967295/(9999*9999)=43次,仅能够确保任意两个不超过172位的整数相乘,没什么实用价值,更不要说5位了。
3.1.2 除法
和乘法一样,若用减法一个个减则耗费时间较长。此程序先判断除数的绝对值是否比被除数大。若大,则直接返回数字0;若小,则将其补位至位数相同,再开始减,减到要出现负数时,减一位再进行上述运算,直到位数与原先的相同再停止。正负情况可以设临时对象,使其变为正再进行运算,最后设置结果的正负。
第四部分 测试结果分析
number1和number2用于十进制加减法运算中的两个运算数
number4和number5用于二进制加减法运算中的两个运算数
number3用于存放运算结果
截取部分结果展示
二进制输出
十进制输出
4.2 错误数据测试
当输入数字块大于999时会自动忽略该数据块
源代码
#ifndef BigInt_hpp
#define BigInt_hpp
#include "Linkedlist.hpp"
const int DIGITS_PER_BLOCK = 3; //用于设置每个节点中最大数字的个数
class BigInt
{
public:
BigInt();
~BigInt();
void read(istream &in); //用于读入大整数
void display(ostream &out) const; //用于显示大整数
void push_back(const int value); //从后加入数字块
void push_front(const int value); //从前加入数字快
bool operator > (const BigInt &secondBigInt); //重载 >
bool operator < (const BigInt &secondBigInt); //重载 <
bool operator == (const BigInt &secondBigInt); //重载 ==
BigInt operator + (const BigInt &secondBigInt); //重载 +
BigInt operator - (const BigInt &secondBigInt); //重载 -
BigInt &operator = (const BigInt &secondBigInt); //重载 =
BigInt operator * (const BigInt &secondBigInt); //重载 *
BigInt operator / (const BigInt &secondBigInt); //重载 /
BigInt operator ^ (const BigInt &secondBigInt); //重载 ^
friend string decimal_to_dinary(BigInt &original); //友元函数 用于将大整数转化为二进制
BigInt dinary_to_decimal(string oringinal); //用于将二进制转化为十进制
void menu(); //用于显示菜单
private:
Linkedlist myList; //数字内容
};
inline istream & operator>>(istream &in, BigInt &number) //重载 >>
{
number.read(in);
return in;
}
inline ostream & operator<<(ostream &out, BigInt &number) //重载 <<
{
number.display(out);
return out;
}
#endif /* BigInt_hpp */
#ifndef Linkedlist_hpp
#define Linkedlist_hpp
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
#include <time.h>
using namespace std;
class Node
{
public:
int data; //数据
Node *prev; //前指正
Node *next; //后指针
Node():prev(0), next(0){}
Node(int item):data(item),prev(0),next(0){}
};
typedef Node* NodePointer;
class Linkedlist
{
public:
Linkedlist();
~Linkedlist();
bool empty() const; //判空
int getLenth() const; //得到长度
void setIsPositive(bool flag); //设置正负
bool getIsPositive() const; //获得正负信息
NodePointer begin() const; //返回头指针
NodePointer end() const; //返回尾指针
void push_back(const int value); //从后加入数字块
void push_front(const int value); //从前加入数字块
Linkedlist(const Linkedlist &original); //复制构造函数
Linkedlist &operator = (const Linkedlist &secondList); //重载 =
bool operator > (const Linkedlist &secondList); //重载 >
bool operator < (const Linkedlist &secondList); //重载 <
bool operator == (const Linkedlist &secondList); //重载 ==
Linkedlist operator + (const Linkedlist &secondList); //重载 +
Linkedlist operator - (const Linkedlist &secondList); //重载 -
Linkedlist operator * (const Linkedlist &secondList); //重载 *
Linkedlist operator / (const Linkedlist &secondList); //重载 /
Linkedlist operator ^ (const Linkedlist &secondList); //重载 ^
private:
NodePointer head; //头指针
NodePointer tail; //尾指针
int lenth; //链表长度
bool isPositive; //表示大整数正负 正为true, 负为false
};
#endif /* Linkedlist_hpp */