首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

求帮优化 小弟我的高精度加减法以及乘法模块

2013-09-29 
求帮优化 我的高精度加减法以及乘法模块本帖最后由 SureEdding 于 2013-09-04 21:24:22 编辑//高精度加法v

求帮优化 我的高精度加减法以及乘法模块
本帖最后由 SureEdding 于 2013-09-04 21:24:22 编辑



//高精度加法

void plus(char *a, char *b, char *c)
{
int i, j, l;
int length1, length2;
int A[10005] = { 0 }, B[10005] = { 0 }, C[10005] = { 0 }, D[10005] = { 0 };
length1 = strlen(a);
length2 = strlen(b);
int counter = 0;

if (length1 >= length2)//取A和B较长的长度
l = length1;
else
l = length2;

for (i = 0; i < length1; i++)//将字符串转化为整形数组

{

A[i] = a[length1 - i - 1] - '0';

}

for (i = 0; i < length2; i++)
{

B[i] = b[length2 - 1 - i] - '0';

}

for (i = 0; i < l; i++)

{

C[i] += A[i] + B[i];   //c[i]表示结果的第i位

if (C[i] >= 10)   //当前的位和大于等于10 需进位

{

C[i + 1]++;   //下一位加1

C[i] -= 10;  //当前位减去10

}

}

if (C[l] > 0) l++; //处理最高位是否进位

//如999+1=1000 此时长度为l+1
for (i = 0; i < l; i++)
D[i] = C[l - i - 1];

j = 0;
for (i = 0; i < l; i++)
{
if (D[i] == 0)
{
counter++;
continue;
}
else
{
c[j++] = D[i] + '0';
goto o;
}
}
o:
for (j; j < l - counter; j++)
{
c[j] = D[++i] + '0';
}
c[j] = '\0';
if (c[0] == '\0')
{
c[0] = '0';
c[1] = '\0';
}
return;
}

//高精度减法

void minus(char *a, char *b, char *c)
{
int i, l;
int length1, length2;
int A[10005] = { 0 }, B[10005] = { 0 }, C[10005] = { 0 }, D[10005] = { 0 };
length1 = strlen(a);
length2 = strlen(b);

if (length1 > length2)
{
p:
if (length1 >= length2)//取A和B较长的长度
l = length1;
else
l = length2;

for (i = 0; i < length1; i++)//将字符串转化为整形数组

{

A[i] = a[length1 - i - 1] - '0';

}

for (i = 0; i < length2; i++)
{

B[i] = b[length2 - 1 - i] - '0';

}
for (i = 0; i < l; i++)

{

C[i] += (A[i] - B[i]);

if (C[i] < 0)  //借位操作

{

C[i + 1]--;

C[i] += 10;

}

}

while (C[l] == 0 && l > 0)

{

l--;

}

for (i = 0; i < l + 1; i++)
c[i] = C[l - i] + '0';

c[l + 1] = '\0';for (i = 0; i <= l; i++)
return;
}
else if (length1 < length2)
{
q:
if (length1 >= length2)//取A和B较长的长度
l = length1;
else
l = length2;

for (i = 0; i < length1; i++)//将字符串转化为整形数组

{

A[i] = a[length1 - i - 1] - '0';

}

for (i = 0; i < length2; i++)
{

B[i] = b[length2 - 1 - i] - '0';

}
for (i = 0; i < l; i++)

{

C[i] += (B[i] - A[i]);

if (C[i] < 0)  //借位操作

{

C[i + 1]--;

C[i] += 10;

}

}

while (C[l] == 0 && l > 0)

{

l--;

}

c[0] = '-';
for (i = 1; i < l + 2; i++)
c[i] = C[l - i + 1] + '0';

c[l + 2] = '\0';
return;
}
else
{
int P = strcmp(a, b);
if (P > 0)
goto p;
else if (P < 0)
goto q;
else
{
for (i = 0; i < length1; i++)
if (i == length1 - 1)
{
c[0] = '0';
c[1] = '\0';


}
}
}

}

//高精度乘法

void multiply(char* a, char* b, char* c)
{
int i, j, ca, cb, *s;
ca = strlen(a);
cb = strlen(b);
s = (int*) malloc(sizeof(int) * (ca + cb));
for (i = 0; i < ca + cb; i++)
s[i] = 0;
for (i = 0; i < ca; i++)
for (j = 0; j < cb; j++)
s[i + j + 1] += (a[i] - '0') * (b[j] - '0');
for (i = ca + cb - 1; i >= 0; i--)
if (s[i] >= 10)
{
s[i - 1] += s[i] / 10;
s[i] %= 10;
}
i = 0;
while (s[i] == 0)
i++;
for (j = 0; i < ca + cb; i++, j++)
c[j] = s[i] + '0';
c[j] = '\0';
free(s);
}


