大数运算

来源:互联网 发布:嵌入式linux驱动教程 编辑:程序博客网 时间:2024/06/06 01:18

大数运算

    最近思考了关于大数运算的问题。我们知道在微型计算机中要想实现几十位甚至是上千位的四则运算是不可能的。我在网上找一些关于此类计算的问题,大概有两种解决方法,一种是用二进制和移位,这种方法非高手不能解之,另一种方法是用数组模拟人工手算。我花了4天左右时间把这个大数的四则运算程序写完了,其中加法,减法和乘法相对简单实现,唯独除法运算繁琐一些。我依次说明这四则运算的解决方法。(因为刚刚写完没有对代码进行优化,所以大家看它可能有些不适)

    加法运算:大概的思路是这样的,我们用两个字符串接受输入的字符,例如6 和 6.14 (这只是随便举的例子,并非特例)相加,用s1保存"6",s2保存"3.14",输出结果保存在一个整形数组resu中,这些数组的大数都是256,当然可以随意定义。要将6和6.14相加,这个小数点是最麻烦的,我们不妨将小数点先去掉,将6和3对齐,然后将从6和3的相加结果放入resu中,1和6也放入resu中,接着对resu中的数字进行进位操和,再移动小数点。

    将小数点去掉:

    要对齐整数位和小数位,我采用的方法是先获得小数点位置(每个整数后面默认有一个小数点,我用了#define POINT -1000 来表示小数点),然后两个小数点位置相减

较大数从resu的2号位置开始存放(我用数组0号位置作为符号位,1表示正,-1表标负,1号位置先空着,如果有进位可能要用到),较小的数从2+小数点位置相减之差,这样就完成了对齐操作:

 

    接着是进位和设置小数点:进位的方法很简单,相加之后从resu的2号位置开始的情况是这样的:

    只要从后面开始依次进位就行了。顺便把退位的函数也放一起:

    最后是要移运小数点,只要知道小数点位置较大值就行了,下面是移动小数点的函数代码和加法函数代码:
    
 
    减法运算:减法运算的基本思路和加法相同,唯一不同的是我们要比较两个无符号数的大小,用max指针指向较大数,min指针指向较小数,这样才能实现相减退位,至你手算的时候不会把无符号较小数放到上面,较大的放在下面这样计算吧呵。
    
 
    乘法运算:乘法运算的方法是先去除所有符号,用第二组字符串的末端数字字符转换成数值后依次从第一组字符的后面开始相乘,而后小数点位置由相者小数点位置相加结定:
 

 

 

    除法运算:我先写了几个要用于除法运算的函数,每个函数第一个“{”后我都写了说明:

    其中最后一个rid_sign函数重载了之前的函数,在这里只用于除法的去符号操作,因为在去除小数点后要进行补0操作。

    我举一个例子说明除法运算的程序执行过程:6 和 3.14,

              a.    去0后的结果为600和314,即是600(temp1) 除314 (  temp2)

              b.   600 - 314 = 286 (tempDiv), 执行正数操作,resu[i]++, 继续进行减法操作

              c.   因为 286 - 314 < 0 , 执行负数操作, 若下一次减法运算小于0,则该位置商0, 若下一位置没有除数或为0,则插入0,否则插入除数下一位置的数resu的索引  i++,即商到了下一位。

    d.   若相数结果相减 = 0, 仍要进行一次判断,若temp1不为空则将其加入到 tempDiv 中。

    e.  循环判断,若达到最大精度或是相除已经有结果,则退出循环。

int* divi(char* s1, char * s2){//除法/*定义变量*/char temp1[MAX], temp2[MAX];//无符号的s1,s2char tempDiv[MAX] = {""};//用于保存前n位除数int* resu = new int[MAX];//商的结果int* nArr = new int[MAX];//减法所得结果int i = 0, j = 0, m = 0, n = 0, len1 = 0, len2 = 0;//无符号S1,S2的长度bool isSetPoint = false;//是否设置小数点/*初始化*/for(i = 0; i < MAX; i++){//初始化整形结果数组resu,字符串subStrresu[i] = 0;nArr[i] = 0;}i = 0;rid_sign(s1, s2, temp1, temp2);len1 = strlen(temp1);//计算temp1的长度len2 = strlen(temp2);strncpy(tempDiv, temp1, len2);//复制前len2位除数到subStrwhile((j++ == -1) || (!isZero(nArr, MAX) && i < MAX)){nArr = sub(tempDiv, temp2);//除数前n位减被除数if(*nArr == -1){//负数if(isSet0(resu, i + 1)) //若下一次减法运算小于0,则该位置商0resu[i + 1] = 0;if(temp1[len2 + i] < '1'){//若下一位置没有除数或为0,则插入0,否则插入除数下一位置的数insert(tempDiv, '0');if(!isSetPoint && temp1[len2 + i] == '\0'){resu[i++ + 2] = POINT;isSetPoint = true;}}elseinsert(tempDiv, temp1[len2 + i]);i++;}else if(*nArr == 1){//正数m = 0;while(*(nArr + m) != POINT)m++;//判断是否置小数点标志if(i > 0){for(n = 0; n < i; n++)tempDiv[n] = '0';for(; n < m; n++)tempDiv[n] = '\0';}resu[i + 1] += 1;itos(nArr, tempDiv, 2);//前n位除数减被除数的值}else{//相等m = 0;while(*(nArr + m) != POINT)m++;if(i > 0){//清空tempDiv的值for(n = 0; n < i; n++)tempDiv[n] = '0';for(; n < m; n++)tempDiv[n] = '\0';}resu[i + 1] += 1;itos(nArr, tempDiv, 2);if(temp1[len2 + i] != '\0'){//判断除数下一位置是否有数值if(isSet0(resu, i + 1)) //若下一次减法运算小于0,则该位置商0resu[i++ + 1] = 0;insert(tempDiv, temp1[len2 + i]);}else{//若没有数值则退出if(!isSetPoint && temp1[len2 + i] == '\0'){resu[i + 2] = POINT;isSetPoint = true;}break;}i++;}}if(!((int)(s1[0] - '-') * (int)(s2[0] - '-')))//判断正负号resu[0] = -1;elseresu[0] = 1;return resu;//返回结果数组}


 

    

 

 

 

0 0
原创粉丝点击