高效的乘法

时间:2014-11-07 23:47:43

标签: c# c++ algorithm math mathematical-optimization

我已经编写了一些代码来繁殖真正的长数字。想知道是否有更有效的方法来做到这一点?

这是我现在如何做到的。基本上实现了典型的长乘法'技术

    internal enum Digit
    {
        Zero = 0,
        One,
        Two,
        Three,
        Four,
        Five,
        Six,
        Seven,
        Eight,
        Nine
    }

    public class NumbersWhiz
    {
        public string Add(string Augend, string Addend)
        {
            string longerNum = (Augend.Length > Addend.Length == true) ? Augend : Addend;
            string shorterNum = (Addend.Length < Augend.Length == true) ? Addend : Augend;

            int longerLen = (Augend.Length > Addend.Length == true) ? Augend.Length : Addend.Length;
            int shorterLen = (Addend.Length < Augend.Length == true) ? Addend.Length : Augend.Length;

            //Pad the shorter number initially with zeros to match length of longer number
            int deltaLen = longerLen - shorterLen;
            string numTwoZeroed = new String('0', deltaLen);
            string numTwo = numTwoZeroed.Insert(deltaLen, shorterNum);
            string numOne = longerNum;

            string result = new String('0', longerLen);
            StringBuilder resultBuilder = new StringBuilder(result);

            bool carryForward = false;
            for (int index = longerLen; index > 0; index--)
            {
                int augend = Convert.ToInt32(numOne.Substring(index - 1, 1));
                int addend = Convert.ToInt32(numTwo.Substring(index - 1, 1));

                int sum = (carryForward == true) ? 1 : 0;
                sum = sum + augend + addend;
                carryForward = ((sum > 9) == true) ? true : false;
                int reminder = sum % 10;
                resultBuilder[index - 1] = Convert.ToChar(reminder.ToString());
            }

            if(carryForward)
                resultBuilder.Insert(0, '1');

            return resultBuilder.ToString();
        }

        public string Multiply(string Multiplicand, string Multiplier)
        {
            int resultLen = Multiplicand.Length + Multiplier.Length;
            string totalSum = new String('0', resultLen);
            for (int index = Multiplier.Length; index > 0; index--)
            {
                int multiplierDigit = Convert.ToInt32(Multiplier.Substring(index - 1, 1));

                string product = Multiply(Multiplicand, (Digit)multiplierDigit);
                product += new String('0', Multiplier.Length - index);
                totalSum = Add(totalSum, product);
            }
            return totalSum;
        }

        string Multiply(string Multiplicand, Digit MultiplierDigit)
        {
            int multiplier = (int)MultiplierDigit;
            if (multiplier == 0)
                return "0";

            int carry = 0;
            bool carryForward = false;
            int len = Multiplicand.Length;

            int productLen = len + 1;
            string result = new String('0', productLen);
            StringBuilder resultBuilder = new StringBuilder(result);

            for (int index = len; index > 0; index--)
            {
                int multiplicandDigit = Convert.ToInt32(Multiplicand.Substring(index - 1, 1));

                int product = (multiplicandDigit * multiplier) + carry;
                carryForward = ((product > 9) == true) ? true : false;
                int reminder = product % 10;
                carry = (product - reminder) / 10;
                resultBuilder[index] = Convert.ToChar(reminder.ToString());
            }

            if (carryForward)
                resultBuilder[0] = Convert.ToChar(carry.ToString());

            return resultBuilder.ToString();
        }
    }

2 个答案:

答案 0 :(得分:3)

嗯,是的。有更高级的乘法方法。

一种快速简便的加速算法的方法是从基数10(也就是小数位)移动到更适合计算机的数字系统。在base-2中使用32位或64位整数会快得多。你可以为每次计算做更多的工作,也可以去掉所有的模数计算。

除此之外,你可以用更好的东西取代(普通的)乘法算法。如果您的数字开始变得非常大,您可以通过迁移到不同的复杂区域来获得巨大的加速。您的算法具有复杂度O(n * m),其中n和m是两个因子的位数。

快速傅里叶变换可用于在O(n log n)中更快地进行大量乘法。值得一提的是Number Theoretic Transform,它更适合这项任务。

在大整数算术的主题中有很多东西需要学习和探索。如果你只是想增加数字并且不关心它是如何完成的,我建议只使用经过测试的快速bignum库。

答案 1 :(得分:2)

是的 - 这是一个逐位操作。

你有更明智的选择,可以更快地完成任务。一个是二元运算,你将其中一个数字视为两个幂的和,结果也是你得到的部分结果的总和乘以二的幂。

例如,让我们做17 x 11(我相信它应该给我181个。)

因此,让我们将17视为2的幂。它是2 0 + 2 4 (即1 + 16)。因此我们可以取11 * 1 + 11 * 16.我们可以用移位进行这些乘法中的每一个,所以它是11 <&lt; 0 + 11&lt;&lt; 4。

另一种看待事物的方式(导致一种不同的做事方式)对大数字很有用。为了论证,我们假设您只能进行4位操作。在这种情况下,您可以将4位数中的每个数字考虑在内,并使用乘法的分配属性来得到结果 - 也就是说,我们取每个大数,并将其分解为数字之和,每个数字都是表示构成整数的位的“切片”。例如,考虑像0x1234 * 0x4321这样的东西(为了简单起见),我们假设我们将它们与一个可以乘以两个8位操作数的CPU相乘以产生一个16位的结果。因此,我们将每个分解为8位切片:

(0x1200 + 0x34) * (0x4300 + 0x21)

然后我们可以使用分配属性:

0x1200 * 0x4300 + 0x1200 * 0x21 + 0x34 * 0x4300 + 0x34 * 0x21

每个(显然足够)只有8个有效位,因此我们可以在8位CPU上执行每个操作。那么你基本上只需要取4个中间结果并将它们全部加在一起。任何合理的CPU都有一个进位和一个可以用来处理这种多精度操作的加载进位指令。

虽然我在这里用8位操作显示它,但我认为这很明显如何扩展到(例如)32位或64位CPU上的256位操作数。