我正在尝试编写一个程序,它将接收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。是否有一个处理这个的库?找不到类似的东西。
答案 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