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

我需要计算高达100左右的数字因子! 为了确定一系列硬币翻转式数据是否是随机的,根据贝叶斯概率的维基百科条目。 正如你在那里看到的那样,必要的公式涉及3个因子计算(但是,有趣的是,这些因子计算中的两个是沿着第三个计算的方式计算的)。

我在这里看到了这个问题 ,但我认为整数很快就会被吹灭。 我还可以创建一个更有智能的因子计算function(即,如果我有11!/(7!3!),根据维基示例,我可以去(11 * 10 * 9 * 8)/ 3!),但这对我来说过早优化,在某种意义上我希望它能够工作,但我并不关心速度(还)。

那么,为了获得这个概率,我可以调用什么样的C#库来计算阶乘? 我对所有可以进入阶乘计算的可怕性感兴趣,我只想以一种我可以操纵它的方式得到结果。 在Math命名空间中似乎没有因子函数,因此问题。

您可以尝试Math.NET – 我没有使用过该库,但它们列出了Factorial和Logarithmic Factorial。

先前有一个关于类似主题的问题。 有人将Fast Factorial Functions网站链接起来,其中包括对高效算法甚至C#源代码的一些解释。

您想计算阶乘或二项式系数吗?

听起来你想要计算二项式系数 – 尤其是当你提到11!/(7!3!)时。

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

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

这个算法仍然需要改进 ,但是你有一个好算法的基础。 分母值需要分成其最佳结果的主要因素。 就目前而言,这将非常快地运行n = 50。

float CalculateBinomial(int n, int k) { var numerator = new List(); var denominator = new List(); var denominatorOld = new List(); // 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 Primes = new List() { 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 SplitIntoPrimeFactors(int x) { var results = new List(); 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(返回6×10 ^ 31)但不能运行n = 120,k = 50。

 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(); } } } 

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

 public class Number { #region Fields private static long _valueDivision = 1000000000; private static int _valueDivisionDigitCount = 9; private static string _formatZeros = "000000000"; List _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(); } public Number(long value) : this() { SetValue(value.ToString()); } public Number(string value) : this() { SetValue(value); } private Number(List 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> values = new List>(); for (int i = 0; i < value2._value.Count; i++) { values.Add(new List()); 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 result = new List(); 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; } }