Ich habe mich gefragt, ob Statistikfunktionen in Mathematikbibliotheken integriert sind, die Teil der Standard-C++-Bibliotheken wie cmath sind. Wenn nicht, können Sie eine gute Statistikbibliothek empfehlen, die eine kumulative Normalverteilungsfunktion hätte? Danke im Voraus.
Genauer gesagt möchte ich eine kumulative Verteilungsfunktion verwenden / erstellen.
Wenn die CDF der Normalverteilung alles ist, was Sie brauchen, warum implementieren Sie sie nicht einfach selbst? Es enthält keine Magie, daher ist die Implementierung unkompliziert.
– Hannes Ovrén
24. Februar 2010 um 21:56 Uhr
JFS
Es gibt keine direkte Funktion. Da aber die Gaußsche Fehlerfunktion und ihre Komplementärfunktion mit der kumulativen Normalverteilungsfunktion verwandt sind (vgl hieroder hier) können wir die implementierte c-Funktion verwenden erfc (komplementäre Fehlerfunktion):
#include <cmath>
double phi(double x)
{
// constants
double a1 = 0.254829592;
double a2 = -0.284496736;
double a3 = 1.421413741;
double a4 = -1.453152027;
double a5 = 1.061405429;
double p = 0.3275911;
// Save the sign of x
int sign = 1;
if (x < 0)
sign = -1;
x = fabs(x)/sqrt(2.0);
// A&S formula 7.1.26
double t = 1.0/(1.0 + p*x);
double y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x);
return 0.5*(1.0 + sign*y);
}
void testPhi()
{
// Select a few input values
double x[] =
{
-3,
-1,
0.0,
0.5,
2.1
};
// Output computed by Mathematica
// y = Phi[x]
double y[] =
{
0.00134989803163,
0.158655253931,
0.5,
0.691462461274,
0.982135579437
};
int numTests = sizeof(x)/sizeof(double);
double maxError = 0.0;
for (int i = 0; i < numTests; ++i)
{
double error = fabs(y[i] - phi(x[i]));
if (error > maxError)
maxError = error;
}
std::cout << "Maximum error: " << maxError << "\n";
}
Beachten Sie, dass dies eine Annäherung mit einfacher Genauigkeit ist, aber es gibt unten eine Implementierung mit doppelter Genauigkeit von also ak stackoverflow.com/a/23119456/190452
– David
4. März 2019 um 15:57 Uhr
Die Funktion berechnet die [pnorm]( cosmosweb.champlain.edu/people/stevens/webtech/R/…) mit Mittelwert=0 und SD=1. Gibt es eine Möglichkeit, benutzerdefinierte Mittelwerte und Standardabweichungen anzugeben? Wie kann man in diesem Fall die Funktion ändern?
– Suman Khanal
12. Oktober 2019 um 3:54 Uhr
@suman-khanal: Du brauchst eine Z-Transformation. Fügen Sie einfach die Parameter mean und sd zum Funktionskopf hinzu und x = (x – mean) / sd vor der Zeile int sign = 1.
– jwdietrich
27. Oktober 2020 um 17:04 Uhr
Auf Vorschlag der Leute, die vor mir geantwortet haben, habe ich herausgefunden, wie man es mit gsl macht, aber dann eine Lösung gefunden, die nicht aus der Bibliothek stammt (hoffentlich hilft das vielen Leuten da draußen, die danach suchen wie ich):
autsch … nicht verwenden pow, verwenden Sie die Horner-Regel. Ich stimme ab, bis dies korrigiert ist (bitte benachrichtigen Sie mich).
– Alexander C.
11. März 2011 um 10:31 Uhr
Dieser Code verliert an Genauigkeit. Horners Regel ist stabiler (und auch schneller).
– Alexander C.
27. Mai 2011 um 19:04 Uhr
warum nicht einfach verwenden double pK3 = K*K*K usw?
– Daniel Bonetti
18. Juni 2015 um 18:31 Uhr
(Soweit ich weiß) Aber pow wird als Makro definiert, denke ich, um gute Implementierungen zu ermöglichen, um gemeinsame Kräfte zu optimieren, wie z 2 und 3. Also nicht aufgeben pow zu früh!
– Aaron McDaid
4. Dezember 2015 um 9:09 Uhr
Danke für den Code! Ich nehme an, dies ist eine Taylor-Erweiterung der Normalverteilung und dann die Integration des erhaltenen Polynoms. Wie auch immer, ich habe den Code gegen Boost-Bibliotheken im z-Bereich von -3,8 bis +3,8 mit einem Inkrement von 0,01 getestet und die Summe der absoluten Unterschiede abs(boost-cnd_manul) liegt in der Größenordnung von 10^-6.
Die hier angegebenen Implementierungen des normalen CDF sind mit einfacher Genauigkeit Annäherungen, die gehabt haben float Ersetzt mit double und sind daher nur auf 7 oder 8 signifikante (Dezimal-) Stellen genau.
Für eine VB-Implementierung von Hart’s Doppelte Genauigkeit Annäherung, siehe Abbildung 2 von West Bessere Annäherungen an kumulative Normalfunktionen.
Bearbeiten: Meine Übersetzung von Wests Implementierung in C++:
Beachten Sie, dass ich Ausdrücke in die vertrauteren Formen für Annäherungen an Reihen und fortgesetzte Brüche umgeordnet habe. Die letzte magische Zahl in Wests Code ist die Quadratwurzel von 2π, die ich in der ersten Zeile an den Compiler weitergegeben habe, indem ich die Identität acos(0) = ½ π ausgenutzt habe.
Ich habe die magischen Zahlen dreimal überprüft, aber es besteht immer die Möglichkeit, dass ich mich vertippt habe. Wenn Sie einen Tippfehler entdecken, kommentieren Sie ihn bitte!
Die Ergebnisse für die Testdaten, die John Cook in seiner Antwort verwendet hat, sind
Ich schöpfe einen kleinen Trost aus der Tatsache, dass sie allen Ziffern zustimmen, die für die Mathematica-Ergebnisse angegeben wurden.
Wie ist das im Vergleich zu erfc ?
– Johan Lundberg
24. Mai 2016 um 19:58 Uhr
Das hängt von den Genauigkeitsgarantien von erfc ab. Es wird sicherlich eine leichte Rundung des Produkts des Arguments und der Quadratwurzel von einer Hälfte geben, die sich auf den endgültigen Wert ausbreiten kann. Harts Algorithmus soll mit doppelter Genauigkeit genau sein jeder Argument, obwohl ich das nicht unabhängig verifiziert habe. Auf jeden Fall wird beides viel sein, viel besser als Annäherungen mit einfacher Genauigkeit, bei denen Float durch Double ersetzt wird!
– also sprach ak
25. Mai 2016 um 20:59 Uhr
Gibt es eine einfache Möglichkeit, diesen Code zu ändern, um Freiheitsgrade zu berücksichtigen? Wie bei Scipy t-Test?
– tantrew
21. Mai 2017 um 4:37 Uhr
@tantrev Ich bezweifle sehr, dass es eine einfache Möglichkeit gibt, die Annäherungen der Reihen und fortgesetzten Brüche der normalen CDF in die der t-Verteilung umzuwandeln, fürchte ich.
– also sprach ak
27. Mai 2017 um 0:39 Uhr
@thusspakea.k. Vielen Dank! Ich nehme an, meine Hoffnung auf eine schnelle Annäherung an ~1E6 p-Werte mit der gleichen N-Größe war einfach töricht.
Das hängt von den Genauigkeitsgarantien von erfc ab. Es wird sicherlich eine leichte Rundung des Produkts des Arguments und der Quadratwurzel von einer Hälfte geben, die sich auf den endgültigen Wert ausbreiten kann. Harts Algorithmus soll mit doppelter Genauigkeit genau sein jeder Argument, obwohl ich das nicht unabhängig verifiziert habe. Auf jeden Fall wird beides viel sein, viel besser als Annäherungen mit einfacher Genauigkeit, bei denen Float durch Double ersetzt wird!
– also sprach ak
25. Mai 2016 um 20:59 Uhr
Gibt es eine einfache Möglichkeit, diesen Code zu ändern, um Freiheitsgrade zu berücksichtigen? Wie bei Scipy t-Test?
– tantrev
21. Mai 2017 um 4:37 Uhr
@tantrev Ich bezweifle sehr, dass es eine einfache Möglichkeit gibt, die Annäherungen der Reihen und fortgesetzten Brüche der normalen CDF in die der t-Verteilung umzuwandeln, fürchte ich.
– also sprach ak
27. Mai 2017 um 0:39 Uhr
@thusspakea.k. Vielen Dank! Ich nehme an, meine Hoffnung auf eine schnelle Annäherung an ~1E6 p-Werte mit der gleichen N-Größe war einfach töricht.
Wenn die CDF der Normalverteilung alles ist, was Sie brauchen, warum implementieren Sie sie nicht einfach selbst? Es enthält keine Magie, daher ist die Implementierung unkompliziert.
– Hannes Ovrén
24. Februar 2010 um 21:56 Uhr