大数取余???


/*
FileName: 大数取余.cpp Author: Dojking Version : V1.0 Date:2014/3/16 Function List: 1.int main() 主函数 2.void swap(); 交换两数 3.void strmod(); 模拟大数取余 4.void strsub(); 模拟大数减法 History: <author> <time> <version > <desc> Dojking 2014/3/16 1.0 build */ /************************************************* Function: void strmod() Description: 该函数用于模拟大数取余 Calls: 无 Called By: 1.main() Table Accessed: 无 Table Updated: 无 Input: 无 Output: 无 Return: 无 Others: 思路:我们用大数减法来模拟大数取余,(直到:str1 < str2)才退出循环,注意用字符串模拟整数时大小的判断。 其中需要注意一个问题:我们这里是用快速减法来模拟取余的,何为快速减法? 比如:1020 - 12 ,我们直接用1020 - 120 相当于一次减了10次12,此时str2 = 120,当str1 < 120时就退出了。 这不是我们想要的结果,所以,我们在快速减法进行到临界点的时候,又将str2 = strt = 12;(strt为我们首先保存的str2值) *************************************************/ /************************************************* Function: void strsub() Description: 该函数用于模拟大数减法 Calls: 无 Called By: 1.strmod() Table Accessed: 无 Table Updated: 无 Input: 无 Output: 无 Return: 无 Others: 思路:字符串按位相减,我们从最末位开始相减,也就是个位,这时牵涉到借位问题。 str1 str2 比如: 103 - 24 按位相减:个位3-4需要借位,而十位却是0,。我们是这样处理的。 将个位:3+10 - 4 = 9 (已借位)。而十位0被借之后,本来是-1,但是字符串只能储存一位,我们用f来代表-1。 str1 str2 变成:1f3 - 24 个位:9 现在求十位:f - 2又需要借位,f为-1,我们直接这样计算:-1+10-2 = 7 str1 str2 现在变成:073 - 24 个位,十位:97 然后,最前面的0,直接填在后面:970 最后去掉后面无效的0,并逆序,得到结果:79 *************************************************/ /************************************************ 举个例子:>> 1020 12 1020 % 12 我们这样模拟: str1 - str2= str1 1020 - 120 = 900 (str2末尾填0,直到str1,str2相差一位) 900 - 120 = 780 780 - 120 = 660 660 - 120 = 540 540 - 120 = 420 420 - 120 = 300 300 - 120 = 180 180 - 120 = 60 (注意:此时快速减法已经达到临界点,需要执行str2 = strt = 12) 60 - 12 = 48 48 - 12 = 36 36 - 12 = 24 24 - 12 = 12 12 - 12 = 0 (此时:str1 < strt = 12,break进入main) ----------- cout<<str1=0,所以结果就是0; ----------- 再举个例子: >> 6 5 6 % 5 如下模拟: str1 - str2 = str1 6 - 5 = 1 (此时:str1 < str2 = strt = 12,break进入main) ----------- cout<<str1=1,所以结果就是1; ----------- *************************************************/ #include <iostream> #include <string> using namespace std; string r, str1, str2,strt; /*str1:大数1,str2:大数2,r:每步的余数*/ void strsub() /*该函数用大数减法,模拟取余*/ { int i,j,len; int len1 = str1.size(); /*得到str1长度*/ int len2 = str2.size(); string str, mod; while (len1-1 > len2) /*使str1,str2位数相差一位*/ { str2 += '0'; /*增长str2*/ ++len2; } for (i = len1-1,j=len2-1; j >= 0; --i,--j) /*模拟减法*/ { if (str1[i] < str2[j] || str1[i] == 'f') /*需要借位,f表示-1*/ { if (str1[i-1] != '0') /*高位不为0*/ { str1[i-1] -= 1; /*向高位借位*/ } else /*高位为0,借位后变为-1,用f表示-1*/ { str1[i-1] = 'f'; /* f = -1 */ } if (str1[i] != 'f') /*本位不为f,执行 '-' 操作*/ str += ((str1[i]-'0')+10-(str2[j]-'0')+'0'); else /*本位为f,直接用-1代替*/ str += ((-1+10)-(str2[j]-'0')+'0'); } else /*不需要借位,直接 '-' 操作*/ { str += ((str1[i]-'0')-(str2[j]-'0')+'0'); } } if (len1 != len2) /*如果str1,str2长度不等,则需要单独对最高位操作*/ str += str1[0]; /*最高位*/ len = str.size()-1; while (str[len] == '0' && len != 0) /*去掉相减后高位上的无效0。(len!=0:防止只有一个0的情况)*/ { --len; } while (len >= 0) /*逆序*/ { mod += str[len]; --len; } str1 = mod; /*将中间结果赋值给str1,准备进行下一次strmod()操作*/ //cout<<"str1 = "<<str1<<", str2 = "<<str2<<endl; } void strmod() /*此函数作用相当于 str1 %= str2,注意str1,str2都是全局变量*/ { while (1) { if (str1.size() > str2.size() || (str1 >= str2 && str1.size() == str2.size()))/*假设将str1,str2看做数字,当str1<str2时跳出*/ strsub(); /*进行大数减法,模拟取余*/ else if (str1.size() > strt.size() || (str1 > strt && str1.size() == strt.size())) /*防止快速减法带来的错误*/ str2 = strt; else break; } } int main() { while (1) { cin>>str1>>str2; /*输入两个大数*/ if (str1[0] == '0' || str2[0] == '0') /*请不要输入0*/ { cout<<"input error"<<endl; break; } if (str1 < str2 && str1.size() <= str2.size()) /*如果str1 < str2,直接输出str1*/ { cout<<str1<<endl; } else { strt = str2; strmod(); /*大数求余*/ cout<<str1<<endl; /*输出求余结果*/ } } return 0; }

