C 乘以大数

Posted

技术标签:

【中文标题】C 乘以大数【英文标题】:C multiplying large numbers 【发布时间】:2019-05-20 23:41:21 【问题描述】:

以下 C 程序将大数乘以字符串。它适用于正数,但使用大量内存时会使用太多内存。如何改进它以使用更少的内存?

我的程序:

char *strrev(char *str) 
        char *p1, *p2;

        if(!str || !*str)
            return str;

        for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) 
            *p1 ^= *p2;
            *p2 ^= *p1;
            *p1 ^= *p2;
        
        return str;
    

    char* addNumbers(char* c1, char* c2) 

        char *m1;
        char *m2;


        if (strlen(c1) >= strlen(c2)) 
            m1 = malloc(sizeof(c1));
            m2 = malloc(sizeof(c2));
            strcpy(m1, c1);
            strcpy(m2, c2);
         else 
            m1 = malloc(sizeof(c2));
            m2 = malloc(sizeof(c1));
            strcpy(m1, c2);
            strcpy(m2, c1);
        

        strrev(m1);
        strrev(m2);

        int lm1 = strlen(m1);
        int lm2 = strlen(m2);

        //char *w = malloc(1000000);
        char its;
        int jd = 0;
        for (int l = 0; l < lm1; l++) 
            int w1 = strToInt(m1[l]);
            int w2;
            if (l < strlen(m2)) 
                w2 = strToInt(m2[l]);
             else 
                w2 = 0;
            
            int w3 = w1 + w2 + jd;
            if (w3 > 9) 
                jd = 1;
                w3 = w3 % 10;
             else 
                jd = 0;
            
            its = w3 + 48;
            m1[l] = its;
        
        if (jd > 0) 
            char its2[12];
            sprintf(its2, "%d", jd);
            strcat(m1, its2);
        

        return strrev(m1);
    

    int main(int argc, char* argv[]) 
        char *c1;
        char *c2;
        if (strlen(argv[1]) > strlen(argv[2])) 
            c1 = malloc(sizeof(argv[1]));
            c2 = malloc(sizeof(argv[2]));
            strcpy(c1, argv[1]);
            strcpy(c2, argv[2]);
         else 
            c1 = malloc(sizeof(argv[2]));
            c2 = malloc(sizeof(argv[1]));
            strcpy(c1, argv[2]);
            strcpy(c2, argv[1]);
        
        char counter[sizeof(c2)];
        sprintf(counter, "%d", 0);
        char one[2];
        sprintf(one, "%d", 1);
        char *w = malloc(100);
        while (strcmp(counter, c2) != 0) 
            strcpy(counter, addNumbers(counter, one));
            strcpy(w, addNumbers(w, c1));
        
        printf("%s\n%s\n", c1, c2);
        free(c1);
        free(c2);
        printf("Result: %s,%ld\n\n", w,sizeof(w));
        free(w);
    

我知道存在更好的算法,但我必须使用addNumbers() 函数。

【问题讨论】:

请正确格式化您的问题。 sizeof pointer_char ==> strlen(pointer_char) + 1;你有几个要改变 至少有一个大问题:sizeof(c1) 不是字符串的长度。使用strlen。阅读 C 教科书中处理字符串的章节。 您可以查看 GMP(GNU 多精度库)。 gmplib.org/ 将大整数存储为二进制,这(a)更紧凑,(b)计算速度更快, BTW 现在不鼓励使用 XOR 交换值。使用临时变量。 【参考方案1】:

如何改进它以节省内存? 如所写,您的帖子包括对calloc() 的多个调用实例,每个实例都会创建堆内存,但所创建的内存都没有被释放,从而导致内存泄漏。至少,您的问题的答案是简单地对free() 的每次调用malloc() 进行相应的调用。

顺便说一下,关于何时、何地以及如何使用动态分配的内存herehere的讨论很好。

以下是addNumbers 函数的简化,同时保留其原始原型。根据 cmets 中的要求,它使用 ANSI C,没有其他库。它还具有集成字符串反转功能(消除strrev() 函数),仅使用一个动态分配的内存实例,并且没有泄漏。

请注意,该示例使用硬编码输入进行说明,但通过取消注释 scanf() 函数并添加命令行输入,可以轻松地将其转换为符合您的需求。

char* addNumbers(char* s1, char* s2) ;

int main(int argc, char *argv[])

    char s1[101] = "150353265326";
    char s2[101] = "22055653351";

    // Expect: 3316139500221184007426

    //scanf(" %s",s1);
    //scanf(" %s",s2);
    char * result = addNumbers(s1, s2); 


    printf("%s\n", result);

    free(result);

    return 0;



char* addNumbers(char* s1, char* s2) 

    int i=0, j=0, tmp;

    int l1 = strlen(s1);
    int l2 = strlen(s2);
    int a[100]=0,b[100]=0;
    int ans[200] = 0;
    char *result = calloc(l1+l2+1, 1);

    for(i = l1-1,j=0;i>=0;i--,j++)
    
        a[j] = s1[i]-'0';
    
    for(i = l2-1,j=0;i>=0;i--,j++)
    
        b[j] = s2[i]-'0';
    
    for(i = 0;i < l2;i++)
    
        for(j = 0;j < l1;j++)
        
            ans[i+j] += b[i]*a[j];
        
    
    for(i = 0;i < l1+l2;i++)
    
        tmp = ans[i]/10;
        ans[i] = ans[i]%10;
        ans[i+1] = ans[i+1] + tmp;
    
    for(i = l1+l2; i>= 0;i--)
    
        if(ans[i] > 0)
            break;
    

    for(j=i;j >= 0;j--)
    
        result[i-j] = (char)('0' + ans[j]);
    
    return result;

使用命令行输入测试:

注意:此改编归功于 this implementation.

【讨论】:

【参考方案2】:

分配但不释放它会占用大量内存。即使你释放它,你也有大量的分配、复制和释放。

与其那样做,你最好为结果分配空间,然后在相同的结果中累积,直到你的产品完成。

由于您的输入可以是 const 字符串,因此您应该只针对 main() 函数中的一个 malloc 来为结果分配空间,然后就地修改该空间。如果您需要反转输入字符串,那么您将需要更多的分配,但仅此而已。我不会在字符串中进行加法,而是使用 uint_8 数组并在开始时为每个输入进行一次 strToInt 转换,而不是在循环中多次。

【讨论】:

以上是关于C 乘以大数的主要内容,如果未能解决你的问题,请参考以下文章

oj---九度oj----大数---进制转换

大数处理--阶乘计算

HDU 1023 Train Problem II 大数打表Catalan数

剑指 Offer 43. 1~n 整数中 1 出现的次数(为什么是大数这边数的个数乘以小数边数的个数)

[编程题]大数的运算

大数相乘 51nod 1027 水题