大整数的运算 实验报告

第一部分 实验题目和要求

1.1 问题描述

密码学分为两类密码:对称密码和非对称密码。对称密码主要用于数据的加/解密,而非对称密码则主要用于认证、数字签名等场合。非对称密码在加密和解密时,是把加密的数据当作一个大的正整数来处理,这样就涉及到大整数的加、减、乘、除和指数运算等,同时,还需要对大整数进行输出。请采用相应的数据结构实现大整数的加、减、乘、除和指数运算,以及大整数的输入和输出。

1.2 基本要求

  1. 要求采用链表来实现大整数的存储和运算,不允许使用标准模板类的链表类(list)和函数。同时要求可以从键盘输入大整数,也可以文件输入大整数,大整数可以输出至显示器,也可以输出至文件。大整数的存储、运算和显示,可以同时支持二进制和十进制,但至少要支持十进制。大整数输出显示时,必须能清楚地表达出整数的位数。测试时,各种情况都需要测试,并附上测试截图;要求测试例子要比较详尽,各种极限情况也要考虑到,测试的输出信息要详细易懂,表明各个功能的执行正确;
  2. 要求大整数的长度可以不受限制,即大整数的十进制位数不受限制,可以为十几位的整数,也可以为500多位的整数,甚至更长;大整数的运算和显示时,只需要考虑正的大整数。如果可能的话,请以秒为单位显示每次大整数运算的时间;
  3. 要求采用类的设计思路,不允许出现类以外的函数定义,但允许友元函数。主函数中只能出现类的成员函数的调用,不允许出现对其它函数的调用。
  4. 要求采用多文件方式:.h文件存储类的声明,.cpp文件存储类的实现,主函数main存储在另外一个单独的cpp文件中。如果采用类模板,则类的声明和实现都放在.h文件中。
  5. 不强制要求采用类模板,也不要求采用可视化窗口;要求源程序中有相应注释;
  6. 要求采用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 */

猜你喜欢

转载自blog.csdn.net/qq_41579622/article/details/81631166