是否有执行Excel NORMINV功能的C#库?
我正在运行一些,并使用Office Interrop广泛使用Excel函数。此函数接受三个参数(概率、平均值、标准偏差),并返回累积分布的倒数是否有执行Excel NORMINV功能的C#库?,c#,excel,statistics,montecarlo,C#,Excel,Statistics,Montecarlo,我正在运行一些,并使用Office Interrop广泛使用Excel函数。此函数接受三个参数(概率、平均值、标准偏差),并返回累积分布的倒数 我想将代码移动到web应用程序中,但这需要在服务器上安装Excel有人知道有一个C#统计库具有与NORM.INV等效的函数吗?我不知道有哪个库,但找到了这个链接--描述一个算法。它有多种语言的实现,但没有C语言。你可以使用VB.NET版本,也可以自己移植。有一个非常整洁的库,可以处理统计数据(所以我假设CDF),我没有使用过它,所以我不能肯定它是你想要的
我想将代码移动到web应用程序中,但这需要在服务器上安装Excel有人知道有一个C#统计库具有与NORM.INV等效的函数吗?我不知道有哪个库,但找到了这个链接--描述一个算法。它有多种语言的实现,但没有C语言。你可以使用VB.NET版本,也可以自己移植。有一个非常整洁的库,可以处理统计数据(所以我假设CDF),我没有使用过它,所以我不能肯定它是你想要的,但它看起来应该是。也许你可以试试这个组件,,它有一个Excel兼容的运行时计算引擎,它不需要安装Excel。
我也需要一个C++实现,Nordimv,我发现的最接近的东西是C++实现,所以我对C语言做了一个快速而肮脏的翻译,这里详细介绍。我只做了一些基本的测试,所以如果你决定使用它,请小心,无论如何,希望它有帮助
描述了逆法线CDF,包括系数。相对误差的绝对值小于1.15×10−九,public static class NormalDistributionConfidenceCalculator
{
/// <summary>
///
/// </summary>
public static double InverseNormalDistribution(double probability, double min, double max)
{
double x = 0;
double a = 0;
double b = 1;
double precision = Math.Pow(10, -3);
while ((b - a) > precision)
{
x = (a + b) / 2;
if (NormInv(x) > probability)
{
b = x;
}
else
{
a = x;
}
}
if ((max > 0) && (min > 0))
{
x = x * (max - min) + min;
}
return x;
}
/// <summary>
/// Returns the cumulative density function evaluated at A given value.
/// </summary>
/// <param name="x">A position on the x-axis.</param>
/// <param name="mean"></param>
/// <param name="sigma"></param>
/// <returns>The cumulative density function evaluated at <C>x</C>.</returns>
/// <remarks>The value of the cumulative density function at A point <C>x</C> is
/// probability that the value of A random variable having this normal density is
/// less than or equal to <C>x</C>.
/// </remarks>
public static double NormalDistribution(double x, double mean, double sigma)
{
// This algorithm is ported from dcdflib:
// Cody, W.D. (1993). "ALGORITHM 715: SPECFUN - A Portabel FORTRAN
// Package of Special Function Routines and Test Drivers"
// acm Transactions on Mathematical Software. 19, 22-32.
int i;
double del, xden, xnum, xsq;
double result, ccum;
double arg = (x - mean) / sigma;
const double sixten = 1.60e0;
const double sqrpi = 3.9894228040143267794e-1;
const double thrsh = 0.66291e0;
const double root32 = 5.656854248e0;
const double zero = 0.0e0;
const double min = Double.Epsilon;
double z = arg;
double y = Math.Abs(z);
const double half = 0.5e0;
const double one = 1.0e0;
double[] a =
{
2.2352520354606839287e00, 1.6102823106855587881e02, 1.0676894854603709582e03,
1.8154981253343561249e04, 6.5682337918207449113e-2
};
double[] b =
{
4.7202581904688241870e01, 9.7609855173777669322e02, 1.0260932208618978205e04,
4.5507789335026729956e04
};
double[] c =
{
3.9894151208813466764e-1, 8.8831497943883759412e00, 9.3506656132177855979e01,
5.9727027639480026226e02, 2.4945375852903726711e03, 6.8481904505362823326e03,
1.1602651437647350124e04, 9.8427148383839780218e03, 1.0765576773720192317e-8
};
double[] d =
{
2.2266688044328115691e01, 2.3538790178262499861e02, 1.5193775994075548050e03,
6.4855582982667607550e03, 1.8615571640885098091e04, 3.4900952721145977266e04,
3.8912003286093271411e04, 1.9685429676859990727e04
};
double[] p =
{
2.1589853405795699e-1, 1.274011611602473639e-1, 2.2235277870649807e-2,
1.421619193227893466e-3, 2.9112874951168792e-5, 2.307344176494017303e-2
};
double[] q =
{
1.28426009614491121e00, 4.68238212480865118e-1, 6.59881378689285515e-2,
3.78239633202758244e-3, 7.29751555083966205e-5
};
if (y <= thrsh)
{
//
// Evaluate anorm for |X| <= 0.66291
//
xsq = zero;
if (y > double.Epsilon) xsq = z * z;
xnum = a[4] * xsq;
xden = xsq;
for (i = 0; i < 3; i++)
{
xnum = (xnum + a[i]) * xsq;
xden = (xden + b[i]) * xsq;
}
result = z * (xnum + a[3]) / (xden + b[3]);
double temp = result;
result = half + temp;
}
//
// Evaluate anorm for 0.66291 <= |X| <= sqrt(32)
//
else if (y <= root32)
{
xnum = c[8] * y;
xden = y;
for (i = 0; i < 7; i++)
{
xnum = (xnum + c[i]) * y;
xden = (xden + d[i]) * y;
}
result = (xnum + c[7]) / (xden + d[7]);
xsq = Math.Floor(y * sixten) / sixten;
del = (y - xsq) * (y + xsq);
result = Math.Exp(-(xsq * xsq * half)) * Math.Exp(-(del * half)) * result;
ccum = one - result;
if (z > zero)
{
result = ccum;
}
}
//
// Evaluate anorm for |X| > sqrt(32)
//
else
{
xsq = one / (z * z);
xnum = p[5] * xsq;
xden = xsq;
for (i = 0; i < 4; i++)
{
xnum = (xnum + p[i]) * xsq;
xden = (xden + q[i]) * xsq;
}
result = xsq * (xnum + p[4]) / (xden + q[4]);
result = (sqrpi - result) / y;
xsq = Math.Floor(z * sixten) / sixten;
del = (z - xsq) * (z + xsq);
result = Math.Exp(-(xsq * xsq * half)) * Math.Exp(-(del * half)) * result;
ccum = one - result;
if (z > zero)
{
result = ccum;
}
}
if (result < min)
result = 0.0e0;
return result;
}
/// <summary>
/// Given a probability, a mean, and a standard deviation, an x value can be calculated.
/// </summary>
/// <returns></returns>
public static double NormInv(double probability)
{
const double a1 = -39.6968302866538;
const double a2 = 220.946098424521;
const double a3 = -275.928510446969;
const double a4 = 138.357751867269;
const double a5 = -30.6647980661472;
const double a6 = 2.50662827745924;
const double b1 = -54.4760987982241;
const double b2 = 161.585836858041;
const double b3 = -155.698979859887;
const double b4 = 66.8013118877197;
const double b5 = -13.2806815528857;
const double c1 = -7.78489400243029E-03;
const double c2 = -0.322396458041136;
const double c3 = -2.40075827716184;
const double c4 = -2.54973253934373;
const double c5 = 4.37466414146497;
const double c6 = 2.93816398269878;
const double d1 = 7.78469570904146E-03;
const double d2 = 0.32246712907004;
const double d3 = 2.445134137143;
const double d4 = 3.75440866190742;
//Define break-points
// using Epsilon is wrong; see link above for reference to 0.02425 value
//const double pLow = double.Epsilon;
const double pLow = 0.02425;
const double pHigh = 1 - pLow;
//Define work variables
double q;
double result = 0;
// if argument out of bounds.
// set it to a value within desired precision.
if (probability <= 0)
probability = pLow;
if (probability >= 1)
probability = pHigh;
if (probability < pLow)
{
//Rational approximation for lower region
q = Math.Sqrt(-2 * Math.Log(probability));
result = (((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / ((((d1 * q + d2) * q + d3) * q + d4) * q + 1);
}
else if (probability <= pHigh)
{
//Rational approximation for lower region
q = probability - 0.5;
double r = q * q;
result = (((((a1 * r + a2) * r + a3) * r + a4) * r + a5) * r + a6) * q /
(((((b1 * r + b2) * r + b3) * r + b4) * r + b5) * r + 1);
}
else if (probability < 1)
{
//Rational approximation for upper region
q = Math.Sqrt(-2 * Math.Log(1 - probability));
result = -(((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / ((((d1 * q + d2) * q + d3) * q + d4) * q + 1);
}
return result;
}
/// <summary>
///
/// </summary>
/// <param name="probability"></param>
/// <param name="mean"></param>
/// <param name="sigma"></param>
/// <returns></returns>
public static double NormInv(double probability, double mean, double sigma)
{
double x = NormInv(probability);
return sigma * x + mean;
}
}
公共静态类NormalDistributionConfidenceCalculator
{
///
///
///
公共静态双反正态分布(双概率、双最小、双最大)
{
双x=0;
双a=0;
双b=1;
双精度=数学功率(10,-3);
而((b-a)>精度)
{
x=(a+b)/2;
if(NormInv(x)>概率)
{
b=x;
}
其他的
{
a=x;
}
}
如果((最大值>0)和&(最小值>0))
{
x=x*(最大-最小)+最小;
}
返回x;
}
///
///返回以给定值计算的累积密度函数。
///
///x轴上的位置。
///
///
///在x处计算的累积密度函数。
///点x处累积密度函数的值为
///具有此正态密度的随机变量值为
///小于或等于x。
///
公共静态双正态分布(双x、双均值、双西格玛)
{
//此算法从dcdflib移植:
//Cody,W.D.(1993),“算法715:SPECFUN-A Portabel FORTRAN
//特殊功能例程和测试驱动程序包”
//数学软件上的acm交易。19,22-32。
int i;
双del、xden、xnum、xsq;
双结果,ccum;
双参数=(x-平均值)/西格玛;
常数双六十=1.60e0;
常数双sqrpi=3.98942280401432677944E-1;
常数双thrsh=0.66291e0;
常数双根32=5.656854248e0;
常数双零=0.0e0;
常数double min=double.Epsilon;
双z=arg;
双y=数学绝对值(z);
常数双半=0.5e0;
常数双1=1.0e0;
双[]a=
{
2.2352520354606839287e00,1.6102823106855587881e02,1.0676894854603709582e03,
1.8154981253343561249e04,6.568233791820744911E-2
};
双[]b=
{
4.7202581904688241870e01、9.7609855173777669322e02、1.0260932208618978205e04、,
4.550778933502672956E04
};
双[]c=
{
3.9894151208813466764e-1、8.8831497943883759412e00、9.3506656132177855979e01、,
5.9727027639480026226e02、2.4945375852903726711e03、6.8481904505362823326e03、,
1.1602651437647350124e04、9.842714838397802183、1.0765576773720192317e-8
};
双[]d=
{
2.2266688044328115691e01、2.3538790178262499861e02、1.5193775994075548050e03、,
6.4855582982667607550e03、1.8615571640885098091e04、3.4900952721145977266e04、,
3.8912003286093271411e04,1.9685429676859990727e04
};
双[]p=
{
2.1589853405795699e-1、1.274011611602473639e-1、2.2235277870649807e-2、,
1.421619193227893466e-3、2.9112874951168792e-5、2.307344176494017303e-2
};
双[]q=
{
1.28426009614491121e00,4.68238212480865118e-1,6.59881378689285515e-2,
3.7823963202758244E-3,7.29751555083966205e-5
};
if(y完全符合您的要求。以下是使用该库执行此操作的代码:
Distribution n = new NormalDistribution(mean, standardDeviation);
double x = n.InverseLeftProbability(probability);
如果您这样做是为了生成正常偏差,则GetRandomValue函数会更快。添加图表控件
双结果=图表1.数据操纵器.统计.逆异常分布(概率)
概率例如:0.9,0.4无论你做什么,都不要在你的web服务器上安装Excel。如果必须的话,请为此编写你自己的函数。@MusiGenesis:为什么你对web服务器上的Excel如此反感?我同意这并不理想,但似乎比尝试编写自己的统计函数要好,对吗?我对web服务器上的Excel没有敌意-我是我很害怕。Office对象是巨大的东西,你不想让你的web应用程序因为像分发函数这样的小功能而实例化它们。你确实不想到处去重新发明轮子,但你也确实不想到处用榴弹炮杀老鼠。你肯定更好停止编写自己的函数。@MusiGenesis:恕我直言,我不同意。这是一个蒙特卡罗模拟,这个函数被调用25000次。