假设我有n1
和n2
我希望将它们相乘
例如我有数组
n1={1,2,3};
并在
n2={5,6}
它们是n1
中的两个整数,我们有123
和n2
56
123*56=6888
然后结果我应该
result = {6,8,8,8}
这是我认为不完整的算法
for(i in n1 bigger array)
for(j in n2 smaller one)
{
mult=n1[i]*n2[j]
mult+= carry;
if(mult>=10)
{
carry = (mult/10);
mult-= (carry*10);
}
}
}
我怎么写呢?我不知道商店的位置 在完成内幕循环之后,我应该将num存储在数组中,然后再次计算并... 我该怎么写呢?我在这里搜索了整个溢出,但我没有在c代码中找到它
目标是计算大数字整数已8 Bytes,in other words 64 bits
,以便它们可以存储2pow64-1
19 digits
现在这将有助于计算超过19位的数字
答案 0 :(得分:3)
如果您的数字阵列是小端,那会稍微容易一些。然后你的例子乘法看起来
3 2 1 * 6 5
---------------
18 12 6
15 10 5
---------------
18 27 16 5 // now propagate carries
8 28 16 5
8 8 18 5
8 8 8 6
============
n1[i]
和n2[j]
的产品会对result[i+j]
产生影响。主循环可能大致看起来像
for (i = 0; i < l1; ++i) // l1 is length of n1
{
for (j = 0; j < l2; ++j) // l2 is length of n2
{
result[i+j] += n1[i]*n2[j];
}
}
// now carry propagation
您会发现结果必须至少为(l1-1) + (l2-1) + 1
长,因为最高有效数字的乘积为result[(l1-1) + (l2-1)]
。另一方面,n1 < 10^l1
和n2 < 10^l2
,因此产品为< 10^(l1+l2)
,您最多需要l1+l2
位数。
但是,如果您正在使用char
(已签名或未签名),则会在每个数字中快速溢出,因为(对于k <= min(l1-1,l2-1)
)k+1
两位数的产品(每个都可以很大) 81)贡献产品的数字k
。
因此,最好根据结果数字进行分组,以较大的类型进行累加,并在写入结果数字时进行进位传播。使用小端数字
char *mult(char *n1, size_t l1, char *n2, size_t l2, size_t *rl)
{
// allocate and zero-initialise, may be one more digit than needed
char *result = calloc(l1+l2+1,1);
*rl = l1 + l2;
size_t k, i, lim = l1+l2-1;
for (k = 0; k < lim; ++k)
{
unsigned long accum = result[k];
for (i = (k < l2) ? 0 : k-(l2-1); i <= k && i < l1; ++i)
{
accum += (n1[i] - '0') * (n2[k-i] - '0');
}
result[k] = accum % 10 + '0';
accum /= 10;
i = k+1;
while(accum > 0)
{
result[i] += accum % 10;
accum /= 10;
++i;
}
}
if (result[l1+l2-1] == 0)
{
*rl -= 1;
char *real_result = calloc(l1+l2,1);
for (i = 0; i < l1+l2-1; ++i)
{
real_result[i] = result[i];
}
free(result);
return real_result;
}
else
{
result[l1+l2-1] += '0';
return result;
}
}
对于大端数字,必须修改索引 - 你可以自己想出来,希望 - 但原则保持不变。
事实上,用铅笔和纸张跟踪指数后,结果差别不大:
char *mult(char *n1, size_t l1, char *n2, size_t l2, size_t *rl)
{
// allocate and zero-initialise, may be one more digit than needed
// we need (l1+l2-1) or (l1+l2) digits for the product and a 0-terminator
char *result = calloc(l1+l2+1,1);
*rl = l1 + l2;
size_t k, i, lim = l1+l2-1;
// calculate the product from least significant digit to
// most significant, least significant goes into result[l1+l2-1],
// the digit result[0] can only be nonzero by carry propagation.
for (k = lim; k > 0; --k)
{
unsigned long accum = result[k]; // start with carry
for (i = (k < l2) ? 0 : k-l2; i < k && i < l1; ++i)
{
accum += (n1[i] - '0') * (n2[k-1-i] - '0');
}
result[k] = accum % 10 + '0';
accum /= 10;
i = k-1;
while(accum > 0)
{
result[i] += accum % 10;
accum /= 10;
--i;
}
}
if (result[0] == 0) // no carry in digit 0, we allocated too much
{
*rl -= 1;
char *real_result = calloc(l1+l2,1);
for (i = 0; i < l1+l2-1; ++i)
{
real_result[i] = result[i+1];
}
free(result);
return real_result;
}
else
{
result[0] += '0'; // make it an ASCII digit
return result;
}
}
编辑:添加0终结符
注意:这些不是NUL
- 终止的(unsigned) char
数组,所以我们需要保留长度信息(这样做很好),因此将这些信息与数字一起存储会更好struct
中的数组。此外,正如所写,它只适用于正数。如果您只有原始数组,则处理负数很难,因此存储其他信息的另一点。
将数字保持为'0' + value
对于计算没有意义,它只对打印很方便,但只有当它们是NUL
时才会终止数组。您可能希望为NUL
- 终结符添加一个插槽。在这种情况下,我们存储产品长度的参数rl
并非绝对必要。
答案 1 :(得分:2)
绝对是一个有趣的问题。
以下是我的想法:
有了这个逻辑,你可以查看“ToInteger”或“ToString”方法如何处理数字,这将导致答案。
答案 2 :(得分:1)
考虑如何在纸上进行,因为您正在模拟乘以两个十进制数。对于初学者,我认为你会从最不重要的数字变为最重要的数字,所以你要计算索引(较大的数组为2,1,0;较小的数字为1)。此外,你必须安排在乘以n2[0]
(56中的5)时,你开始在十位增加,而不是单位。
答案 3 :(得分:0)
您无法在SO找到问题的完整C代码。你的第一种方法并不是那么糟糕。您可以执行以下操作:
a{1,2,3} -> 1*100 + 2*10 + 3*1
,易于实施如果您不能或者如果您不想处理动态数组分配,那么请考虑事先确定存储阵列的大小并执行静态分配。
修改强>
根据讨论的另一种方法:
假设r = n1 * n2
算法中还剩下一件事:确定目标数组的大小,根据中间数组中的信息,你可以用铅笔和纸来思考;)
答案 4 :(得分:0)
此代码未进行优化,也未考虑数组/数字的通用长度,但它应该为您提供如何实现算法的一般概念:
(这类似于string-to-int或int-to-string算法,只需将ASCII偏移添加到数组的每个项目即可。)
#include <stdio.h>
#include <stdint.h>
#define N1_N 3
#define N2_N 2
#define MAX_N 4 /* maximum array length allowed */
void print_array (const uint8_t* array, size_t size);
uint32_t array_to_ulong (const uint8_t* array, size_t size);
size_t ulong_to_array (uint8_t* array, size_t size, uint32_t val);
int main()
{
uint8_t n1[N1_N] = {1,2,3};
uint8_t n2[N2_N] = {5,6};
uint8_t n3[MAX_N];
size_t n3_size = MAX_N;
uint32_t n1_int;
uint32_t n2_int;
uint32_t result;
print_array(n1, N1_N);
printf(" * ");
print_array(n2, N2_N);
n1_int = array_to_ulong (n1, N1_N);
n2_int = array_to_ulong (n2, N2_N);
result = n1_int * n2_int;
printf(" = %d = ", result);
n3_size = ulong_to_array (n3, n3_size, result);
print_array(n3, n3_size);
getchar();
return 0;
}
void print_array (const uint8_t* array, size_t size)
{
size_t i;
printf("{");
for(i=0; i<size; i++)
{
printf("%d", array[i]);
if(i != size-1)
{
printf(", ");
}
}
printf("}");
}
uint32_t array_to_ulong (const uint8_t* array, size_t size)
{
uint32_t result = 0;
uint32_t multiplier = 1;
size_t i;
for(i=1; i<=size; i++)
{
result += array[size-i] * multiplier;
multiplier *= 10;
}
return result;
}
size_t ulong_to_array (uint8_t* array, size_t size, uint32_t val)
{
size_t i;
for(i=1; i<=size && val!=0; i++)
{
array[size-i] = val % 10;
val /= 10;
}
return i-1;
}
答案 5 :(得分:0)
12345 * 6789是: 12345 * 6 * 1000 + 12345 * 7 * 100 + 12345 * 8 * 10 + 12345 * 9 * 1
那就是: 1 * 6 * 1000 * 10000 + 2 * 6 * 1000 * 1000 + 3 * 6 * 1000 * 100 + 4 * 6 * 1000 * 10 + 5 * 6 * 1000 * 1 + 1 * 7 * 100 * 10000 + 2 * 7 * 100 * 1000 + 3 * 7 * 100 * 100 + 4 * 7 * 100 * 10 + 5 * 7 * 100 * 1 + 1 * 8 * 10 * 10000 + 2 * 8 * 10 * 1000 + 3 * 8 * 10 * 100 + 4 * 8 * 10 * 10 + 5 * 8 * 10 * 1 + 1 * 9 * 1 * 10000 + 2 * 9 * 1 * 1000 + 3 * 9 * 1 * 100 + 4 * 9 * 1 * 10 + 5 * 9 * 1 * 1
所以算法将每个值乘以每个值并将其加到(累积)到适当的结果数组元素(1000是10 ^ 3所以数组元素3(数组从零开始))。
然后通过结果数组移动并向大于10的结果移动到左边的div(从最右边开始)
答案 6 :(得分:0)
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
#define MAX 10000
char * multiply(char [],char[]);
int main(){
char a[MAX];
char b[MAX];
char *c;
int la,lb;
int i;
printf("Enter the first number : ");
scanf("%s",a);
printf("Enter the second number : ");
scanf("%s",b);
printf("Multiplication of two numbers : ");
c = multiply(a,b);
printf("%s",c);
return 0;
}
char * multiply(char a[],char b[]){
static char mul[MAX];
char c[MAX];
char temp[MAX];
int la,lb;
int i,j,k=0,x=0,y;
long int r=0;
long sum = 0;
la=strlen(a)-1;
lb=strlen(b)-1;
for(i=0;i<=la;i++){
a[i] = a[i] - 48;
}
for(i=0;i<=lb;i++){
b[i] = b[i] - 48;
}
for(i=lb;i>=0;i--){
r=0;
for(j=la;j>=0;j--){
temp[k++] = (b[i]*a[j] + r)%10;
r = (b[i]*a[j]+r)/10;
}
temp[k++] = r;
x++;
for(y = 0;y<x;y++){
temp[k++] = 0;
}
}
k=0;
r=0;
for(i=0;i<la+lb+2;i++){
sum =0;
y=0;
for(j=1;j<=lb+1;j++){
if(i <= la+j){
sum = sum + temp[y+i];
}
y += j + la + 1;
}
c[k++] = (sum+r) %10;
r = (sum+r)/10;
}
c[k] = r;
j=0;
for(i=k-1;i>=0;i--){
mul[j++]=c[i] + 48;
}
mul[j]='\0';
return mul;
}