zoukankan      html  css  js  c++  java
  • 计算任意数值的阶乘

    计算任意数值的阶乘

    作者: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

  • 相关阅读:
    Shared Memory in Windows NT
    Layered Memory Management in Win32
    软件项目管理的75条建议
    Load pdbs when you need it
    Stray pointer 野指针
    About the Rebase and Bind operation in the production of software
    About "Serious Error: No RTTI Data"
    Realizing 4 GB of Address Space[MSDN]
    [bbk4397] 第1集 第一章 AMS介绍
    [bbk3204] 第67集 Chapter 17Monitoring and Detecting Lock Contention(00)
  • 原文地址:https://www.cnblogs.com/eaglet/p/1550311.html
Copyright © 2011-2022 走看看