大型Lambda的C# 泊松累积分布

目录

介绍

背景

使用代码


介绍

Ramanujan的阶乘近似值计算C#中的泊松分布

背景

如果需要用于很大型Lambda的泊松累积分布函数,则可以使用此代码。

使用代码

泊松概率质量函数的公式为:

F(k,\lambda )=\sum_{i=0}^{k}\frac{e^{-\lambda} \lambda^i}{i!} 

C#中,可以将其计算为:

public double Cdf(long k)
{
    var e = Math.Pow(Math.E, -_lambda);
    long i = 0;
    var sum = 0.0;
    while (i <= k)
    {
        sum += e * Math.Pow(_lambda, i) / Factorial(i);
        i++;
    }
    return sum;
}

问题在于,随着k_lambda_lambda = λ增加,分母都变得非常大,并且程序崩溃。这可以通过使用对数来解决。为简单起见,自然对数是用于:\log_e=\ln。计算中使用以下规则:

  • \ln(x)=n => e^n =x
  • \ln(e^y) = y
  • e^{\ln(x)} = x => e^{\ln(x)} = y => x=y,forx >=0
  • \ln(x/y) = \ln(x) - \ln(y)
  • \ln(x*y) = \ln(x) + \ln(y)

计算使用对数和Ramanujan的阶乘近似表示:

\ln(n!) \approx n\ln(n)-n+\frac{\ln(n(1+4n(1+2n)))}{6} +\frac{\ln(\Pi )}{2} 

在此处详细了解。

设置Math.Pow(_lambda, i) / Factorial(i)= (A) = (\frac{\lambda ^{i}}{i!})给出了

 \ln(A) = \ln(\frac{\lambda^i}{i!}) =>\ln(A) =\ln(\lambda^i) -\ln(i!)

通过使用Ramanujan的阶乘近似,我们得到:

使用C#表示法并利用e^{\ln(x)} =x,我们得到:

A = Math.Pow(e, i*ln() -i*ln(i) + i - ln(i*(1 + 4*i*(1 + 2*i)))/6 - ln(π)/2))

可以在C#计算中使用此表达式,如以下代码所示:

var log6ThTail = Math.Log(i * (1 + 4 * i * (1 + 2 * i)))/6;
var lnN = i * Math.Log(_lambda) - (i * Math.Log(i) - i + log6ThTail + logPiDivTwo);
n = Math.Pow(Math.E, lnN - _lambda);

这是代码:

using System;

namespace PoissonEvaluator
{
	public class PoissonDistribution
	{
		private readonly double _lambda;

		public PoissonDistribution(double lambda = 1.0)
		{
			_lambda = lambda;
		}

		public double Pmf(long k)
		{
			if (k > 170 || double.IsInfinity(Math.Pow(_lambda, k)))
			{
				var logLambda = k * Math.Log(_lambda) - 
                                        _lambda - (k * Math.Log(k) - k +
					Math.Log(k * (1 + 4 * k * (1 + 2 * k))) / 6 + 
                                        Math.Log(Math.PI) / 2);
				return Math.Pow(Math.E, logLambda);
			}
			return Math.Pow(Math.E, -_lambda) * Math.Pow(_lambda, k) / Factorial(k);
		}

		public double Cdf(long k)
		{
			long i = 0;
			var sum = 0.0;
			var infinityIsFound = false;
			var eLambda = Math.Pow(Math.E, -_lambda);
			var logPiDivTwo = Math.Log(Math.PI) / 2;
			while (i <= k)
			{
				double n;
				if (infinityIsFound)
				{
					var log6ThTail = Math.Log(i * (1 + 4 * i * (1 + 2 * i))) / 6;
					var lnN = i * Math.Log(_lambda) - (i * Math.Log(i) - i +
						log6ThTail + logPiDivTwo);
					n = Math.Pow(Math.E, lnN - _lambda);
				}
				else
				{
					if (i > 170 || double.IsInfinity(Math.Pow(_lambda, i)))
					{
						infinityIsFound = true;
						var log6ThTail = Math.Log
                                                    (i * (1 + 4 * i * (1 + 2 * i))) / 6;
						var lnN = i * Math.Log(_lambda) - 
                                                            (i * Math.Log(i) - i +
							log6ThTail + logPiDivTwo);
						n = Math.Pow(Math.E, lnN - _lambda);
					}
					else
					{
						n = eLambda * Math.Pow(_lambda, i) / Factorial(i);
					}
				}

				sum += n;
				i++;
			}
			return (sum > 1) ? 1.0 : sum;
		}


		public double Factorial(long k)
		{
			long count = k;
			double factorial = 1;
			while (count >= 1)
			{
				factorial = factorial * count;
				count--;
			}

			return factorial;
		}
	}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值