课程设计 长整数四则运算.docx
《课程设计 长整数四则运算.docx》由会员分享,可在线阅读,更多相关《课程设计 长整数四则运算.docx(126页珍藏版)》请在冰豆网上搜索。
课程设计长整数四则运算
课程设计实验报告:
1.4长整数四则运算
题目:
长整数四则运算
一、实验内容
【问题描述】
设计一个实现任意长的整数进行加法运算的演示程序
【基本要求】
利用双向循环链表实现长整数的存储,每个结点含一个整形变量。
任何整形变量的范围是-(2^15-1)~(2^15-1)。
输入和输出形式:
按中国对于长整数的表示习惯,每四位一组,组间用逗号隔开。
【实现基本功能】
(i)是想长整数的四则运算;
(ii)实现长整数的乘方和阶乘运算;
(iii)整形量范围是-(2^n-1)~(2^n-1),其中n是由程序读入的参量。
输入数据的分组方法另行规定;
【实现加强版本的功能】
(i)四则运算在原来版本的基础上支持小数运算,除法还可以通过输入整数后加小数点与相应要求取的精确位数求出精确值,如:
求取3666除以7的后三位精确值,可以在输入时将除数输入为3666.000或3666.0000,就能得出相应的精确位数,当然求取后,没有余数的输出;
(ii)乘方的功能也进行了强化,支持小数操作;
(iii)添加了多个出错处理(即输入重操作)对相应数据输入与输出进行提示;
【加强版的实现原理】
(i)加减法运算加强:
在原来版本的基础上依照基本的加减法操作将数据用小数点进行分隔,记录下连个输入数的小数位长度,并将小数位较短的一个数据后补0直至小数位数相同,然后用函数处理输出的数据;
(ii)乘除法、乘方:
其处理方法较为简单,主要是记录数据中小数位数的长度,然后通过每种运算方式不同的运算原理截取小数位,再按照输出格式将数据处理进行输出;
(iii)根据定义,阶乘保持不变;
【特色分析】
(i)加强版程序加上了简单的声音提示,无论是输入与输出均会有八个音符的其中之一对输入与输出与否进行提示,同时在输入输出数据出错时,还会用三个音符对重输入进行提示,增强了人性化操作;
【测试数据】
(1)0;0;应输出“0”。
(2)-2345,6789;-7654,3211;应输出“-1,0000,0000”。
(3)-9999,9999;1,0000,0000,0000;应输出“9999,0000,0001”。
(4)1,0001,0001;-1,0001,0001;应输出“0”。
(5)1,0001,0001;-1,0001,0000;应输出“1”。
(6)-9999,9999,9999;-9999,9999,9999;应输出“1,9999,9999,9998”。
(7)1,0000,9999,9999;1;应输出“1,0001,0000,0000”。
二、实验目的
1、熟悉掌握双向循环链表的基本操作;
2、熟悉任意长字符串的输入,并实现把字符串转化为整数;
3、熟悉任意长整数的加法运算;
4、更进一步掌握有关类的操作
3、实验文档:
长整数四则运算
需求分析
(i)本程序实现计算任意长的整数的加法运算.以用户和计算机对话的方式,即在计算机终端上显示“提示信息”之后,由用户在键盘上输入演示程序中规定的运算命令,然后程序就计算并显示出这两个数的运算。
(ii)本演示程序中,集合的元素限定为数字字符[‘0’~’9’]和字符‘,’与‘;’,输入字符可以任意长,输入形式以“回车符”为结束标志,串中字符顺序不限,且允许出现重复字符。
(iii)利用双向循环链表现实长整数的存储,每个结点含一个整形变量。
输入的形式以回车结束,可以直接输入正数或负数。
按中国对于长整数的表示习惯,每四位一组,除数字和位于首位置的负号外,其它一切字符都将作为分隔符,连续多个分隔符当一个处理。
但不使用分隔符也不影响结果。
(iv)自行定义的测试数据
(1)0;0;输出“0”;
(2)-2345,6789;;-7654,3211;;加法输出“-1,000,000”;
(3)-9999,9999;;1,0000,0000,0000;;加法输出“9999,0000,0001”;
(4)1,0001,0001;;1,0001,0001;减法输出“0”;
(5)1,0001,0001;;1,0001,0000;;减法输出”1”;
(6)-9999,9999,9999;;-9999,9999,9999;加法输出“-1,9999,9999,9998”;
(7)1,0000,9999,9999;1;加法输出"1,0001,0000,0000";
(8)10;8;乘方输出"1,0000,0000";
(9)-98,9997;3;除法输出-32,9999;
(10)6;阶乘输出720;
四、概要设计
为实现上述程序功能,应以双向循环链表表示长整数。
为此,需要定义一个抽象数据类型。
1、抽象数据类型定义为:
ADTOrderedOperation{
数据对象:
D={ai|ai∈int,i=1,2,...n,n≥0}
数据关系:
R1={|ai-1,ai∈D|=2,……n}
基本操作:
Statusconversion(str,oprh)
//操作结果:
输入转换函数,将字符串形式的操作数转换成所需的类型
cmplinklen(opr1,opr2)
//操作结果:
比较链表长度函数,opr1链比opr2链长则返回1,短则返回-1,否则返//回0
length(oprr)
//操作结果:
求链表长度
StatusCreat(oprr,len)
//操作结果:
生成指定长度链表
compare(opr1,opr2)
//操作结果:
比较opr1、opr2绝对值的大小
Statusinit(oppr)
//初始化链表函数
Statusdistroy(oprr)
//销毁链表函数
Statusevaluate(opri,i)
//操作结果:
链表短赋值函数,将i的值转换成万进制类型,i为整形变量
Statusadd_bas(opr1,opr2,oprr)
//操作结果:
加法基本操作,本算法实现A,B相加的操作。
Statussub_bas(opr1,opr2,oprr)
//减法基本操作,本算法实现A,B相减的操作
Statusadd(opr1,opr2,oprr)
//操作结果:
带符号加法运算
Statussub(opr1,opr2,oprr)
//操作结果:
带符号减法函数
Statusimul(opr1,opr2,oprr)
//操作结果:
乘法运算
Statusidiv(opr1,opr2,quti,remand)
//操作结果:
除法运算
Statusimul_power(opr1,n,oprr)
//操作结果:
乘方运算,运用了二分思想,时间长度为lgN
Statusimul_factorial(opr1,oprr)
//操作结果:
阶乘运算
Statusoutput(oprr,str)
//操作结果:
输出的数据按四位一组,分隔符为","的格式
}ADTOrderedOperation
链表抽象数据类型的定义:
ADTList{
数据对象:
D={ai|ai∈ElemSet,i=1,2,…,n,n≧0}
数据关系:
R1={|ai-1,ai∈D,i=1,2,…,n}
基本操作:
Statusinitbuf(charstr[])
//操作结果:
缓冲区部分初始化函数,返回OK
intcmplinklen(NodeListopr1,NodeListopr2)
//操作结果:
opr1链比opr2链长则返回1,短则返回-1,否则返回0
intlength(NodeListoprr)
//操作结果:
计算链表长度,并返回链表长度的操作数
StatusCreat(NodeList&oprr,intlen)
//操作结果:
生成指定长度链表,返回OK
intcompare(NodeListopr1,NodeListopr2)
//操作结果:
比较opr1、opr2绝对值的大小
Statusinit(NodeList&oppr)
//操作结果:
初始化链表函数
Statusdistroy(NodeList&oprr)
//操作结果:
销毁链表函数,返回OK
Statusevaluate(NodeList&opri,inti)
//操作结果:
链表短赋值函数,将i的值转换成万进制类型,i为整形变量
}ADTOrderedList
2、本程序大体包含三个模块:
(i)主程序模块:
voidmain()
{
初始化;
do
{
接受命令;
处理命令;
}while(“命令”=”退出”)
}
(ii)集合单元模块——实现集合的抽象数据类型
(iii)结点结构单元模块——定义集合的结点结构
各模块之间的关系如下:
3、本程序细分为以下几大功能模块:
(i)输入模块;
(ii)输出模块;
(iii)预处理及相关操作模块
(iv)四则预算模块及(包含乘方、阶乘);
(v)主操作模块;
五、详细设计(伪代码)
1、头文件的定义部分
#include
#include
#include
#include
#include
#include
#defineLENsizeof(structNode)
#defineMAX1000
#defineOK1
#defineERROR0
#defineOVERFLOW-1
#defineTRUE1
#defineFALSE0
typedefchar_TCHAR;
typedefintStatus;
2、输入模块:
//求指数函数值
intaxp(inta,intk)
{
if(k==0)
return1;//k指数为零的情况
for(;k>0;k--)//指数结果处理
r=r*a;
returnr;
}
//输入转换函数
Statusconversion(charstr[],NodeList&oprh)
{//将字符串形式的操作数转换成所需的类型
k=buffer=0;
oprh=(NodeList)malloc(LEN);//申请长整数由字符串转换为链表的存储空间
oprh->next=oprh;
oprh->prior=oprh;
//初始化链表的前驱指针prior指针与后驱指针next
for(i=strlen(str)-1;i>=0;i--)
{
//出错判断处理,规范输入格式;若输入格式出错,则跳出转换程,并序重新输入
if(str[i]!
='-'&&str[i]!
='+')
{
buffer=buffer+(str[i]-'0')*axp(10,k);
k++;
if(k==4||str[i-1]=='-'||str[i-1]=='+'||i==0)
{//将新建结点插入到头结点之后
p=(NodeList)malloc(LEN);
oprh->next->prior=p;
p->prior=oprh;
p->next=oprh->next;
oprh->next=p;
p->data=buffer;
buffer=k=0;
}
}
}
//根据字符串输入的首位字符,确定链表的数据类型是正整数还是负整数,返回OK
}
//输入函数
Statusinput(NodeList&opr1,NodeList&opr2,charstr[])
{
//分别输入连个字符串并进行判断,直至输入成功则返回OK
}
Statusinput1(NodeList&opr1,int&n,charstr[])
{
//分别输入乘方的底数和指数两个操作数,直至输入成功返回OK
}
Statusinput2(NodeList&oprr,charstr[])
{
//只是输入阶乘的一个正整数,直至输入成功返回OK
}
3、输出模块:
//输出函数
Statusoutput(NodeListoprr,charstr[])
{
if(!
oprr)
returnERROR;//判断用链表记录的运算结果是否为空(出错),返回FALSE
p=oprr;//指针对链表进行遍历
initbuf(str);//清空字符串数组str的内容
//符号位判断,若为负数,在字符串的首位加‘—’
p=p->next;
if(p->next==oprr&&p->data==0)//若要输出的数为0则执行
str[i++]='0';
else
while(p!
=oprr)
{
//每千位进行取余数运算
while(j<4)
{
if(num[j]!
=0||(str[0]=='-'&&str[1]!
='\0')||(str[0]!
='-'&&str[0]!
='\0'))
//此判断语句是为了避免输出诸如:
00123…的情况
//规范字符串的处理,消除长整数前面的0,每四位进行一个循环操作
}
//指针后移,并重新计算操作位
}
//取字符串长度
//从低位到高位开始,按每四位数用一个‘,’将数据进行分割,并记录在新的字//符串数组str1翻转输出,并返回OK
}
4、预处理相关项操作模块(双向链表的相关ADT的操作):
typedefstructNode
{
intdata;//数据域
structNode*prior,*next;//前驱指针prior,后驱指针next
}Node,*NodeList;
双向链表的基本操作设计如下:
Statusinitbuf(charstr[])
//操作结果:
缓冲区部分初始化函数,返回OK
intcmplinklen(NodeListopr1,NodeListopr2)
//操作结果:
opr1链比opr2链长则返回1,短则返回-1,否则返回0
intlength(NodeListoprr)
//操作结果:
计算链表长度,并返回链表长度的操作数
StatusCreat(NodeList&oprr,intlen)
//操作结果:
生成指定长度链表,返回OK
intcompare(NodeListopr1,NodeListopr2)
//操作结果:
比较opr1、opr2绝对值的大小
Statusinit(NodeList&oppr)
//操作结果:
初始化链表函数
Statusdistroy(NodeList&oprr)
//操作结果:
销毁链表函数,返回OK
Statusevaluate(NodeList&opri,inti)
//操作结果:
链表短赋值函数,将i的值转换成万进制类型,i为整形变量
其中部分操作的伪代码如下:
Statusinitbuf(charstr[])
{
//缓冲区部分初始化函数,返回OK
}
//比较链表长度函数
intcmplinklen(NodeListopr1,NodeListopr2)
{
//opr1链比opr2链长则返回1,短则返回-1,否则返回0
}
intlength(NodeListoprr)
{
//计算链表长度,并返回链表长度的操作数
}
StatusCreat(NodeList&oprr,intlen)
{
//生成指定长度链表,返回OK
}
intcompare(NodeListopr1,NodeListopr2)
{//比较opr1、opr2绝对值的大小
p1=opr1->next;
p2=opr2->next;//取指针进行操作
if(cmplinklen(opr1,opr2)==1)//opr1比较长
return1;
elseif(cmplinklen(opr1,opr2)==-1)//opr2比较长
return-1;
else//长度相等的情况
{
while(p1->data==p2->data&&p1->next!
=opr1)
//注意不要少了p1->next!
=opr1这个条件
{
p1=p1->next;
p2=p2->next;
}
//比较长度,分别返回操作值-1,0,1
}
}
Statusinit(NodeList&oppr)
{
//初始化链表函数
}
Statusdistroy(NodeList&oprr)
{
//销毁链表函数,返回OK
}//distroy
Statusevaluate(NodeList&opri,inti)
{//链表短赋值函数,将i的值转换成万进制类型,i为整形变量
opri=(NodeList)malloc(LEN);
opri->data='+';
opri->next=(NodeList)malloc(LEN);
opri->next->data=i;
opri->next->next=opri;
opri->prior=opri->next;
opri->next->prior=opri;
returnOK;
}//evaluate
5、加减法模块
//加法基本操作
Statusadd_bas(NodeListopr1,NodeListopr2,NodeList&oprr)
{//本算法实现A,B相加的操作。
oprr=(NodeList)malloc(LEN);
//初始化前驱指针prior与后驱指针next,并用p1,p2进行指针操作
CF=buffer=0;
while(p1!
=opr1&&p2!
=opr2)
{
buffer=p1->data+p2->data+CF;
CF=buffer/10000;//若buffer的值大于9999则产生进位,赋给CF
//将新建结点插入到头结点之后
p3=(NodeList)malloc(LEN);//结点存储空间
oprr->next->prior=p3;
//前驱指针与后驱指针互换
p3->data=buffer%10000;//应该将buffer的第四位赋给p3->data
//..........................
//指针进入下一个双向链表的结点
}
while(p1!
=opr1)
{//处理opr1链的剩余部分
buffer=p1->data+CF;
CF=buffer/10000;
//将新建结点插入到头结点之后
p3=(NodeList)malloc(LEN);
oprr->next->prior=p3;
p3->prior=oprr;
p3->next=oprr->next;
oprr->next=p3;
p3->data=buffer%10000;
//..........................
p1=p1->prior;
}
while(p2!
=opr2)
{//处理opr2链的剩余部分
buffer=p2->data+CF;
CF=buffer/10000;
//将新建结点插入到头结点之后
p3=(NodeList)malloc(LEN);
oprr->next->prior=p3;
//前驱指针与后驱指针互换
p3->data=buffer%10000;
//..........................
p2=p2->prior;
}
if(CF)
{//判定进位,并进行进位操作
p3=(NodeList)malloc(LEN);
oprr->next->prior=p3;
p3->prior=oprr;
p3->next=oprr->next;
oprr->next=p3;
p3->data=CF;
}
//添加长整数类型符号,并返回OK
}
//减法基本操作
Statussub_bas(NodeListopr1,NodeListopr2,NodeList&oprr)
{//本算法实现A,B相减的操作。
//将A链分成与B链长相等的底位部分,和剩余的高位部分,并做相应处理。
oprr=(NodeList)malloc(LEN);
//前驱指针prior与后驱指针next置空,并用p1,p2进行指针操作
CF=buffer=flag=0;
while(p2!
=opr2)
{//opr2链的长度小于等于opr1链的
if(p1->data<(p2->data+CF))
//判断进位CF,并进行进位操作
p3=(NodeList)malloc(LEN);
oprr->next->prior=p3;
//前驱指针与后驱指针互换
p3->data=buffer;
p1=p1->prior;
p2=p2->prior;
}
while(p1!
=opr1)
{//处理opr1链剩下的部分
if(p1->data//判断进位CF,并进行进位操作
p3=(NodeList)malloc(LEN);
oprr->next->prior=p3;
//前驱指针与后驱指针互换
p3->data=buffer;
p1=p1->prior;
}
//处理链表开头结点值为0的无意义情况,若链表本身表示0,则不做如下处理
p3=oprr->next;
while(p3->data==0&&p3->next!
=oprr)
{
p3=p3->next;
flag=1;
}
if(flag)
{
qh=oprr->next;//保存无用结点的头尾指针
qt=p3->prior;//为释放做准备
oprr->next=p3;//重接next链
p3->prior=oprr;//重接prior链
qt->next=NULL;
while(qh!
=NULL)
{//释放无用结点
qq=qh;
qh=qh->next;
free(qq);
}
}
//--------------------------------------------------------
//添加符号,返回OK
}
//带符号加法函数
Statusadd(NodeListopr1,NodeListopr2,NodeList&oprr)
{
//出错处理:
若opr1或opr2为空,返回FALSE