举个例子:>> 1020 12
1020 % 12 我们这样模拟:
str1 - str2= str1
1020 - 120 = 900    (str2末尾填0,直到str1,str2相差一位)
900  - 120 = 780
780  - 120 = 660
660  - 120 = 540
540  - 120 = 420
420  - 120 = 300
300  - 120 = 180
180  - 120 = 60    (注意:此时快速减法已经达到临界点,需要执行str2 = strt = 12)
60   - 12  = 48
48   - 12  = 36
36   - 12  = 24
24   - 12  = 12
12   - 12  = 0     (此时:str1 < strt = 12,break进入main)
-----------
cout<<str1=0,所以结果就是0;
-----------


 再举个例子: >> 6 5
 6 % 5 如下模拟:
 str1 - str2 = str1
 6    -  5   = 1   (此时:str1 < str2 = strt = 12,break进入main)
-----------
cout<<str1=1,所以结果就是1;

-----------

思路:我们用大数减法来模拟大数取余,(直到:str1 < str2)才退出循环,注意用字符串模拟整数时大小的判断。
 其中需要注意一个问题:我们这里是用快速减法来模拟取余的,何为快速减法?
 比如:1020 - 12  ,我们直接用1020 - 120 相当于一次减了10次12,此时str2 = 120,当str1 < 120时就退出了。
 这不是我们想要的结果,所以,我们在快速减法进行到临界点的时候,又将str2 = strt = 12;(strt为我们首先保存的str2值)

 思路:字符串按位相减,我们从最末位开始相减,也就是个位,这时牵涉到借位问题。
              str1  str2
 比如: 103 - 24
 按位相减:个位3-4需要借位,而十位却是0,。我们是这样处理的。
 将个位:3+10 - 4 = 9  (已借位)。而十位0被借之后,本来是-1,但是字符串只能储存一位,我们用f来代表-1。
            str1   str2 
 变成:1f3 - 24      个位:9
 现在求十位:f - 2又需要借位,f为-1,我们直接这样计算:-1+10-2 = 7
                     str1  str2
 现在变成:073 - 24  个位,十位:97
 然后,最前面的0,直接填在后面:970
 最后去掉后面无效的0,并逆序,得到结果:79

转载请保留原文地址:http://blog.csdn.net/dojking/article/details/21342493

一下是我的看法

由于我并没有手撕掉这个代码,所以复杂度不敢多说,估计复杂度不低。

我搜索这篇代码是因为我在做cf上一题时由于知识方面的缺失导致题做不了,所以来寻求大佬的帮助

当时题目的数据范围是10的1e6次方(也就是一共1e6+1位)根据这个函数取余的复杂度加上题目要求保守估计有复杂度会在1e12左右(也可能是我思路有问题,毕竟我是那么的菜)保守的我就没敢写,但这个大数取余的方法很好,毕竟实现它并不难希望以后可以学会一个更优秀的取余方法。

猜你喜欢

转载自www.cnblogs.com/fzw1523/p/9670461.html