密码学之大数减法
2017-03-29 00:47
351 查看
大数减法是密码学中比较基础的算法。人人都要掌握。
实现原理:
1,采用字符数组存储输入的两个大数str1、str2。
2,设置一个能够容纳最大大数位数+1的字符数组result。
3,利用flag判断str1是否大于str2.flag=1表示大于,flag=0表示小于,flag=0表示等于。
4,较大数先与result同时从后往前遍历,较大数在result对应位置赋上较大数对应位置的值(个位给result个位赋值,十位给result十位赋值。。。)
5,较小数与result同时从后往前遍历,较小数在result对应位置减去较小数的值(result个位减去较小数的个位,result十位减去较小数的十位。。。)。
6,比较在相减时,是否需要往前借位。若需要,result[i-1]减一,result[i]加十。然后在进行减法运算。
7,在减完后,根据减数的正负,若保留result[0],赋为'-',表示负数。否则,去掉,数组往前移一位,表示正数。
示意图:
注:本人使用C语言,是为了展现算法的过程,让人了解原理。
所需头文件
核心代码
char *BigDataSub(const char *str_1, const char *str_2, char *result)
{
int len_1 = 0;
int len_2 = 0;
char flag = 1;//flag默认为1,正常进行减法
assert(str_1 && str_2 && result); //str_1,str_2,result不能为空
len_1 = strlen(str_1);//获取str_1长度
len_2 = strlen(str_2);//获取str_2长度
if (len_1 < len_2) //str1长度大于str2
flag = -flag;
else if (len_1 == len_2) //两个长度相同
{
flag = strncmp(str_1, str_2, len_1);//比较两者大小
if (flag < 0)
flag = -1;
else if (0 == flag) //当两者相等时,直接返回"0";
{
result[0] = '0';
return result;
}
}
if (flag == 1) //正常减,str_1大于str_2,len_1>=len_2
{
int i = 0;
int j = 0;
for (i = len_1; i > 0; --i) //先将str1赋给result
result[i] = str_1[i-1];
for (i = len_1, j = len_2; j > 0; --i, --j)//再与str2每一位进行比较,直到str2遍历完。
{
if (result[i] < str_2[j-1])//判断需要进位
{
result[i-1] -= 1;
result[i] += 10;
}
result[i] += '0' - str_2[j-1]; //注意将数字转换为字符。
}
memmove(result, result+1, len_1);//因为str1大于str2时,result[0]没必要存'+',去掉
result[len_1] = '\0'; //result数组往前移了一位,将空出来的最后一位置位结束符'\0'
}
else //反着减,str_1小于str_2
{
int i = 0;
int j = 0;
for (i = len_2; i > 0; --i)//先将str2赋给result
result[i] = str_2[i-1];
for (i = len_2, j = len_1; j > 0; --i,--j)//再与str1每一位进行比较,直到str2遍历完
{
if (result[i] < str_1[j-1])//判断需要进位
{
result[i-1] -= 1;
result[i] += 10;
}
result[i] += '0' - str_1[j-1];//注意将数字转换为字符。
}
result[0] = '-';//result[0]存储'-'
}
return result;
}
调用代码:
实现原理:
1,采用字符数组存储输入的两个大数str1、str2。
2,设置一个能够容纳最大大数位数+1的字符数组result。
3,利用flag判断str1是否大于str2.flag=1表示大于,flag=0表示小于,flag=0表示等于。
4,较大数先与result同时从后往前遍历,较大数在result对应位置赋上较大数对应位置的值(个位给result个位赋值,十位给result十位赋值。。。)
5,较小数与result同时从后往前遍历,较小数在result对应位置减去较小数的值(result个位减去较小数的个位,result十位减去较小数的十位。。。)。
6,比较在相减时,是否需要往前借位。若需要,result[i-1]减一,result[i]加十。然后在进行减法运算。
7,在减完后,根据减数的正负,若保留result[0],赋为'-',表示负数。否则,去掉,数组往前移一位,表示正数。
示意图:
注:本人使用C语言,是为了展现算法的过程,让人了解原理。
所需头文件
#include <stdio.h> #include <string.h> #include <assert.h>
核心代码
char *BigDataSub(const char *str_1, const char *str_2, char *result)
{
int len_1 = 0;
int len_2 = 0;
char flag = 1;//flag默认为1,正常进行减法
assert(str_1 && str_2 && result); //str_1,str_2,result不能为空
len_1 = strlen(str_1);//获取str_1长度
len_2 = strlen(str_2);//获取str_2长度
if (len_1 < len_2) //str1长度大于str2
flag = -flag;
else if (len_1 == len_2) //两个长度相同
{
flag = strncmp(str_1, str_2, len_1);//比较两者大小
if (flag < 0)
flag = -1;
else if (0 == flag) //当两者相等时,直接返回"0";
{
result[0] = '0';
return result;
}
}
if (flag == 1) //正常减,str_1大于str_2,len_1>=len_2
{
int i = 0;
int j = 0;
for (i = len_1; i > 0; --i) //先将str1赋给result
result[i] = str_1[i-1];
for (i = len_1, j = len_2; j > 0; --i, --j)//再与str2每一位进行比较,直到str2遍历完。
{
if (result[i] < str_2[j-1])//判断需要进位
{
result[i-1] -= 1;
result[i] += 10;
}
result[i] += '0' - str_2[j-1]; //注意将数字转换为字符。
}
memmove(result, result+1, len_1);//因为str1大于str2时,result[0]没必要存'+',去掉
result[len_1] = '\0'; //result数组往前移了一位,将空出来的最后一位置位结束符'\0'
}
else //反着减,str_1小于str_2
{
int i = 0;
int j = 0;
for (i = len_2; i > 0; --i)//先将str2赋给result
result[i] = str_2[i-1];
for (i = len_2, j = len_1; j > 0; --i,--j)//再与str1每一位进行比较,直到str2遍历完
{
if (result[i] < str_1[j-1])//判断需要进位
{
result[i-1] -= 1;
result[i] += 10;
}
result[i] += '0' - str_1[j-1];//注意将数字转换为字符。
}
result[0] = '-';//result[0]存储'-'
}
return result;
}
调用代码:
void test() { char str_1[1024] = {0};//存储number1 char str_2[1024] = {0};//存储number2 char result[1025] = {0};//存储result printf("输入number1:"); scanf("%s", str_1); printf("输入number2:"); scanf("%s", str_2); //大数减法 BigDataSub(str_1, str_2, result); //输出结果 printf("result = %s - %s = %s\n\n", str_1, str_2, result); } int main() { do{ test(); getchar(); printf("输入ctrl+z结束输入,输入Enter键继续。。。\n"); }while (getchar() != EOF); return 0; }