• 计算任意数值的阶乘


    计算任意数值的阶乘

    作者:eaglet

         谈到计算阶乘,大家可能会觉得比较简单,不就是一个循环从1一直乘到n吗?是的,确实是这样,但由于计算机的计算精度问题,利用计算机提供的现成的整数类型,我们最多可以计算到22! = 17196083355034583040 再大了,64位整形就无法存储。那么如果我们想计算100! 怎么办呢?eaglet 以前在博问中回答过类似问题,今天有空把它整理出来,供大家参考。

         要实现任意数值的阶乘,最简单的办法就是自己实现一个整数类型,这个整数类型可以像int, long 这些类型一样实现加和乘的操作,但没有大小限制。下面就给出eaglet 做的十进制无符号整形类。这个类只实现了加法和乘法操作,没有实现减法和除法,但用作阶乘已经足够了,减法和除法大家有兴趣可以自己补充。

    加法是基础

    算法很简单,就是从个位开始按位相加,如果有进位,就进位。

    乘法的方法是将乘数从各位开始逐位和被乘数相乘,然后再将相乘后得到的数累加,这个方法和手工计算乘法的方法是一样的。

    个人感觉这两种方法的效率应该不是最高的,如果哪位TX有更高效的算法,也不妨一起讨论一下。

    下面给出代码

        /// <summary>
        /// 十机制无符号整数类
        /// </summary>
        public class DecimalNumber
        {
            List<byte> _Data;
     
            public List<byte> Data
            {
                get
                {
                    return _Data;
                }
            }
     
            public int Length
            {
                get
                {
                    return _Data.Count;
                }
            }
     
            public DecimalNumber()
            {
                _Data = new List<byte>();
            }
     
            public DecimalNumber(byte[] data)
            {
                foreach (byte b in data)
                {
                    System.Diagnostics.Debug.Assert(b >= 0 && b <= 9);
                }
     
                _Data = new List<byte>(data);
            }
     
            public DecimalNumber(List<byte> data)
            {
                foreach (byte b in data)
                {
                    System.Diagnostics.Debug.Assert(b >= 0 && b <= 9);
                }
     
                _Data = data;
            }
     
            /// <summary>
            /// 1位10机制数和10进制序列相乘
            ///
            /// </summary>
            /// <param name="s">10进制序列</param>
            /// <param name="d">1位10机制数</param>
            /// <param name="power">10的幂数</param>
            /// <returns></returns>
            private static List<byte> Multiply(List<byte> s, byte d, int power)
            {
                System.Diagnostics.Debug.Assert(power >= 0);
                System.Diagnostics.Debug.Assert(d >= 0 && d <= 9);
     
                List<byte> result = new List<byte>();
     
                for (int i = 0; i < power; i++)
                {
                    result.Add(0);
                }
     
                byte carry = 0; //进位
     
                foreach (byte si in s)
                {
                    System.Diagnostics.Debug.Assert(si >= 0 && si <= 9);
     
                    byte r = (byte)(si * d + carry);
                    byte m = (byte)(r % 10);
                    carry = (byte)(r / 10);
                    result.Add(m);
                }
     
                if (carry > 0)
                {
                    result.Add(carry);
                }
     
     
                return result;
            }
     
            /// <summary>
            /// 两个10进制序列相加
            /// </summary>
            /// <param name="s1">序列1</param>
            /// <param name="s2">序列2</param>
            /// <returns>相加后的序列</returns>
            private static List<byte> Plus(List<byte> s1, List<byte> s2)
            {
                List<byte> result = new List<byte>();
     
                int c1 = s1.Count;
                int c2 = s2.Count;
     
                if (c1 > c2)
                {
                    for (int i = 0; i < c1 - c2; i++)
                    {
                        s2.Add(0);
                    }
                }
                else if (c1 < c2)
                {
                    for (int i = 0; i < c2 - c1; i++)
                    {
                        s1.Add(0);
                    }
                }
     
                byte carry = 0; //进位
     
                for (int i = 0; i < s1.Count; i++)
                {
                    System.Diagnostics.Debug.Assert(s1[i] >= 0 && s1[i] <= 9);
                    System.Diagnostics.Debug.Assert(s2[i] >= 0 && s2[i] <= 9);
     
                    byte r = (byte)(s1[i] + s2[i] + carry);
                    byte m = (byte)(r % 10);
                    carry = (byte)(r / 10);
                    result.Add(m);
                }
     
                if (carry > 0)
                {
                    result.Add(carry);
                }
     
                return result;
            }
     
            public static implicit operator DecimalNumber(string value)
            {
                List<byte> data = new List<byte>();
     
                for (int i = value.Length - 1; i >= 0; i--)
                {
                    data.Add(byte.Parse(value[i].ToString()));
                }
     
                return new DecimalNumber(data);
            }
     
            public static implicit operator DecimalNumber(int value)
            {
                System.Diagnostics.Debug.Assert(value >= 0);
                return value.ToString();
            }
     
            public static DecimalNumber operator ++(DecimalNumber d)
            {
                return d + new DecimalNumber(new byte[] { 1 });
            }
     
            public static DecimalNumber operator +(DecimalNumber d1, int d2)
            {
                System.Diagnostics.Debug.Assert(d2 >= 0);
     
                return d1 + d2.ToString();
            }
     
            public static DecimalNumber operator +(DecimalNumber d1, DecimalNumber d2)
            {
                return new DecimalNumber(Plus(d1.Data, d2.Data));
            }
     
            public static DecimalNumber operator *(DecimalNumber d1, DecimalNumber d2)
            {
                List<List<byte>> multiplicationSerial = new List<List<byte>>();
     
                for (int i = 0; i < d1.Data.Count; i++)
                {
                    multiplicationSerial.Add(Multiply(d2.Data, d1.Data[i], i));
                }
     
                List<byte> result = new List<byte>();
     
                foreach (List<byte> s in multiplicationSerial)
                {
                    result = Plus(s, result);
                }
     
                return new DecimalNumber(result);
            }
     
            public override string ToString()
            {
                StringBuilder str = new StringBuilder();
     
                for (int i = _Data.Count - 1; i >= 0; i--)
                {
                    str.Append(_Data[i].ToString());
                }
     
                return str.ToString();
            }
         }

    有了这个类,我们计算阶乘就简单了

    下面是计算任意数阶乘的函数

            static public DecimalNumber Factorial(int n)
            {
                if (n < 0)
                {
                    throw new System.ArgumentException("n < 0!");
                }
     
                DecimalNumber result = 1;
     
                for (int i = 1; i <= n; i++)
                {
                    result *= i;
                }
     
                return result;
            }

    用这个函数,我们计算0 到 50 的阶乘

                for (int i = 0; i <= 50; i++)
                {
                    Console.WriteLine(string.Format("{0}! = {1}", i,  Factorial(i)));
                }

    看看结果:

    0! = 1
    1! = 1
    2! = 2
    3! = 6
    4! = 24
    5! = 120
    6! = 720
    7! = 5040
    8! = 40320
    9! = 362880
    10! = 3628800
    11! = 39916800
    12! = 479001600
    13! = 6227020800
    14! = 87178291200
    15! = 1307674368000
    16! = 20922789888000
    17! = 355687428096000
    18! = 6402373705728000
    19! = 121645100408832000
    20! = 2432902008176640000
    21! = 51090942171709440000
    22! = 1124000727777607680000
    23! = 25852016738884976640000
    24! = 620448401733239439360000
    25! = 15511210043330985984000000
    26! = 403291461126605635584000000
    27! = 10888869450418352160768000000
    28! = 304888344611713860501504000000
    29! = 8841761993739701954543616000000
    30! = 265252859812191058636308480000000
    31! = 8222838654177922817725562880000000
    32! = 263130836933693530167218012160000000
    33! = 8683317618811886495518194401280000000
    34! = 295232799039604140847618609643520000000
    35! = 10333147966386144929666651337523200000000
    36! = 371993326789901217467999448150835200000000
    37! = 13763753091226345046315979581580902400000000
    38! = 523022617466601111760007224100074291200000000
    39! = 20397882081197443358640281739902897356800000000
    40! = 815915283247897734345611269596115894272000000000
    41! = 33452526613163807108170062053440751665152000000000
    42! = 1405006117752879898543142606244511569936384000000000
    43! = 60415263063373835637355132068513997507264512000000000
    44! = 2658271574788448768043625811014615890319638528000000000
    45! = 119622220865480194561963161495657715064383733760000000000
    46! = 5502622159812088949850305428800254892961651752960000000000
    47! = 258623241511168180642964355153611979969197632389120000000000
    48! = 12413915592536072670862289047373375038521486354677760000000000
    49! = 608281864034267560872252163321295376887552831379210240000000000
    50! = 30414093201713378043612608166064768844377641568960512000000000000

  • 相关阅读:
    动态开点线段树
    Codeforces Round #524 (Div. 2) F. Katya and Segments Sets(主席树)
    Codeforces Round #524 (Div. 2) E. Sonya and Matrix Beauty(字符串哈希,马拉车)
    Codeforces Round #523 (Div. 2) E. Politics(最小费+思维建图)
    UVA12118 Inspector's Dilemma(欧拉路径)
    UVA
    UVA-127 "Accordian" Patience(模拟)
    UVA-1599 Ideal Path(双向BFS)
    UVA-1572 Self-Assembly(拓扑排序判断有向环)
    UVA-122 Trees on the level(树的遍历)
  • 原文地址:https://www.cnblogs.com/eaglet/p/1550311.html
Copyright © 2020-2023  润新知