使用字符串乘以非常大的数字

时间:2015-01-18 15:33:41

标签: c string algorithm

我正在尝试编写一个C程序,该程序在不直接使用乘法运算符的情况下执行两个数的乘法,并且它应该考虑足够大的数字,以便即使通常添加这两个数也不能通过直接添加。

当我尝试(并且成功地)编写了一个使用字符串执行添加的C程序时,我的动机是这样的,我做了以下内容:

#include<stdio.h>
#define N 100000
#include<string.h>
void pushelts(char X[], int n){
int i, j;
for (j = 0; j < n; j++){
    for (i = strlen(X); i >= 0; i--){
        X[i + 1] = X[i];
    }
        X[0] = '0'; 
    }
}

int max(int a, int b){
    if (a > b){ return a; }
    return b;
}

void main(){
    char E[N], F[N]; int C[N]; int i, j, a, b, c, d = 0, e;
    printf("Enter the first number: ");
    gets_s(E);
    printf("\nEnter the second number: ");
    gets_s(F);
    a = strlen(E); b = strlen(F); c = max(a, b);
    pushelts(E, c - a); pushelts(F, c - b);
    for (i = c - 1; i >= 0; i--){
        e = d + E[i] + F[i] - 2*'0';
        C[i] = e % 10; d = e / 10;
    }
    printf("\nThe answer is: ");
    for (i = 0; i < c; i++){
        printf("%d", C[i]);
    }
    getchar();
}

它可以添加任意两个带“N”位的数字。现在,我将如何使用它来执行大数字的乘法运算?首先,我写了一个函数,它通过数字n(即0 <= n <= 9)执行数字的乘法,该数字将作为字符串输入。很容易看出这样的函数是如何写的;我叫它(*)。现在主要目的是将两个数字(作为一个字符串输入)相乘。我们可能会看到第k个数字的数字(假设它是a1a2 ..... ak):

a1a2...ak = a1 x 10^(k - 1) + a2 x 10^(k - 2) + ... + ak-1 x 10 + ak

因此,使用为加法和函数(*)设计的解决方案可以实现两个数字的相乘。

如果第一个数字是x1x2 ..... xn而第二个数字是y1y2 .... yk,那么:

x1x2...xn x y1y2...yk = (x1x2...xn) x y1 x 10^(k-1) + .....

现在函数(*)可以乘以(x1x2 ... xn)和y1,乘以10 ^(k-1)只是在数字旁边加上k-1零;最后,我们将所有这些k项相互添加以获得结果。但困难在于只知道每个数字包含多少位数,以便每次在设计用于将它们添加到一起的循环内执行添加。我已经考虑过做一个空数组,并且每次都将(x1x2 .... xn)乘以yi x 10 ^(i-1)的结果加到它上面,但就像我说的那样我无法精确所需的边界,我不知道每次在每个获得的结果前面添加多少个零,以便使用上述算法将其添加到空数组。当我必须从char类型转换为int类型并且相反地进行多次转换时,会出现更多困难。也许我让它变得比它应该更复杂;我不知道是否有更简单的方法可以做到这一点,或者是否有我不知道的工具。我是编程的初学者,我不了解基本工具。

有没有人提出解决方案,想法或算法?感谢。

3 个答案:

答案 0 :(得分:2)

我在SPOJ上遇到Small Factorials问题时开发了一种算法。

该算法基于小学乘法。在上学日,我们通过将第一个数字的每个数字乘以第二个数字的最后一个数字来学习两个数字的乘法。然后将第一个数字的每个数字与第二个数字的倒数第二个数字相乘,依此类推:

               1234
               x 56
         ------------
               7404
             +6170-   // - is denoting the left shift    
         ------------
              69104  

实际发生了什么:

  
      
  1. num1 = 1234,num2 = 56,left_shift = 0;
  2.   
  3. char_array [] = num1
  4. 中的所有数字   
  5. result_array []
  6.   
  7. 而(NUM2)      
        
    • n = num2%10
    •   
    • num2 / = 10
    •   
    • carry = 0,i = left_shift,j = 0
    •   
    • 而(CHAR_ARRAY [J])
           一世。 partial_result = char_array [j] * n +携带
          II。 partial_result + = result_array [i]
         III。 result_array [i ++] = partial_result%10
          IV。 carry = partial_result / 10
    •   
    • left_shift ++
    •   
  8.   
  9. 以相反的顺序打印result_array
  10.   

您应该注意,如果num1num2未超出其数据类型的范围,则上述算法有效。如果您想要更通用的程序,那么您必须读取char数组中的两个数字。逻辑将是相同的。将num1num2声明为char数组。请参阅实施:

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

int main(void)
{
    char num1[200], num2[200];
    char result_arr[400] = {'\0'};
    int left_shift = 0;

    fgets(num1, 200, stdin);
    fgets(num2, 200, stdin);

    size_t n1 = strlen(num1);
    size_t n2 = strlen(num2);   

    for(size_t i = n2-2; i >= 0; i--)
    {
        int carry = 0, k = left_shift;
        for(size_t j = n1-2; j >= 0; j--)
        {
            int partial_result = (num1[j] - '0')*(num2[i] - '0') + carry;
            if(result_arr[k])
                partial_result += result_arr[k] - '0';
            result_arr[k++] = partial_result%10 + '0';
            carry = partial_result/10;  
        }
        if(carry > 0)
            result_arr[k] = carry +'0'; 
        left_shift++;
    }
    //printf("%s\n", result_arr);

    size_t len = strlen(result_arr);
    for(size_t i = len-1; i >= 0; i-- )
        printf("%c", result_arr[i]);
    printf("\n");   
}

这不是标准算法,但我希望这会有所帮助。

答案 1 :(得分:0)

您可以按照以下方式重复使用字符串添加代码(使用user300234&#39; 384 x 56的示例):

Set result="0" /* using your character-string representation */
repeat:
    Set N = ones_digit_of_multiplier /* 6 in this case */
    for (i = 0; i < N; ++i)
      result += multiplicand  /* using your addition algorithm */
    Append "0" to multiplicand /* multiply it by 10 --> 3840 */
    Chop off the bottom digit of multiplier /* divide it by 10 --> 5 */
    Repeat if multiplier != 0.

答案 2 :(得分:0)

Bignum算术难以有效实施。这些算法很难理解(有效的算法比你想要实现的算法更好),你可以找到几本书。

我建议使用像GMPLib这样的现有Bignum库,或者使用一些本地提供bignums的语言(例如Common Lisp with SBCL