【问题标题】:Multiplication of very long integers很长整数的乘法
【发布时间】:2010-09-16 15:25:38
【问题描述】:

有没有一种算法可以准确地将两个任意长的整数相乘?我正在使用的语言限制为 64 位无符号整数长度(最大整数大小为 18446744073709551615)。实际上,我希望能够通过分解每个数字来做到这一点,使用无符号 64 位整数以某种方式处理它们,然后能够将它们重新组合成一个字符串(这将解决相乘结果的问题存储)。

有什么想法吗?

【问题讨论】:

标签: algorithm math 64-bit


【解决方案1】:

    //Here is a JavaScript version of an Karatsuba Algorithm running with less time than the usual multiplication method
    
    function range(start, stop, step) {
        if (typeof stop == 'undefined') {
            // one param defined
            stop = start;
            start = 0;
        }
        if (typeof step == 'undefined') {
            step = 1;
        }
        if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
            return [];
        }
        var result = [];
        for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
            result.push(i);
        }
        return result;
    };
    function zeroPad(numberString, zeros, left = true) {
        //Return the string with zeros added to the left or right.
        for (var i in range(zeros)) {
            if (left)
                numberString = '0' + numberString
            else
                numberString = numberString + '0'
        }
    
        return numberString
    }
    function largeMultiplication(x, y) {
        x = x.toString();
        y = y.toString();
    
        if (x.length == 1 && y.length == 1)
            return parseInt(x) * parseInt(y)
    
        if (x.length < y.length)
            x = zeroPad(x, y.length - x.length);
    
        else
            y = zeroPad(y, x.length - y.length);
    
        n = x.length
        j = Math.floor(n/2);
    
        //for odd digit integers
        if ( n % 2 != 0)
            j += 1    
        var BZeroPadding = n - j
        var AZeroPadding = BZeroPadding * 2
    
        a = parseInt(x.substring(0,j));
        b = parseInt(x.substring(j));
        c = parseInt(y.substring(0,j));
        d = parseInt(y.substring(j));
    
        //recursively calculate
        ac = largeMultiplication(a, c)
        bd = largeMultiplication(b, d)
        k = largeMultiplication(a + b, c + d)
        A = parseInt(zeroPad(ac.toString(), AZeroPadding, false))
        B = parseInt(zeroPad((k - ac - bd).toString(), BZeroPadding, false))
        return A + B + bd
    }
    //testing the function here
    example = largeMultiplication(12, 34)
    console.log(example)

【讨论】:

  • 你的代码有很多语法错误导致编译失败。我已经修复了其中一些,但代码仍然不起作用
  • 你确定这行得通吗?为什么要去掉js标签让人验证?
  • 这不是故意的,我只是用工作代码重新替换了代码。您可以为此创建一个 plunkr 或 jsfiddle
【解决方案2】:

这是我在 C 中的代码片段。很好的旧乘法方法

char *multiply(char s1[], char s2[]) {
    int l1 = strlen(s1);
    int l2 = strlen(s2);
    int i, j, k = 0, c = 0;
    char *r = (char *) malloc (l1+l2+1); // add one byte for the zero terminating string
    int temp;

    strrev(s1);
    strrev(s2);
    for (i = 0;i <l1+l2; i++) {
        r[i] = 0 + '0';
    }

    for (i = 0; i <l1; i ++) {
        c = 0; k = i;
        for (j = 0; j < l2; j++) {
            temp = get_int(s1[i]) * get_int(s2[j]);
            temp = temp + c + get_int(r[k]);
            c = temp /10;
            r[k] = temp%10 + '0';

            k++;
        }
        if (c!=0) {
            r[k] = c + '0';
            k++;
        }
    }

    r[k] = '\0';
    strrev(r);
    return r;
}

【讨论】:

    【解决方案3】:

    如果您不能使用现有的 bignum 库(如 GMP),请查看 Wikipedia's article on binary multiplication with computers。有许多好的、有效的算法可以解决这个问题。

    【讨论】:

      【解决方案4】:

      最简单的方法是使用教科书机制,将任意大小的数字分成 32 位的块。

      给定 A B C D * E F G H(每个块 32 位,总共 128 位)
      您需要一个 9 个双字宽的输出数组。 设置 Out[0..8] 为 0

      您首先要执行以下操作:H * D + out[8] => 64 位结果。
      将低 32 位存入 out[8] 并将高 32 位作为进位
      下一个: (H * C) + out[7] + 进位
      同样,将低 32 位存储在 out[7] 中,使用高 32 位作为进位
      做完H*A + out[4] +进位后,需要继续循环直到没有进位。

      然后用 G、F、E 重复。
      对于 G,您将从 out[7] 而不是 out[8] 开始,依此类推。

      最后,遍历并将大整数转换为数字(这将需要“将大数除以单个单词”例程)

      【讨论】:

        【解决方案5】:

        大多数语言都有执行此操作的函数或库,通常称为 Bignum 库(GMP 是一个不错的库。)

        如果你想自己做,我会像人们在纸上做长乘法一样做。为此,您可以使用包含数字的字符串,也可以使用按位运算以二进制形式进行。

        例子:

          45
         x67
         ---
         315
        +270
        ----
         585
        

        或二进制:

           101
          x101
          ----
           101
          000
        +101
        ------
         11001
        

        编辑:在用二进制完成后,我意识到使用按位运算而不是包含以 10 为基数的字符串来编码会更简单(当然也更快)。我已经编辑了我的二进制乘法示例以显示一种模式:对于底部数字中的每个 1 位,将顶部数字添加到变量中,向左位移 1 位的位置次.最后,该变量将包含产品。

        要存储产品,您必须有两个 64 位数字,并想象其中一个是产品的前 64 位,另一个是产品的第二个 64 位。您必须编写代码,将第二个数字的第 63 位加到第一个数字的第 0 位。

        【讨论】:

        • 恭喜,您刚刚重新发明了“农民乘法”。 ;) en.wikipedia.org/wiki/…
        • 有比“农民乘法”更快的乘法算法
        【解决方案6】:

        这通常作为家庭作业给出。你在小学学到的算法会起作用。如果您需要将其用于实际应用程序,请使用库(其他帖子中提到了几个)。

        【讨论】:

          【解决方案7】:

          是的,您使用的数据类型实际上是一串数字(就像普通的“字符串”是一串字符一样)。你如何做到这一点高度依赖于语言。例如,Java 使用 BigDecimal。你用的是什么语言?

          【讨论】:

          • Freebasic,我认为它没有内置此功能。不过,如果我能了解所使用的算法,我愿意编写它。
          猜你喜欢
          • 1970-01-01
          • 2020-04-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-18
          • 1970-01-01
          • 1970-01-01
          • 2015-11-28
          相关资源
          最近更新 更多