将两个数组乘以int值

时间:2011-12-16 07:11:53

标签: c arrays

假设我有n1n2我希望将它们相乘 例如我有数组

n1={1,2,3};

并在

n2={5,6}   

它们是n1中的两个整数,我们有123n2 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位的数字

7 个答案:

答案 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^l1n2 < 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)

绝对是一个有趣的问题。

以下是我的想法:

  • 对于给定的数组,将每个值附加到字符串的末尾。因此,您按顺序构造一个数字字符串。 {1,2,3} =“123”
  • 然后,您使用可在其中一个C库中找到的“ToInteger”方法。现在你有了你的号码。

有了这个逻辑,你可以查看“ToInteger”或“ToString”方法如何处理数字,这将导致答案。

答案 2 :(得分:1)

考虑如何在纸上进行,因为您正在模拟乘以两个十进制数。对于初学者,我认为你会从最不重要的数字变为最重要的数字,所以你要计算索引(较大的数组为2,1,0;较小的数字为1)。此外,你必须安排在乘以n2[0](56中的5)时,你开始在十位增加,而不是单位。

答案 3 :(得分:0)

您无法在SO找到问题的完整C代码。你的第一种方法并不是那么糟糕。您可以执行以下操作:

  1. 乘以n1和n2,通过多重复制和加法完成转换,即。即a{1,2,3} -> 1*100 + 2*10 + 3*1,易于实施
  2. 计算乘法结果的数字(在循环内使用除法)
  3. 循环显示数字时,您可以将它们存储回另一个数组
  4. 如果您不能或者如果您不想处理动态数组分配,那么请考虑事先确定存储阵列的大小并执行静态分配。

    修改

    根据讨论的另一种方法:

    假设r = n1 * n2

    1. 创建一个n * m 2D数组,其中
      • n = n2
      • 中的位数
      • m = n1 + 1
      • 中的位数
    2. 在循环内将n1的每个数字与n2的一个元素相乘,将结果存储在数组中,将结果存储在2D数组中,不要忘记将进位添加到每个数字< / LI>
    3. 使用n2
    4. 的所有其他数字重复2
    5. 现在阵列已经填满,您必须像在纸上一样添加每个数字,将每个结果存储在目标数组中,再次处理进位
    6. 算法中还剩下一件事:确定目标数组的大小,根据中间数组中的信息,你可以用铅笔和纸来思考;)

答案 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;
}