进行超大数据运算的时候觉得耗时太多

。。PS
如果我想将高精度乘法改成万进制该如何修改??
[解决办法]
思路跟你学的10进制是一样的,
你把超大整数很多1位数,这边把超大整数 每4位分解成一个short的整数 

1位数的加算 --》 4位数的加算,也就是2个short的加算,
超过10000,就进位,

static void Ladd(const short *a, const short *b, const int n, short *c)
{
short i, cy = 0;

for (i = n- 1; i >= 0; i--) {
c[i] = a[i] + b[i] + cy;
if (c[i]  < 10000) {
cy = 0;
} else {
c[i]  = c[i] - 10000;
cy = 1;
}
}
}
[解决办法]
GMP库参考一下。如果嫌庞大,参考下面:
#include <iostream>
#include <string>
using namespace std;
inline int compare(string str1,string str2) {//相等返回0,大于返回1,小于返回-1
         if (str1.size()>str2.size()) return 1; //长度长的整数大于长度小的整数
    else if (str1.size()<str2.size()) return -1;
    else                              return str1.compare(str2); //若长度相等,则头到尾按位比较
}
string SUB_INT(string str1,string str2);
string ADD_INT(string str1,string str2) {//高精度加法
    int sign=1; //sign 为符号位
    string str;
    if (str1[0]=='-') {
        if (str2[0]=='-') {
            sign=-1;
            str=ADD_INT(str1.erase(0,1),str2.erase(0,1));
        } else {
            str=SUB_INT(str2,str1.erase(0,1));
        }
    } else {
        if (str2[0]=='-') {
            str=SUB_INT(str1,str2.erase(0,1));
        } else { //把两个整数对齐,短整数前面加0补齐
            string::size_type L1,L2;
            int i;
            L1=str1.size();
            L2=str2.size();
            if (L1<L2) {
                for (i=1;i<=L2-L1;i++) str1="0"+str1;
            } else {
                for (i=1;i<=L1-L2;i++) str2="0"+str2;
            }
            int int1=0,int2=0; //int2 记录进位
            for (i=str1.size()-1;i>=0;i--) {
                int1=(int(str1[i])-'0'+int(str2[i])-'0'+int2)%10;
                int2=(int(str1[i])-'0'+int(str2[i])-'0'+int2)/10;


                str=char(int1+'0')+str;
            }
            if (int2!=0) str=char(int2+'0')+str;
        }
    }
    //运算后处理符号位
    if ((sign==-1)&&(str[0]!='0')) str="-"+str;
    return str;
}
string SUB_INT(string str1,string str2) {//高精度减法
    int sign=1; //sign 为符号位
    string str;
    int i,j;
    if (str2[0]=='-') {
        str=ADD_INT(str1,str2.erase(0,1));
    } else {
        int res=compare(str1,str2);
        if (res==0) return "0";
        if (res<0) {
            sign=-1;
            string temp =str1;
            str1=str2;
            str2=temp;
        }
        string::size_type tempint;
        tempint=str1.size()-str2.size();
        for (i=str2.size()-1;i>=0;i--) {
            if (str1[i+tempint]<str2[i]) {
                j=1;
                while (1) {//zhao4zhong1添加
                    if (str1[i+tempint-j]=='0') {
                        str1[i+tempint-j]='9';
                        j++;
                    } else {
                        str1[i+tempint-j]=char(int(str1[i+tempint-j])-1);
                        break;
                    }
                }
                str=char(str1[i+tempint]-str2[i]+':')+str;
            } else {
                str=char(str1[i+tempint]-str2[i]+'0')+str;
            }
        }
        for (i=tempint-1;i>=0;i--) str=str1[i]+str;
    }
    //去除结果中多余的前导0
    str.erase(0,str.find_first_not_of('0'));
    if (str.empty()) str="0";
    if ((sign==-1) && (str[0]!='0')) str ="-"+str;
    return str;
}
string MUL_INT(string str1,string str2) {//高精度乘法
    int sign=1; //sign 为符号位
    string str;
    if (str1[0]=='-') {
        sign*=-1;
        str1 =str1.erase(0,1);
    }
    if (str2[0]=='-') {
        sign*=-1;
        str2 =str2.erase(0,1);
    }
    int i,j;
    string::size_type L1,L2;
    L1=str1.size();
    L2=str2.size();
    for (i=L2-1;i>=0;i--) { //模拟手工乘法竖式
        string tempstr;
        int int1=0,int2=0,int3=int(str2[i])-'0';
        if (int3!=0) {
            for (j=1;j<=(int)(L2-1-i);j++) tempstr="0"+tempstr;
            for (j=L1-1;j>=0;j--) {
                int1=(int3*(int(str1[j])-'0')+int2)%10;


                int2=(int3*(int(str1[j])-'0')+int2)/10;
                tempstr=char(int1+'0')+tempstr;
            }
            if (int2!=0) tempstr=char(int2+'0')+tempstr;
        }
        str=ADD_INT(str,tempstr);
    }
    //去除结果中的前导0
    str.erase(0,str.find_first_not_of('0'));
    if (str.empty()) str="0";
    if ((sign==-1) && (str[0]!='0')) str="-"+str;
    return str;
}
string DIVIDE_INT(string str1,string str2,int flag) {//高精度除法。flag==1时,返回商; flag==0时,返回余数
    string quotient,residue; //定义商和余数
    int sign1=1,sign2=1;
    if (str2 == "0") {  //判断除数是否为0
        quotient= "ERROR!";
        residue = "ERROR!";
        if (flag==1) return quotient;
        else         return residue ;
    }
    if (str1=="0") { //判断被除数是否为0
        quotient="0";
        residue ="0";
    }
    if (str1[0]=='-') {
        str1   = str1.erase(0,1);
        sign1 *= -1;
        sign2  = -1;
    }
    if (str2[0]=='-') {
        str2   = str2.erase(0,1);
        sign1 *= -1;
    }
    int res=compare(str1,str2);
    if (res<0) {
        quotient="0";
        residue =str1;
    } else if (res == 0) {
        quotient="1";
        residue ="0";
    } else {
        string::size_type L1,L2;
        L1=str1.size();
        L2=str2.size();
        string tempstr;
        tempstr.append(str1,0,L2-1);
        for (int i=L2-1;i<L1;i++) { //模拟手工除法竖式
            tempstr=tempstr+str1[i];
            tempstr.erase(0,tempstr.find_first_not_of('0'));//zhao4zhong1添加
            if (tempstr.empty()) tempstr="0";//zhao4zhong1添加
            for (char ch='9';ch>='0';ch--) { //试商
                string str;
                str=str+ch;
                if (compare(MUL_INT(str2,str),tempstr)<=0) {
                    quotient=quotient+ch;
                    tempstr =SUB_INT(tempstr,MUL_INT(str2,str));
                    break;
                }
            }
        }
        residue=tempstr;
    }
    //去除结果中的前导0
    quotient.erase(0,quotient.find_first_not_of('0'));
    if (quotient.empty()) quotient="0";
    if ((sign1==-1)&&(quotient[0]!='0')) quotient="-"+quotient;
    if ((sign2==-1)&&(residue [0]!='0')) residue ="-"+residue ;
    if (flag==1) return quotient;
    else         return residue ;
}
string DIV_INT(string str1,string str2) {//高精度除法,返回商
    return DIVIDE_INT(str1,str2,1);


}
string MOD_INT(string str1,string str2) {//高精度除法,返回余数
    return DIVIDE_INT(str1,str2,0);
}
int main() {
    char ch;
    string s1,s2,res;

    while (cin>>s1>>ch>>s2) {
        switch (ch) {
            case '+':res=ADD_INT(s1,s2);break;
            case '-':res=SUB_INT(s1,s2);break;
            case '*':res=MUL_INT(s1,s2);break;
            case '/':res=DIV_INT(s1,s2);break;
            case '%':res=MOD_INT(s1,s2);break;
            default :                   break;
        }
        cout<<res<<endl;
    }
    return(0);
}


[解决办法]
大数运算,不是有对应的算法么,用算法优化才是真的。大师的算法,你就自己去网上查吧。
我给你说个简单的吧,比如A,B为1000位整数,令A=a1*10^500+a2,B=b1*10^500 + b2,
那么A*B = a1*b1*10^1000 + (a1*b2+a2*b1)*10^500 + a2*b2
        = a1*b1*10^1000 + [(a1+b1)*(a2+b2) - a1*b1 - a2*b2]*10^500 + a2*b2
如此便能用归并的思想递归。
计算下2者的复杂度,假设2个大数都为N位,主要考虑乘法运算的次数,那么你的不用说就是N^2。
而归并,第二步的优化后,计算式只需3次乘法。每个函数调用3个子函数,层数为logN - 1,那么总的复杂度为3*3^(logN - 1) = 3^logN。
或许你认为指数级的要高,但你用10w,100w,去试试就知道N^2 和 3^logN差多少了。 

热点排行