前言
在直接粘贴代码之前,我想先讲一讲这段代码的来历。我的第一篇CSDN就是关于类int_128的函数的。正如我在那篇结尾提及的那样,我当时就在考虑拓展完成那段代码的思路,真正将其改写为可以直接调用的函数。然而实际上,我也确实做了,但是效果及其不尽如人意。
由于当时刚学习C++,对于各种C++操作不熟悉,该代码在现在看来极其屎山。又由于上一代码为实现函数之间尽量独立,复制粘贴即可使用,导致其极为冗余复杂,出现了一些我当时无力理解修复的BUG,再加上由于本学期课业压力的逐渐加重,我闲置了这部分代码一段时间。
再此拾起这份工作还是三天前,我大致拓展了MD5信息指纹和RSA加密技术的相关算法(这些都是相当有意思的东西,以后有时间我会再详细说说),其中RSA算法中需要找到两个极大的质数,这就令我想到了这段代码,碰巧这段时间空闲时间较多,于是就花了大概三个晚自习了重新编写调试这段代码。
一、函数使用须知
- 为了尽量减少代码量,避免之前工作中出现的循环过多逻辑混乱,该组函数之间存在相互引用,若需使用某一函数,最好复制以下的所有函数。
- 本函数事实上定义了一数据类型(超长整数),由两部分组成:用于存储的数组L和表示存储所用位数的N,L使用该函数已自动更新,N由return返回。(至于为什么不直接用struct,是因为写完才想起来,懒得改了)
- 本段代码再Dev C++5.11上完成调试,可能在其他编译器上出现问题。
- LEN是规定的单个超长整数可使用存储空间,可自行根据需要更改。
- 本代码仅适用于整数类型的加减乘除。
二、代码
1.函数及其作用
int numToList(int L[],long long n); //已经证明可用
//将整数转化为超长整数;
long long listToNum(int L[],int N); //已经证明可用
//将超长整数转化为整数;
void printList(int L[],int N); //已经证明可用
//打印超长整数;
int LcomparList(int L1[],int L2[],int N1,int N2); //已经证明可用
//比较两超长整数大小;
int sumList(int L[],int N,long long num); //已经证明可用
//对超长整数做整数加法;
int LsumList(int L1[],int L2[],int N1,int N2); //已经证明可用
//将两个超长整数相加;
int multiList(int L[],int N,long long num); //已经证明可用
//对超长整数做整数乘法;
int LmultiList(int L1[],int L2[],int N1,int N2); //已经证明可用
//对超长整数做超长整数乘法;
int subList(int L[],int N,long long num); //已经证明可用
//对超长整数做整数减法;
int LsubList(int L1[],int L2[],int N1,int N2); //已经证明可用
//两个超长整数相减;
int divList(int L[],int times[],int N,int tN,long long num); //已经证明可用
//对超长整数做整除;
int remaList(int L[],int Left[],int N,long long num); //已经证明可用,效率低下
//对超长整数求余;
int LdivList(int L1[],int L2[],int times[],int N1,int N2,int tN); //已经证明可用
//对超长整数做超长整数除法;
int LremaList(int L1[],int L2[],int Left[],int N1,int N2); //已经证明可用,效率低下
//对超长整数做超长整数求余;
-
listToNum() 作用:结合存储于L中的超长整数与N,返回为longlong类型的num
-
printList() 作用:结合存储于L中的超长整数与N打印超长整数L
-
LcomparList() 作用:比较两个超长整数L1、L2的大小,根据大于等于小于分别返回1,0,-1
-
sumList() 作用:将常数num加至超长整数L上,返回新产生的N
-
LsumList() 作用:将超长整数L2加至L1上,返回新的L1的N1
-
multiList() 作用:将超长整数与一整数num相乘,返回新产生的N
-
LmultiList() 作用:取超长整数L1的超长整数L2倍,返回新产生的N1
-
subList() 作用:将超长整数L减去一常数num上,返回新产生的N
-
Lsublist() 作用:将超长整数L1减去L2,返回新的L1的N1
-
divList() 作用:将超长整数L整除一常数num,存入超长整数times中,返回times的tN
-
remaList() 作用:将超长整数L整除一常数num求余,存入超长整数Left中,返回Left的LN
-
LdivList() 作用:将超长整数L1整除超长常数L2,存入超长整数times中,返回times的tN
-
LremaList() 作用:将超长整数L整除超长常数L2求余,存入超长整数Left中,返回Left的LN
2.具体函数实现
代码如下:
#include <iostream>
#include <bits/stdc++.h>
#define LEN 100
using namespace std;
int numToList(int L[],long long n); //已经证明可用
//将整数转化为超长整数;
long long listToNum(int L[],int N); //已经证明可用
//将超长整数转化为整数;
void printList(int L[],int N); //已经证明可用
//打印超长整数;
int LcomparList(int L1[],int L2[],int N1,int N2); //已经证明可用
//比较两超长整数大小;
int sumList(int L[],int N,long long num); //已经证明可用
//对超长整数做整数加法;
int LsumList(int L1[],int L2[],int N1,int N2); //已经证明可用
//将两个超长整数相加;
int multiList(int L[],int N,long long num); //已经证明可用
//对超长整数做整数乘法;
int LmultiList(int L1[],int L2[],int N1,int N2); //已经证明可用
//对超长整数做超长整数乘法;
int subList(int L[],int N,long long num); //已经证明可用
//对超长整数做整数减法;
int LsubList(int L1[],int L2[],int N1,int N2); //已经证明可用
//两个超长整数相减;
int divList(int L[],int times[],int N,int tN,long long num); //已经证明可用
//对超长整数做整除;
int remaList(int L[],int Left[],int N,long long num); //已经证明可用,效率低下
//对超长整数求余;
int LdivList(int L1[],int L2[],int times[],int N1,int N2,int tN); //已经证明可用
//对超长整数做超长整数除法;
int LremaList(int L1[],int L2[],int Left[],int N1,int N2); //已经证明可用,效率低下
//对超长整数做超长整数求余;
int main() //测试函数,仅供各种测试使用
{
// long long n1 = 123123123123123;
// long long n2 = 10000000;
// int L1[LEN] = {0};
// int L2[LEN] = {0};
// int times[LEN] = {0};
// int tN = 1;
// int Left[LEN] = {0};
// int N1 = numToList(L1,n1);
// int N2 = numToList(L2,n2);
// N1 = LsubList(L1,L2,N1,N2);
// printList(L1,N1);
// N1 = LsubList(L1,L2,N1,N2);
// printList(L1,N1);
// N1 = multiList(L1,N1,n2);
// tN = divList(L1,times,N1,tN,3);
// tN = LdivList(L1,L2,times,N1,N2,tN);
// printList(times,tN);
// int LN = LremaList(L1,L2,Left,N1,N2);
// printList(Left,LN);
return 0;
}
//将整数转化为超长整数;
int numToList(int L[],long long n)
{
if(n<0) //在零位存储符号
{
n = -n;
L[0] = 1;
}
else
L[0] = 0;
int i = 1; //从L的第一位开始存;
while(true)
{
L[i] = n%1000000000; //将数字的每九位存入一个int单元;
n = n/1000000000;
if(n==0) //当n存完则结束;
break;
i++;
}
return i;
}
//将超长整数转化为整数;
long long listToNum(int L[],int N)
{
long long num = 0;
if(N>1000000000000000000)
{
cout<<"超出可存储长度"<<endl;
return 0;
}
for(int i=N;i>=1;i--)
num = num*1000000000+L[i];
return num;
}
//打印超长整数;
void printList(int L[],int N)
{
if(L[0]==1)
cout<<'-';
int i = N; //从最高位开始打印
while(true)
{
if(i==0) //如果打印完最后一个int,则停止;
break;
int j = 0; //填补该位
if(i!=N)
{
int num = L[i];
while(true)
{
num = num/10;
j++;
if(num==0)
break;
}
for(int k=0;k<9-j;k++)
cout<<"0";
}
cout<<L[i];
i--;
}
cout<<endl;
}
//比较两超长整数大小;(需引用LsubList)
int LcomparList(int L1[],int L2[],int N1,int N2)
{
int tempL1[LEN] = {0}; //复制L1,L2避免改变其中存储的值
int tempL2[LEN] = {0};
for(int i=0;i<=N1;i++)
tempL1[i] = L1[i];
for(int i=0;i<N2;i++)
tempL2[i] = L2[i];
int N = LsubList(tempL1,tempL2,N1,N2);
if(tempL1[0]==1)
return -1;
else
{
if(N==1&&tempL1[1]==0)
return 0;
else
return 1;
}
}
//对超长整数做整数加法;(需引用numToList,LsumList)
int sumList(int L[],int N,long long num)
{
int tempL[LEN];
int tempN = numToList(tempL,num);
return LsumList(L,tempL,N,tempN);
}
//对超长整数做整数减法;
int subList(int L[],int N,long long num)
{
int tempL[LEN];
int tempN = numToList(tempL,num);
if(tempL[0]==1)
tempL[0] = 0;
else
tempL[0] = 1;
return LsumList(L,tempL,N,tempN);
}
//将两个超长整数相加;
int LsumList(int L1[],int L2[],int N1,int N2)
{
int N; //预判加法执行后超长整数占位数
if(L1[0]==L2[0]) //两个超长整数的符号相同
{
N = max(N1,N2);
for(int i=1;i<=N;i++)
{
L1[i] += L2[i]; //各位int数值相加
if(L1[i]>=1000000000) //如果有即将溢出的,十位归零,上位进一
{
L1[i] = L1[i]%1000000000;
L1[i+1] += 1;
if(i==N) //如果是最高位的int即将溢出,对使用位数加一
{
N++;
break;
}
}
}
}
else //两超长整数一正一负
{
N = max(N1,N2);
if(L1[0]==1) //将负数标签转化为int内的符号
{
L1[0] = 0;
for(int i=1;i<=N1;i++)
L1[i] = -L1[i];
}
if(L2[0]==1) //将负数标签转化为int内的符号
{
L2[0] = 0;
for(int i=1;i<=N2;i++)
L2[i] = -L2[i];
}
for(int i=1;i<=N;i++)
{
L1[i] += L2[i];
}
while(L1[N]==0) //重新定位最高int
{
if(N==1)
break;
N--;
}
if(L1[N]<0) //判断最终为正还是为负~负
{
L1[0] = 1; //将符号标签设置为负
for(int i=1;i<=N;i++)
L1[i] = -L1[i]; //翻转,使得方式简化
for(int i=1;i<=N;i++)
{
if(L1[i]<0) //不够则上取下用
{
L1[i] = 1000000000+L1[i];
L1[i+1]--;
}
}
while(L1[N]==0) //再次重新定位最高位(可能最高位被1-1=0了)
{
if(N==1)
break;
N--;
}
if(L1[N]<0) //最高位为符号为负的唯一可能部分,该符号已经存储至L[0],将存储位转正
L1[N] = -L1[N];
}
else //判断最终为正还是为负~正
{
for(int i=1;i<=N;i++)
{
if(L1[i]<0) //不够则上取下用
{
L1[i] = 1000000000+L1[i];
L1[i+1]--;
}
}
while(L1[N]==0) //再次重新定位最高位(可能最高位被1-1=0了)
{
if(N==1)
break;
N--;
}
}
}
return N;
}
//两个超长整数相减;(需引用LsumList)
int LsubList(int L1[],int L2[],int N1,int N2)
{
int tempL2[LEN] = {0};
for(int i=0;i<=N2;i++)
tempL2[i] = L2[i];
if(tempL2[0]==1)
tempL2[0] = 0;
else if(tempL2[0]==0)
tempL2[0] = 1;
return LsumList(L1,tempL2,N1,N2);
}
//对超长整数做乘法;(需引用LsumList)
int multiList(int L[],int N,long long num)
{
bool iffu = 0;
if(num<0) //存符号,归正
{
num = -num;
iffu = 1;
}
int tempL[LEN] = {0};
for(int i=0;i<=N;i++) //复制输入的超长整数L到tempL中
tempL[i] = L[i];
int tempN = N;
for(int i=1;i<num;i++) //在L的基础上相加num-1次
N = LsumList(L,tempL,N,tempN); //对超长整数L的占位N进行重新赋值;
if(iffu) //返回符号
{
if(L[0]==1)
L[0] = 0;
if(L[0]==0)
L[0] = 1;
}
return N;
}
//对超长整数做超长整数乘法;
int LmultiList(int L1[],int L2[],int N1,int N2)
{
int tempL1[LEN] = {0};//将L1中的值转移至tempL2中进行操作,不改变L1的值
for(int i=0;i<=N1;i++)
tempL1[i] = L1[i];
int tempN1 = N1;
int tempL2[LEN] = {0};//将L2中的值转移至tempL2中进行操作,不改变L2的值
for(int i=1;i<=N2;i++)
tempL2[i] = L2[i];
int tempN2 = N2;
bool iffu = 0;
if(L2[0]==1)
iffu = 1;
int tL[LEN] = {0}; //对tempL2多次减法,小于零时停止,记录轮数
tempN2 = subList(tempL2,tempN2,1);
while(LcomparList(tempL2,tL,tempN2,1)==1)
{
N1 = LsumList(L1,tempL1,N1,tempN1);
tempN2 = subList(tempL2,tempN2,1);
}
if(iffu)
{
if(L1[0]==0)
L1[0] = 1;
if(L1[0]==1)
L1[0] = 0;
}
return N1;
}
//对超长整数做整除;(需引用subList,sumList,LcomparList)
int divList(int L[],int times[],int N,int tN,long long num)
{
bool iffu1 = 0;
bool iffu2 = 0;
if(num<0)
{
num = -num;
iffu2 = 1;
}
int tempL[LEN] = {0};
for(int i=1;i<=N;i++) //将L中的值转移至tempL中进行操作,不改变L的值
tempL[i] = L[i];
int tempN = N;
if(L[0]<0)
iffu1 = 1;
while(tempL[0]==0) //对tempL1多次减法,小于零时停止,记录轮数
{
tempN = subList(tempL,tempN,num);
tN = sumList(times,tN,1);
}
tN = subList(times,tN,1);
if(iffu1^iffu2)
times[0] = 1;
return tN;
}
//对超长整数求余;
int remaList(int L[],int Left[],int N,long long num)
{
bool iffu = 0;
Left[0] = 0;
if(num<0)
num = -num;
int LN = N; //将L中的值转移至Left中
for(int i=1;i<=N;i++)
Left[i] = L[i];
if(L[0]==1)
iffu = 1;
while(Left[0]==0) //对Left多次减法,小于零时停止
LN = subList(Left,LN,num);
LN = sumList(Left,LN,num); //补充多减的一步
if(iffu)
Left[0] = 1;
return LN;
}
//对超长整数做超长整数除法;(需引用LsubList,subList,sumList,LcomparList)
int LdivList(int L1[],int L2[],int times[],int N1,int N2,int tN)
{
int tempL1[LEN] = {0};
for(int i=0;i<=N1;i++) //将L1中的值转移至tempL1中进行操作,不改变L1的值
tempL1[i] = L1[i];
int tempN1 = N1;
while(tempL1[0]==0) //对tempL1多次减法,小于零时停止,记录轮数
{
tempN1 = LsubList(tempL1,L2,tempN1,N2);
tN = sumList(times,tN,1);
}
tN = subList(times,tN,1);
return tN;
}
int LremaList(int L1[],int L2[],int Left[],int N1,int N2)
{
int LN = N1; //将L1中的值转移至Left中
for(int i=0;i<=N1;i++)
Left[i] = L1[i];
while(!(Left[0]==1))
LN = LsubList(Left,L2,LN,N2);
LN = LsumList(Left,L2,LN,N2); //补充多减去的一步
return LN;
}
3.代码效果测评
- 使用乘法函数时尽量小数在后,可以提高效率
- 求商和求整的函数运算效率很低,非必要不使用
总结
本代码是我拓展RSA加密算法的衍生产品,在之前概念的基础上拓展了对负数的处理,希望对学习任务中有超大数字处理的同学有一定的帮助。
另外,由于时间有限,未对该代码做更加详细的测试,如果哪位同学在使用过程中发现了什么bug,请马上在评论中告知我,我会就代码做进一步的修改。