在C中将一个数字数组乘以int

时间:2019-03-22 19:00:24

标签: c arrays multiplication

我有一个非常大的数字(> 100位数字长),因此无法将其存储为int甚至unsigned long long (aka uint64_t)。数组如下所示:
{5, 1, 2 ... 8, 6}
数组必须包含一位数字int


问题

将这个“数字”(保持为数组)乘以一位数字的简单且最重要的效率是什么?

我尝试过的事情

由于我是C语言的新手,所以这段代码不是杰作。远离它。

struct returnpointer { int * pointer; int length; };

returnpointer mul_arrays(int * x, int y, int lengthof_x) {
    returnpointer result_end;
    int result[lengthof_x * 2 + 1];
    int final_result[lengthof_x * 2 + 1];
    int carry = 0;
    int j = 0;
    //multiply 'y' by all digits of x, which creates multidigit ints
    //and also reverses the direction of the array (to allow carrying)
    for (int i = lengthof_x; i >= 0; i--) {
        result[j] = x[i] * y;
        j++;
    }
    int i = 0;
    j = lengthof_x
    //this is the bit that doesn't work: it attempts to work out the carry
    //however after hours of debugging I can't get it to work.
    while (carry > 0 || i < lengthof_x + 1) {
        if (result[j] > 9) {
            carry = result[j] / 10;
            final_result[i] = result[j] % 10;
            final_result[i + 1] = carry;
        } else {
            final_result[i] = result[j];
            carry = 0;
        }
        i++;
        j--;
    }
    result_end.pointer = result;
    result_end.length  = i + 1;
    return result_end;
}

此代码无法正常工作。这只是我尝试过的一个示例(如果成功,我将不会发布该示例)。

此外,很高兴知道我正在(尝试)使用的方法是否最有效,因为将其纳入的程序非常耗时,因此功能越快,整个过程所需的时间就越少程序将会执行。

谢谢。

编辑:

我的编译器是g ++。

3 个答案:

答案 0 :(得分:2)

根据要求,这是一个代码示例,该示例将数组乘以一位数字。该数组是小端的。举一个简单的例子,我假设数组的长度是固定的,一个更复杂的数组将分配数组内存,如果数组太大,则将其扩展。

#include <stdio.h>

#define BIGLEN 20

typedef struct {
    int length;
    int array[BIGLEN];
} biggy_t;

void bigmul(biggy_t *big, int mul)
{
    int carry = 0, partial;
    for(int i = 0; i < big->length; i++) {
        partial = big->array[i] * mul + carry;
        big->array[i] = partial % 10;
        carry = partial / 10;
    }
    if(carry) {
        big->array[big->length] = carry;
        big->length++;
    }
}

void bigout(biggy_t *big)
{
    for(int i = big->length-1; i >= 0; i--) {
        printf("%d", big->array[i]);
    }
}

int main(int argc, char *argv[])
{
    biggy_t big = { 6, { 5, 1, 2, 3, 8, 6 }};   // reverse order
    bigout(&big);
    printf(" * 7 = ");

    bigmul(&big, 7);
    bigout(&big);
    printf("\n");
}

程序输出

683215 * 7 = 4782505

我编写了一个bignum实现,可以在其中选择基数。字节存储为10或100,而32位存储为10或100。保持10的幂会使转换为十进制输出比2的基数更容易,并且由于不使用存储类型的全部容量而造成的时间损失较小。

答案 1 :(得分:1)

一些观察:

1)我认为不需要反转数组。只需将其从最低有效位到最高有效位进行处理即可。

2)没有理由存储大于允许的数字范围的临时值。随身携带随身携带,就像您手动进行时一样:

carry = 0
for i in all_the_digits:
    product = x[i]*y + carry
    x[i] = product%10
    carry = product/10

3)您可以将数字存储为uint8_t,而不必担心溢出-这将使您的数组成为当前大小的1/4,这会由于缓存效果而提高速度。

答案 2 :(得分:1)

您的代码中存在多个问题。不确定我是否发现了所有这些对象,但首先要介绍一些。

此循环:

for (int i = lengthof_x; i >= 0; i--) {
    result[j] = x[i] * y;
    j++;
}

执行“ lengthof_x + 1”次。换句话说-一次太多!您要将其更改为:

for (int i = lengthof_x - 1; i >= 0; i--) {  // notice the "- 1"
    result[j] = x[i] * y;
    j++;
}

您还有:

result_end.pointer = result;

但是似乎您已经在变量final_result中计算了结果,所以您返回了错误的数组。

但是-在任何情况下都不允许您返回指向本地数组的指针!函数返回时,它将超出范围。因此,即使您这样做:

result_end.pointer = final_result;

它仍然是无效代码。您需要malloc数组(这会影响性能)。

然后您拥有:

result_end.length  = i + 1;

因此,在全部情况下,您可以增加长度。错了只有在有进位时才应增加。

下面,我试图修复您的代码,即,我试图保持代码的整体结构,以便您可以看到自己在哪里犯了错误。

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

struct returnpointer { int * pointer; int length; };

void print_num(struct returnpointer * num)
{
        printf("len=%d\nvalue=", num->length);
    for(int i = 0; i <num->length; i++) {
        printf("%d", num->pointer[i]);
    }
}

struct returnpointer mul_arrays(int * x, int y, int lengthof_x) {
    struct returnpointer result_end;
    int result[lengthof_x + 1];

    // Multiply all element and revert array
    int j = 0;
    for (int i = lengthof_x-1; i >= 0; i--) {
        result[j] = x[i] * y;
        j++;
    }

    // Handle carry 
    int carry = 0;
    for (j = 0; j < lengthof_x; j++) {
        result[j] = result[j] + carry;
        carry = result[j] / 10;
        result[j] = result[j] % 10;
    }

    // Did length increase
    if (carry)
    {
        lengthof_x++;
        result[j] = carry;
    }

    // malloc result and revert back to desired format
    j = 0;
    int* final_result = malloc(lengthof_x * sizeof *final_result);
    for (int i = lengthof_x-1; i >= 0; i--) {
        final_result[j] = result[i];
        j++;
    }

    result_end.pointer = final_result;
    result_end.length  = lengthof_x;
    return result_end;
}


int main(int argc, char *argv[])
{
    int arr[] = { 5, 1, 2, 3, 8, 6}; 
    struct returnpointer num = mul_arrays(arr, 2, 6);  // 512386 * 2 -> 1024772
    print_num(&num);
}

输出:

len=7
value=1024772

但是请注意,这不是不是最佳解决方案...