将大数字乘以字符串

时间:2014-06-30 10:11:24

标签: c visual-studio-2010

我正在尝试编写一个程序,它将接收2个代表任意长度数字的字符串 (例如,char *a = "10000000000000";char *b = "9999999999999999";)并将它们相乘。 这是我到目前为止所提出的,不知道如何继续(nullify只是用'0'填充整个字符串):

char *multiply(char *hnum, const char *other)
{
    int num1=0, num2=0, carry=0, hnumL=0, otherL=0, i=0, temp1L=0, temp2L=0, n=0;
    char *temp1, *temp2;
    if(!hnum || !other) return NULL;

    for(hnumL=0; hnum[hnumL] != '\0'; hnumL++);
    for(otherL=0; other[otherL] != '\0'; otherL++);

    temp1 = (char*)malloc(otherL+hnumL);
    if(!temp1) return NULL;
    temp2 = (char*)malloc(otherL+hnumL);
    if(!temp2) return NULL;
    nullify(temp1);
    nullify(temp2);

    hnumL--;
    otherL--;
    for(otherL; otherL >= 0; otherL--)
    {
        carry = 0;
        num1 = other[otherL] - '0';
        for(hnumL; hnumL >= 0; hnumL--)
        {
            num2 = hnum[hnumL] - '0';
            temp1[i+n] = (char)(((int)'0') + ((num1 * num2 + carry) % 10));
            carry = (num1 * num2 + carry) / 10;
            i++;
            temp1L++;
        }
        if(carry > 0)
        {
            temp1[i+n] = (char)(((int)'0') + carry);
            temp1L++;

        }  

P.S。是否有一个处理这个的库?找不到类似的东西。

2 个答案:

答案 0 :(得分:1)

在纸面上,你可能会这样做:

 999x99
--------
   8991
  8991
========  
   98901

这个过程是从每个数字的右边开始乘以个别数字,并将它们相加,每次都记住(“9乘9等于81,写1,记住8”)。我很确定你在小学就读到了,不是吗?。

该过程可以很容易地放入算法中:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct result
{
    int carry;
    int res;
};

/*
 * multiply two numbers between 0 and 9 into result.res. If there is a carry, put it into
 * result.carry
 */
struct result mul(int a, int b)
{
    struct result res;

    res.res = a * b;
    if (res.res > 9)
    {
        res.carry = res.res / 10;
        res.res %= 10;
    }
    else
        res.carry = 0;

    return res;
}

/*
 * add
 * adds a digit (b) to str at pos. If the result generates a carry,
 * it's added also (recursively)
 */
add(char str[], int pos, int b)
{
    int res;
    int carry;

    res = str[pos] - '0' + b;
    if (res > 9)
    {
        carry = res / 10;
        res %= 10;
        add(str, pos - 1, carry);
    }
    str[pos] = res + '0';
}

void nullify(char *numstr, int len)
{
    while (--len >= 0)
        numstr[len] = '0';
}

int main(void)
{
    struct result res;
    char *mp1 = "999";
    char *mp2 = "999";
    char sum[strlen(mp1) + strlen(mp2) + 1];

    int i;
    int j;

    nullify(sum, strlen(mp1) + strlen(mp2));

    for (i = strlen(mp2) - 1; i >= 0; i--)
    {
        /* iterate from right over second multiplikand */
        for (j = strlen(mp1) - 1; j >= 0; j--)
        {
            /* iterate from right over first multiplikand */
            res = mul((mp2[i] - '0'), (mp1[j] - '0'));
            add(sum, i + j + 1, res.res);   /* add sum */
            add(sum, i + j, res.carry);     /* add carry */
        }
    }

    printf("%s * %s = %s\n", mp1, mp2, sum);

    return 0;
}

这与纸上的相同,不同之处在于您不需要记住单个的命令,因为我们会动态添加所有内容。

这可能不是最快的方法,但它不需要malloc()(假设你有一个C99编译器,否则你需要动态分配sum)并且可以任意工作长数(由于add()实现为递归函数,因此达到堆栈限制)。

答案 1 :(得分:0)

是的,有库可以解决这个问题。它实际上是一个相当大的主题领域,许多研究已经进入。我没有密切查看你的代码,但我知道大数字操作的库实现有very efficient algorithms,你不太可能自己发现。举个例子,我们在小学阶段(pre-common core)学到的乘法程序是乘法的O(n ^ 2)解,但是存在以~O(n ^ 1.5)求解它的方法。

标准的GNU c大数字库是GNU MP

https://gmplib.org/