'Equivalent C# Function For Excels Norm.S.Inv Function
I plan on finding the benchmark Z's of some data in C#. For this I need the Norm.S.Inv function from Excel. I am not able to find any sort of implementation for this in C#. Can anyone point me out to a library or to some source code that can help me? Thank you
Solution 1:[1]
You can use Math.NET.
The method you are looking for is MathNet.Numerics.Distribution.Normal.InverseCumulativeDistribution
Solution 2:[2]
In Excel 2010 onwards the implementation of NORM.S.INV
looks to be taken from the paper:
Wichura, M.J. (1988). "Algorithm AS241: The Percentage Points of the Normal Distribution". Applied Statistics (Blackwell Publishing) 37 (3): 477–484. (Ref: http://blogs.office.com/b/microsoft-excel/archive/2009/10/08/going-back-to-the-topic-of-functions-for-a-moment.aspx attachment P34 Sections 2.3.32-33)
For precision brenchmarking, maybe try: http://www.alglib.net/specialfunctions/distributions/normal.php
Solution 3:[3]
Since none of the other answers have provided one directly, below is an implementation of Algorithm AS 241: The Percentage Points of the Normal Distribution.
AS241(mean: m, probability: p, standardDeviation: s)
is equivalent to NORM.INV.AS241(mean: 0, probability: p, standardDeviation: 1)
is equivalent to NORM.S.INV.
Code:
public static double As241_Unsafe(double probability) {
var q = (probability - 0.5d);
double v;
if (Math.Abs(value: q) <= 0.425d) {
var r = (0.180625d - (q * q));
var t0 = Math.FusedMultiplyAdd(x: 2.5090809287301226727e+03d, y: r, z: 3.3430575583588128105e+04d);
var t1 = Math.FusedMultiplyAdd(x: t0, y: r, z: 6.7265770927008700853e+04d);
var t2 = Math.FusedMultiplyAdd(x: t1, y: r, z: 4.5921953931549871457e+04d);
var t3 = Math.FusedMultiplyAdd(x: t2, y: r, z: 1.3731693765509461125e+04d);
var t4 = Math.FusedMultiplyAdd(x: t3, y: r, z: 1.9715909503065514427e+03d);
var t5 = Math.FusedMultiplyAdd(x: t4, y: r, z: 1.3314166789178437745e+02d);
var t6 = Math.FusedMultiplyAdd(x: t5, y: r, z: 3.3871328727963666080e+00d);
var u0 = Math.FusedMultiplyAdd(x: 5.2264952788528545610e+03d, y: r, z: 2.8729085735721942674e+04d);
var u1 = Math.FusedMultiplyAdd(x: u0, y: r, z: 3.9307895800092710610e+04d);
var u2 = Math.FusedMultiplyAdd(x: u1, y: r, z: 2.1213794301586595867e+04d);
var u3 = Math.FusedMultiplyAdd(x: u2, y: r, z: 5.3941960214247511077e+03d);
var u4 = Math.FusedMultiplyAdd(x: u3, y: r, z: 6.8718700749205790830e+02d);
var u5 = Math.FusedMultiplyAdd(x: u4, y: r, z: 4.2313330701600911252e+01d);
var u6 = Math.FusedMultiplyAdd(x: u5, y: r, z: 1.0d);
v = ((q * t6) / u6);
}
else {
var r = Math.Sqrt(d: -Math.Log(d: (q < 0.0d) ? probability : (1.0d - probability)));
if (r <= 5.0d) {
r -= 1.6d;
var t0 = Math.FusedMultiplyAdd(x: 7.74545014278341407640e-04d, y: r, z: 2.27238449892691845833e-02d);
var t1 = Math.FusedMultiplyAdd(x: t0, y: r, z: 2.41780725177450611770e-01d);
var t2 = Math.FusedMultiplyAdd(x: t1, y: r, z: 1.27045825245236838258e+00d);
var t3 = Math.FusedMultiplyAdd(x: t2, y: r, z: 3.64784832476320460504e+00d);
var t4 = Math.FusedMultiplyAdd(x: t3, y: r, z: 5.76949722146069140550e+00d);
var t5 = Math.FusedMultiplyAdd(x: t4, y: r, z: 4.63033784615654529590e+00d);
var t6 = Math.FusedMultiplyAdd(x: t5, y: r, z: 1.42343711074968357734e+00d);
var u0 = Math.FusedMultiplyAdd(x: 1.05075007164441684324e-09d, y: r, z: 5.47593808499534494600e-04d);
var u1 = Math.FusedMultiplyAdd(x: u0, y: r, z: 1.51986665636164571966e-02d);
var u2 = Math.FusedMultiplyAdd(x: u1, y: r, z: 1.48103976427480074590e-01d);
var u3 = Math.FusedMultiplyAdd(x: u2, y: r, z: 6.89767334985100004550e-01d);
var u4 = Math.FusedMultiplyAdd(x: u3, y: r, z: 1.67638483018380384940e+00d);
var u5 = Math.FusedMultiplyAdd(x: u4, y: r, z: 2.05319162663775882187e+00d);
var u6 = Math.FusedMultiplyAdd(x: u5, y: r, z: 1.0d);
v = (t6 / u6);
}
else {
r -= 5.0d;
var t0 = Math.FusedMultiplyAdd(x: 2.01033439929228813265e-07d, y: r, z: 2.71155556874348757815e-05d);
var t1 = Math.FusedMultiplyAdd(x: t0, y: r, z: 1.24266094738807843860e-03d);
var t2 = Math.FusedMultiplyAdd(x: t1, y: r, z: 2.65321895265761230930e-02d);
var t3 = Math.FusedMultiplyAdd(x: t2, y: r, z: 2.96560571828504891230e-01d);
var t4 = Math.FusedMultiplyAdd(x: t3, y: r, z: 1.78482653991729133580e+00d);
var t5 = Math.FusedMultiplyAdd(x: t4, y: r, z: 5.46378491116411436990e+00d);
var t6 = Math.FusedMultiplyAdd(x: t5, y: r, z: 6.65790464350110377720e+00d);
var u0 = Math.FusedMultiplyAdd(x: 2.04426310338993978564e-15d, y: r, z: 1.42151175831644588870e-07d);
var u1 = Math.FusedMultiplyAdd(x: u0, y: r, z: 1.84631831751005468180e-05d);
var u2 = Math.FusedMultiplyAdd(x: u1, y: r, z: 7.86869131145613259100e-04d);
var u3 = Math.FusedMultiplyAdd(x: u2, y: r, z: 1.48753612908506148525e-02d);
var u4 = Math.FusedMultiplyAdd(x: u3, y: r, z: 1.36929880922735805310e-01d);
var u5 = Math.FusedMultiplyAdd(x: u4, y: r, z: 5.99832206555887937690e-01d);
var u6 = Math.FusedMultiplyAdd(x: u5, y: r, z: 1.0d);
v = (t6 / u6);
}
if (q < 0.0d) {
v = -v;
}
}
return v;
}
public static double As241(double probability) {
if ((0.0d > probability) || (1.0d < probability)) {
throw new ArgumentOutOfRangeException(
message: "probability must be between the inclusive range [0, 1]",
paramName: nameof(probability)
);
}
if (0.0d == probability) {
return double.NegativeInfinity;
}
if (1.0d == probability) {
return double.PositiveInfinity;
}
return As241_Unsafe(probability: probability);
}
public static double As241(double mean, double probability, double standardDeviation) {
if (0.0d > standardDeviation) {
throw new ArgumentOutOfRangeException(
message: "standardDeviation must be greater than or equal to 0",
paramName: nameof(standardDeviation)
);
}
return (mean + (standardDeviation * As241(probability: probability)));
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Matthieu Durut |
Solution 2 | lori_m |
Solution 3 |