Die Antwort von Dynamis lautet direkt auf den Punkt (und C #> 6.0):
public static double StdDev(this IEnumerable<double> values)
{
var count = values?.Count() ?? 0;
if (count <= 1) return 0;
var avg = values.Average();
var sum = values.Sum(d => Math.Pow(d - avg, 2));
return Math.Sqrt(sum / count);
}
Bearbeiten 2020-08-27:
Ich habe @ David Clarke Kommentare genommen, um einige Leistungstests durchzuführen, und dies sind die Ergebnisse:
public static (double stdDev, double avg) StdDevFast(this List<double> values)
{
var count = values?.Count ?? 0;
if (count <= 1) return (0, 0);
var avg = GetAverage(values);
var sum = GetSumOfSquareDiff(values, avg);
return (Math.Sqrt(sum / count), avg);
}
private static double GetAverage(List<double> values)
{
double sum = 0.0;
for (int i = 0; i < values.Count; i++)
sum += values[i];
return sum / values.Count;
}
private static double GetSumOfSquareDiff(List<double> values, double avg)
{
double sum = 0.0;
for (int i = 0; i < values.Count; i++)
{
var diff = values[i] - avg;
sum += diff * diff;
}
return sum;
}
Ich habe dies mit einer Liste von einer Million zufälligen Doppeln getestet.
Die ursprüngliche Implementierung hatte eine Laufzeit von ~ 48 ms.
Die leistungsoptimierte Implementierung hat 2-3 ms.
Dies ist also eine signifikante Verbesserung.
Einige interessante Details:
Math.Pow loszuwerden bringt einen Schub von 33ms!
Liste statt IEnumerable 6ms
manuell Durchschnittliche Berechnung 4ms
For-Schleifen anstelle von ForEach-Schleifen 2ms
Array statt Liste bringt nur eine Verbesserung von ~ 2%, also habe ich dies übersprungen,
indem ich einfach statt doppelt verwendet habe, bringt nichts
Eine weitere Senkung des Codes und die Verwendung von goto (ja, GOTO ... habe dies seit dem Assembler der 90er Jahre nicht mehr verwendet ...) anstelle von for-Schleifen zahlt sich nicht aus, Gott sei Dank!
Ich habe auch parallele Berechnungen getestet, dies ist bei Listen> 200.000 Elementen sinnvoll. Es scheint, dass Hardware und Software viel initialisiert werden müssen und dies ist für kleine Listen kontraproduktiv.
Alle Tests wurden zweimal hintereinander ausgeführt, um die Aufwärmzeit zu verringern.