分治法的思路一般的算法教科书上都有,大数相乘也经常用来作为练习分治思想的很好的例子。

具体如下:

分治法实现大数相乘 C#实现_第1张图片

虽然上面的原理是对应2进制的,但是对于10进制也同样可行。

分治法实现大数相乘 C#实现_第2张图片

用C#实现,尽可能的利用C#的特性。本例中,只要拆分的数字小于9位数,就可以直接相乘计算,保证不会溢出。

在编程中,还需要用的加法和减法,也要通过字符串模拟实现。

最终的乘法运算,依赖递归思想得以实现。

本文的代码还有一些可以优化的地方,比如对于不使用字符串而是全部使用数组,可能会更快点。

代码如下:


namespace bigIntMultiply
{
    class Program
    {
        static void Main(string[] args)
        {
           string a = "99999999999999";
           string b = "123456789001234567890";
            Stopwatch sw = new Stopwatch();
            sw.Start();
            string s = Multiply(b, b);
            sw.Stop();
            Console.WriteLine(s);
            Console.WriteLine(sw.Elapsed);
        }
        //字符串模拟乘法操作
        static string Multiply(string x, string y)
        {
            //deep++;// Console.WriteLine("-" + deep + "-");
            string negative = "";
            if ((x.StartsWith("-") && y.StartsWith("-")) || (!x.StartsWith("-") && !y.StartsWith("-")))
            {
                x = x.TrimStart('-'); y = y.TrimStart('-');
                negative = "";
            }
            else if ((x.StartsWith("-") && !y.StartsWith("-")) || (!x.StartsWith("-") && y.StartsWith("-")))
            {
                x = x.TrimStart('-'); y = y.TrimStart('-');
                negative = "-";
            }
            //如果长度都小于9,直接相乘,返回就行了。
            if (x.Length <= 9 && y.Length <= 9)
            {
                long tmp = (long.Parse(x) * long.Parse(y));
                if (tmp == 0)
                    return tmp.ToString();
                return negative + (long.Parse(x) * long.Parse(y)).ToString();
            }
            //公式里的abcd
            string a, b, c, d;
            if (x.Length <= 9)
            {
                a = "0"; b = x;
            }
            else
            {
                if (x.Length % 2 != 0)
                    x = "0" + x;
                a = x.Substring(0, x.Length / 2);
                b = x.Substring(x.Length / 2);
            }
            if (y.Length <= 9)
            {
                c = "0";
                d = y;
            }
            else
            {
                if (y.Length % 2 != 0)
                    y = "0" + y;
                c = y.Substring(0, y.Length / 2);
                d = y.Substring(y.Length / 2);
            }
            int n = x.Length >= y.Length ? x.Length : y.Length;
            string t1, t2, t3;
            //递归调用,根据公式计算出值。
            string ac = Multiply(a, c);
            string bd = Multiply(b, d);
            t1 = Multiply(Subtract(a, b), Subtract(d, c));
            t2 = Add(Add(t1, ac), bd);
            t3 = Add(Add(Power10(ac, n), Power10(t2, n / 2)), bd).TrimStart('0');
            if (t3 == "") return "0";
            return negative + t3;
        }
        //字符串模拟加法操作
        static string Add(string x, string y)
        {
            if (x.StartsWith("-") && !y.StartsWith("-"))
            {
                return Subtract(y, x.TrimStart('-'));
            }
            else if (!x.StartsWith("-") && y.StartsWith("-"))
            {
                return Subtract(x, y.TrimStart('-'));
            }
            else if (x.StartsWith("-") && y.StartsWith("-"))
            {
                return "-" + Add(x.TrimStart('-'), y.TrimStart('-'));
            }
            if (x.Length > y.Length)
            {
                y = y.PadLeft(x.Length, '0');
            }
            else
            {
                x = x.PadLeft(y.Length, '0');
            }
            int[] sum = new int[x.Length + 1];
            for (int i = x.Length - 1; i >= 0; i--)
            {
                int tmpsum = int.Parse(x[i].ToString()) + int.Parse(y[i].ToString()) + sum[i + 1];
                if (tmpsum >= 10)
                {
                    sum[i + 1] = tmpsum - 10;
                    sum[i] = 1;//表示进位
                }
                else
                {
                    sum[i + 1] = tmpsum;
                }
            }
            string returnvalue = string.Concat(sum);
            if (sum[0] == 1)
            {
                return returnvalue;
            }
            else
            {
                return returnvalue.Remove(0, 1);
            }
        }
        //字符串模拟减法操作
        static string Subtract(string x, string y)
        {
            //if (x.StartsWith("-") && !y.StartsWith("-"))
            //{
            //    return "-" + Add(x.TrimStart('-'), y);
            //}
            //if (y.StartsWith("-"))
            //{
            //    return Add(x, y.TrimStart('-'));
            //}
            //x是正数,y也是正数
            int flag = checkBigger(x, y);
            if (flag == 0)
            {
                return "0";
            }
            else if (flag == -1)
            {
                string tmp = y;
                y = x;
                x = tmp;
            }
            //保证了x>=y
            y = y.PadLeft(x.Length, '0');//y补0与x对齐
            int[] difference = new int[x.Length];
            for (int i = x.Length - 1; i >= 0; i--)
            {
                int tmpdifference;
                tmpdifference = int.Parse(x[i].ToString()) - int.Parse(y[i].ToString()) + difference[i];
                if (tmpdifference < 0)
                {
                    tmpdifference += 10;
                    difference[i - 1] = -1;//表示借位
                }
                difference[i] = tmpdifference;
            }
            StringBuilder returnvalue = new StringBuilder(string.Concat(difference).TrimStart('0'));
            {
                if (returnvalue.ToString() == "")
                {
                    return "0";
                }
            }
            if (flag == -1)
            {
                returnvalue = returnvalue.Insert(0, "-");
            }
            return returnvalue.ToString();
        }
        //比较大小
        static int checkBigger(string x, string y)
        {
            if (x.Length > y.Length)
            {
                return 1;
            }
            else if (x.Length < y.Length)
            {
                return -1;
            }
            else
            {
                for (int i = 0; i < x.Length; i++)
                {
                    if (int.Parse(x[i].ToString()) > int.Parse(y[i].ToString()))
                    {
                        return 1;
                    }
                    else if (int.Parse(x[i].ToString()) < int.Parse(y[i].ToString()))
                    {
                        return -1;
                    }
                    continue;
                }
                return 0;
            }
        }
        //模拟移位
        static string Power10(string num, int n)
        {
            return num.PadRight(num.Length + n, '0');
        }
                                     
    }
}


测试了一下1234567890.........1234567890(260个1234567890,2600位)的平方,得出的结果如下:分治法实现大数相乘 C#实现_第3张图片


可以从https://defuse.ca/big-number-calculator.htm得到验证。