代码之家  ›  专栏  ›  技术社区  ›  mmr

如何使用库调用计算C中的阶乘?

  •  6
  • mmr  · 技术社区  · 15 年前

    我需要计算100左右的阶乘!为了确定一系列硬币翻转样式数据是否是随机的,根据 this Wikipedia entry on Bayesian probability. 如您所见,必要的公式涉及3个阶乘计算(有趣的是,其中两个阶乘计算是沿着第三个阶乘计算的)。

    我看到了 this question here 但我认为整数会很快被炸飞。我也可以做一个对阶乘计算更智能的函数(如果我有11个!(7)3!),根据wiki示例,我可以转到(11*10*9*8)/3!)但这对我来说有点过早的优化,从某种意义上说,我希望它能工作,但我不在乎速度(还没有)。

    那么,我可以调用什么好的C库来计算阶乘以得到这个概率呢?我对所有可以进入阶乘计算的奇异性不感兴趣,我只是希望结果能够被我操纵。在数学名称空间中似乎没有阶乘函数,因此出现了问题。

    6 回复  |  直到 5 年前
        1
  •  7
  •   TrueWill    15 年前

    你可以试试 Math.NET -我没有使用过这个库,但是它们列出了阶乘和对数阶乘。

        2
  •  4
  •   Community Neeleshkumar S    7 年前

    有一个 previous question 关于一个类似的话题。有人链接了 Fast Factorial Functions 网站,其中包括一些有效算法的解释,甚至C源代码。

        3
  •  3
  •   Kirk Broadhurst    15 年前

    你想计算阶乘还是二项式系数?

    听起来你想计算二项式系数,特别是当你提到11时!(7)3!).

    可能有一个库可以为您做到这一点,但是作为一个(大概)访问堆栈溢出的程序员,没有理由不自己写一个。这并不太复杂。

    为了避免内存溢出,在移除所有常见因素之前不要评估结果。

    这个算法还需要改进 但是你有一个好算法的基础。分母值需要分解成它们的主要因素才能获得最佳结果。就目前而言,这将很快运行到n=50。

    float CalculateBinomial(int n, int k)
    {
        var numerator = new List<int>();
        var denominator = new List<int>();
        var denominatorOld = new List<int>();
    
        // again ignore the k! common terms
        for (int i = k + 1; i <= n; i++)
            numerator.Add(i);
    
        for (int i = 1; i <= (n - k); i++)
        {
            denominator.AddRange(SplitIntoPrimeFactors(i));
        }
    
        // remove all common factors
        int remainder;                
        for (int i = 0; i < numerator.Count(); i++)
        {
            for (int j = 0; j < denominator.Count() 
                && numerator[i] >= denominator[j]; j++)
            {
                if (denominator[j] > 1)
                {
                    int result = Math.DivRem(numerator[i], denominator[j], out remainder);
                    if (remainder == 0)
                    {
                        numerator[i] = result;
                        denominator[j] = 1;
                    }
                }
            }
        }
    
        float denominatorResult = 1;
        float numeratorResult = 1;
    
        denominator.RemoveAll(x => x == 1);
        numerator.RemoveAll(x => x == 1);
    
        denominator.ForEach(d => denominatorResult = denominatorResult * d);
        numerator.ForEach(num => numeratorResult = numeratorResult * num);
    
        return numeratorResult / denominatorResult;
    }
    
    static List<int> Primes = new List<int>() { 2, 3, 5, 7, 11, 13, 17, 19, 
        23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 };
    
    List<int> SplitIntoPrimeFactors(int x)
    {
        var results = new List<int>();
        int remainder = 0;
    
        int i = 0;
        while (!Primes.Contains(x) && x != 1)
        {
            int result = Math.DivRem(x, Primes[i], out remainder);
            if (remainder == 0)
            {
                results.Add(Primes[i]);
                x = result;
                i = 0;
            }
            else
            {
                i++;
            }
        }
        results.Add(x);
        return results;
    }
    

    我可以估计n=110,k=50(返回6x10^31),但不能运行n=120,k=50。

        4
  •  1
  •   mmr    13 年前
    using System;
    //calculating factorial with recursion
    namespace ConsoleApplication2
    {
        class Program
        {
            long fun(long a)
            {
                if (a <= 1)
                {
                    return 1;}
                else
                {
                    long c = a * fun(a - 1);
                    return c;
                }}
    
            static void Main(string[] args)
            {
    
                Console.WriteLine("enter the number");
                long num = Convert.ToInt64(Console.ReadLine());
                Console.WriteLine(new Program().fun(num));
                Console.ReadLine();
            }
        }
    }
    
        5
  •  1
  •   psubsee2003 Miki Shah    12 年前

    下面可以在1秒内计算出5000的阶乘。

    public class Number
    {
        #region Fields
        private static long _valueDivision = 1000000000;
        private static int _valueDivisionDigitCount = 9;
        private static string _formatZeros = "000000000";
        List<long> _value;
        #endregion
    
        #region Properties
        public int ValueCount { get { return _value.Count; } }
        public long ValueAsLong
        {
            get
            {
                return long.Parse(ToString());
            }
            set { SetValue(value.ToString()); }
        }
        #endregion
    
        #region Constructors
        public Number()
        {
            _value = new List<long>();
        }
        public Number(long value)
            : this()
        {
            SetValue(value.ToString());
        }
        public Number(string value)
            : this()
        {
            SetValue(value);
        }
        private Number(List<long> list)
        {
            _value = list;
        }
        #endregion
    
        #region Public Methods
        public void SetValue(string value)
        {
            _value.Clear();
            bool finished = false;
            while (!finished)
            {
                if (value.Length > _valueDivisionDigitCount)
                {
                    _value.Add(long.Parse(value.Substring(value.Length - _valueDivisionDigitCount)));
                    value = value.Remove(value.Length - _valueDivisionDigitCount, _valueDivisionDigitCount);
                }
                else
                {
                    _value.Add(long.Parse(value));
                    finished = true;
                }
            }
        }
        #endregion
    
        #region Static Methods
        public static Number operator +(Number c1, Number c2)
        {
            return Add(c1, c2);
        }
        public static Number operator *(Number c1, Number c2)
        {
            return Mul(c1, c2);
        }
        private static Number Add(Number value1, Number value2)
        {
            Number result = new Number();
            int count = Math.Max(value1._value.Count, value2._value.Count);
            long reminder = 0;
            long firstValue, secondValue;
            for (int i = 0; i < count; i++)
            {
                firstValue = 0;
                secondValue = 0;
                if (value1._value.Count > i)
                {
                    firstValue = value1._value[i];
                }
                if (value2._value.Count > i)
                {
                    secondValue = value2._value[i];
                }
                reminder += firstValue + secondValue;
                result._value.Add(reminder % _valueDivision);
                reminder /= _valueDivision;
            }
            while (reminder > 0)
            {
                result._value.Add(reminder % _valueDivision);
                reminder /= _valueDivision;
            }
            return result;
        }
        private static Number Mul(Number value1, Number value2)
        {
            List<List<long>> values = new List<List<long>>();
            for (int i = 0; i < value2._value.Count; i++)
            {
                values.Add(new List<long>());
                long lastremain = 0;
                for (int j = 0; j < value1._value.Count; j++)
                {
                    values[i].Add(((value1._value[j] * value2._value[i] + lastremain) % _valueDivision));
                    lastremain = ((value1._value[j] * value2._value[i] + lastremain) / _valueDivision);
                    //result.Add(();
                }
                while (lastremain > 0)
                {
                    values[i].Add((lastremain % _valueDivision));
                    lastremain /= _valueDivision;
                }
            }
            List<long> result = new List<long>();
            for (int i = 0; i < values.Count; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    values[i].Insert(0, 0);
                }
            }
            int count = values.Select(list => list.Count).Max();
            int index = 0;
            long lastRemain = 0;
            while (count > 0)
            {
                for (int i = 0; i < values.Count; i++)
                {
                    if (values[i].Count > index)
                        lastRemain += values[i][index];
                }
                result.Add((lastRemain % _valueDivision));
                lastRemain /= _valueDivision;
                count -= 1;
                index += 1;
            }
            while (lastRemain > 0)
            {
                result.Add((lastRemain % _valueDivision));
                lastRemain /= _valueDivision;
            }
            return new Number(result);
        }
        #endregion
    
        #region Overriden Methods Of Object
        public override string ToString()
        {
            string result = string.Empty;
            for (int i = 0; i < _value.Count; i++)
            {
                result = _value[i].ToString(_formatZeros) + result;
            }
            return result.TrimStart('0');
        }
        #endregion
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Number number1 = new Number(5000);
            DateTime dateTime = DateTime.Now;
            string s = Factorial(number1).ToString();
            TimeSpan timeSpan = DateTime.Now - dateTime;
            long sum = s.Select(c => (long) (c - '0')).Sum();
        }
        static Number Factorial(Number value)
        {
            if( value.ValueCount==1 && value.ValueAsLong==2)
            {
                return value;
            }
            return Factorial(new Number(value.ValueAsLong - 1)) * value;
        }
    }
    
        6
  •  -3
  •   mehvan    5 年前

    大家好,根据这个解,我有自己的解,在这里我计算数组1d元素的阶乘。代码是'int[]array=new int[5] { 4、3、4、3、8 };

            int fac = 1;
    
            int[] facs = new int[array.Length+1];
    
            for (int i = 0; i < array.Length; i++)
            {
                for (int j = array[i]; j > 0; j--)
                {
                    fac *= j;
                }
                facs[i] = fac;
                textBox1.Text += facs[i].ToString() + " ";
                fac = 1;
            }`
    

    复制并粘贴按钮中^以上的代码,它解决数组1d元素的阶乘问题。此致。