Prettify math formula in code

Ich habe eine Funktion, um die normale Verteilung in Python zu berechnen:

def norm_cdf(z):
  """ Use the norm distribution functions as of Gale-Church (1993) srcfile. """
  # Equation 26.2.17 from Abramowitz and Stegun (1964:p.932)

  t = 1.0/(1+0.2316419*z) # t = 1/(1+pz) , p=0.2316419
  probdist = 1 - 0.3989423*math.exp(-z*z/2) * ((0.319381530 * t)+ \
                                         (-0.356563782* math.pow(t,2))+ \
                                         (1.781477937 * math.pow(t,3)) + \
                                         (-1.821255978* math.pow(t,4)) + \
                                         (1.330274429 * math.pow(t,5)))
  return probdist

Aber ich muss mich an PEP8 und 80 Char Rand halten, daher die hässlichen \ s. Wie sonst sollte ich meinen Code verschönern?

In mathematischer Form,

$$\begin{align*} \textrm{norm_cdf}(z) = 1 - 0.3989423 e^\frac{-z^2}{2} (&1.330274429 t^5 - 1.821255978 t^4 \\ &+ 1.781477937 t^3 - 0.356563782 t^2 + 0.319381530 t ) \end{align*}$$

woher

$$ t = \ frac {1} {1 + 0.2316419 z} $$

42
Die Kommentare von Jeez in Python sind hässlich ... Oder können Sie etwas wie einen C-Stil typedef für Ihre mathematischen Konstanten tun? Es würde den Code deutlich lesbarer machen, imo. Etwas wie typdef 0.319381530 NORMALITÄT . Aber weißt du, nimm bessere Namen und Sachen. Für Python könnten Sie einfach alle Ihre Konstanten oben an der Methode haben (für Lesbarkeit), etwas wie NORMALITY = 0.319381530 . Das ist meine bevorzugte Methode, um mathematische Funktionen zu organisieren.
hinzugefügt der Autor tai, Quelle
@Davidmh Ah, okay. Das war mein Missverständnis :)
hinzugefügt der Autor tai, Quelle
@Davidmh Ich weiß, dass es in Python keinen typedef gibt, weshalb ich vorgeschlagen habe, einfach eine "Konstante" wie NORMALITY = 0.319381530 zu definieren. Persönlich mag ich den Listenansatz nicht, wie in @ Davidmhs Antwort vorgeschlagen: coeff = [1 , 0.319381530, -0.356563782, 1.781477937, -1.821255978, 1.330274429] Wenn es eine Menge von Konstanten gibt, verwenden Sie coeff [0] , coeff [ 1] usw. beginnt in einer langen Funktion unlesbar zu werden, insbesondere bei Funktionen, die die Konstanten mehrfach verwenden. Wiederum nur meine Meinung.
hinzugefügt der Autor tai, Quelle
@ChrisCirefice Äh, so funktioniert typedef in C nicht.
hinzugefügt der Autor Nic Hartley, Quelle
@ 200_success mag das Formelbild !!
hinzugefügt der Autor hippytea, Quelle
@ChrisCirefice Eine Liste ist nützlich in einer Schleife, die Koeffizienten haben keine spezielle Bedeutung durch Themelves, und sie würden nur in Ausdrücken wiederverwendet werden, die vom Polynom abgeleitet sind (Ableitungen, Integrale, usw.).
hinzugefügt der Autor Davidmh, Quelle
@ChrisCirefice gibt es in Python keine TypeDefs. Das Speichern der Koeffizienten in einer Liste ist ein besser lesbarer Ansatz.
hinzugefügt der Autor Davidmh, Quelle

8 Antworten

Lassen Sie mich das wunderbare Buch Numerical Recipes in C ++ zitieren (aber auch anwendbar):

Wir nehmen an, dass Sie genug wissen, um ein Polynom niemals auf diese Weise zu bewerten:

p = c [0] + c [1] * x + c [2] * x * x + c [3] * x * x * x + c [4] * x * x * x * x;      

oder (noch schlimmer!),

p = c [0] + c [1] * x + c [2] * pow (x, 2.0) + c [3] * pow (x, 3.0) + c [4] * pow (x, 4,0);      

Kommen Sie zur (Computer-) Revolution, alle Personen, die eines solchen kriminellen Verhaltens schuldig sind, werden kurzerhand hingerichtet, und ihre Programme werden nicht ausgeführt!

(Sie finden die Seite in Ihrer Ausgabe im analytischen Index, unter dem Eintrag "Wortspiele, besonders schlecht" . Ich liebe dieses Buch.)

Es gibt zwei Gründe, dies nicht zu tun: Genauigkeit und Leistung. Der richtige Weg, das Polynom auszuwerten, ist wie folgt:

-t * (0.319381530  +  t * (-0.356563782 + t * (1.781477937 + t * (-1.821255978 + 1.330274429 * t))))

And you can, of course, split at your convenience, as the newlines inside parenthesis are ignored. Remember the PEP: " The preferred place to break around a binary operator is after the operator, not before it."

-t * (0.319381530  +  t * (-0.356563782 +
    t * (1.781477937 + t * (-1.821255978 + 1.330274429 * t))))

Eine weitere Alternative besteht darin, die Koeffizienten in einer Liste zu speichern:

coeff = [0, 0.319381530, -0.356563782, 1.781477937, -1.821255978, 1.330274429]
poly = coeff[-1]
for c in coeff[-2::-1]:
    poly *= x
    poly += c

Ich mache Operationen an Ort und Stelle, um die Zuweisung und Freigabe von Speicher zu vermeiden, aber dies ist nur relevant, wenn x ein NumPy-Array ist. Wenn Sie eine einzelne Zahl auswerten, können Sie stattdessen den schöneren Ausdruck verwenden:

poly = poly * x + coeff[i]

Aber ich würde bei der ersten bleiben, weil es allgemeiner ist.

Natürlich muss das Ergebnis mit dem Vorfaktor multipliziert werden:

return 1 - 0.3989423*math.exp(-z*z/2) * poly

Oder, wenn Sie es an Ort und Stelle tun wollen:

z2 = z * z # Be careful not to modify your input!
z2 *= 0.5  # Multiplication is faster than division.
np.exp(z2, out=z2)

probd = z2 * poly
probd *= -0.3989423
probd += 1
return probd

Bonusleiste:

Wenn Sie diese Funktion auf große Arrays (mehr als tausend Zahlen) anwenden, können Sie davon profitieren, die erste Technik in numexpr zu verwenden:

expr += '1 - 0.3989423* exp(-z * z/2) * '
expr += '(-t * (0.319381530  +  t * (-0.356563782 +  t * '
expr += '(1.781477937 + t * (-1.821255978 + 1.330274429 * t)))))'
ne.evaluate(expr)

Dies kompiliert den Ausdruck für Sie und verwendet transparent so viele Kerne wie Sie haben.

40
hinzugefügt
@EmilioMBumachar Hängt vom Polynom ab. Bei vielen Polynomen, die in der Praxis verwendet werden, führt der naive Ansatz jedoch dazu, dass große Werte ähnlicher Größe subtrahiert werden, was den absoluten Fehler erhöht, da größere Zahlen größere absolute Darstellungsfehler unter Verwendung von Gleitkommawerten aufweisen.
hinzugefügt der Autor Ben Crowell, Quelle
Ich kann die strenge Leistungseinbuße sehen, sie auf irgendeine der entmutigten Weisen zu implementieren, aber nicht die Genauigkeitsstrafe. Warum ist es schlecht für die Genauigkeit? Ich fragte es auf SO: stackoverflow.com/q/25203873/174365
hinzugefügt der Autor Czyrek, Quelle
Diese Methode zur Auswertung von Polynomen ist bekannt als "Horner-Schema" (oder Methode, die davon abhängt, wo Sie leben).
hinzugefügt der Autor mikeazo, Quelle
Vielleicht fehlt mir ein Zusammenhang, aber es sieht so aus, als würdest du aus Gründen der Geschwindigkeit einen längeren, hässlicheren Code machen, der dem OP überhaupt keine Sorgen bereitet.
hinzugefügt der Autor jas663, Quelle
Ich denke nicht, dass es sinnvoll ist, für diesen Ausdruck "so viele Kerne wie du" zu verwenden. Es ist zu trivial, um effizient parallelisiert zu werden.
hinzugefügt der Autor Yahya Uddin, Quelle
@ Ruslan "für große Arrays". Wenden Sie die gleiche Funktion auf 1e4 Zahlen an profitiert von der parallelen Ausführung.
hinzugefügt der Autor Davidmh, Quelle
@FranciscoCouzo das ist eine hervorragende Verbesserung! Ich habe es bearbeitet.
hinzugefügt der Autor Davidmh, Quelle
@ raptortech97 Ich gebe beide Optionen. Wie auch immer, der wichtige Teil ist, dass die Auswertung des Polynoms korrekt durchgeführt werden muss, um genau zu sein.
hinzugefügt der Autor Davidmh, Quelle
Anstatt xrange (len (coeff) - 2, -1, -1) zu verwenden und dann coeff von i zu indizieren, würde ich es tun durchlaufen Sie coeff [-2 :: - 1]
hinzugefügt der Autor Francisco Couzo, Quelle

As it turns out, a similar question was asked recently on Math.SE. Rather than , take advantage of built-in functionality in Python.

Ihr norm_cdf (z) ist nur eine numerische Näherung für

$$ P (z) = \ frac {1} {\ sqrt {2 \ pi}} \ int _ {- \ infty} ^ {z} e ^ {- t ^ 2/2} \ dt = \ int _ {- \ infty} ^ {z} Z (t) \ dt = \ frac {1} {2} \ links (1 + \ mathrm {erf} \ links (\ frac {z} {\ sqrt {2}} \ rechts) \ rechts) = \ frac {1} {2} \ mathrm {erfc} \ links (- \, \ frac {z} {\ sqrt {2}} \ right) $$

Daher können Sie einfach math.erfc() (verfügbar seit Python 2.7) und erhalten ein genaueres Ergebnis (besonders für sehr negative Werte von \ $ z \ $).

import math

def norm_cdf(z):
    return 0.5 * math.erfc(-x/math.sqrt(2))

Besser noch, verwenden Sie einfach scipy.stats.norm. cdf() !

22
hinzugefügt
@GraniteRobert Im Gegensatz dazu ist der norm_cdf (z) in der Frage die gröbere Annäherung. norm_cdf (0) ist 0.499999975962 statt 0.5. Jedes z ≤ -2.0 führt zu negativen Ergebnissen. 0.5 * math.erfc (-x/math.sqrt (2)) hat keines dieser Probleme.
hinzugefügt der Autor wjv, Quelle
Oder stehlen Sie einfach diese öffentliche Implementierung von erf() .
hinzugefügt der Autor wjv, Quelle
Warum wird SciPy nicht nur benötigt oder neu verteilt, wenn es auf Python ≤ 2.6 ausgeführt wird?
hinzugefügt der Autor wjv, Quelle
@alvas Alle deine Daten liegen über dem Mittelwert?
hinzugefügt der Autor wjv, Quelle
eigentlich sollte der norm_cdf() immer einen absoluten wert einer anderen kostenfunktion annehmen, also ist es okay.
hinzugefügt der Autor hippytea, Quelle
Das liegt daran, dass die Eingaben niemals negativ sein können, da die Untergrenze für eine beliebige Satzlänge 0 ist.
hinzugefügt der Autor hippytea, Quelle
Ich habe den ganzen Code mit einem Versuch - außer beim Importieren von scipy.stats.norm.cdf() , nur für den Fall, dass die Benutzer scipy nicht installiert haben, sondern die math.erfc wäre gut.
hinzugefügt der Autor hippytea, Quelle
aber ich denke, das wird die <= py 2.6 Benutzer ausmerzen ...
hinzugefügt der Autor hippytea, Quelle
Seien Sie vorsichtig, bevor Sie zu einem anderen Algorithmus wechseln, um die "gleiche" Berechnung durchzuführen. Von den etwa 8 verschiedenen Approximationen in Abramowitz und Stegun (A & S) für die Normalverteilungsfunktion wählte jemand diese spezielle Approximation. Es könnte einen sehr guten Grund für die Wahl gegeben haben. Gehen Sie nicht davon aus, dass eine serienmäßige Bibliotheksfunktion dem vorliegenden Problem eine angemessene Genauigkeit verleiht, es sei denn, Sie nehmen sich die Zeit, die hässlichen Details der Berechnung zu verstehen. Leute, die in A & S herumstöbern, neigen dazu, keine Gelegenheitsbenutzer zu sein; Genauigkeit und Fehlergrenzen können sehr wichtig sein.
hinzugefügt der Autor atos, Quelle
@ 200_success: A & S 26.2.17 sagt explizit, dass die gültigen Eingaben nicht negativ sind. Der Code sollte nicht mit negativen Werten aufgerufen werden, und in einer Umgebung, in der ungültige Aufrufe wahrscheinlich sind, sollte er eine Überprüfung enthalten. Die Fehlergrenze wird als 7.5 * 10 ** -8 aufgelistet. Ist die Genauigkeit für math.erfc irgendwie angegeben? Ich behaupte nicht, dass einer der beiden Algorithmen besser oder schlechter ist, ich möchte nur sagen, dass die Kompromisse im Kontext des zu lösenden Problems verstanden werden sollten.
hinzugefügt der Autor atos, Quelle

Ich werde nur die so genannten "magischen Zahlen" ansprechen, die von mehreren Rezensenten erwähnt wurden.

Manchmal, wenn man in reiner Mathematik arbeitet, ist das, was auf den ersten Blick als "magische Zahl" erscheint, wirklich nicht . Es kann sein, dass die Zahlen selbst nur ein Teil der Problembeschreibung sind. Ich denke, die Frage läuft darauf hinaus: Können Sie sich einen Namen ausdenken, der beschreibender ist als die Zahl? Wenn es einen guten Namen gibt, solltest du ihn wahrscheinlich verwenden.

Auf den ersten Blick dachte ich, dass Ihre Zahlen ein fester Bestandteil des Problems sind. Aber als ich Abramowitz und Stegun anschaute, sah ich, dass die referenzierte Formel Ihre hässlich aussehenden Konstanten bereits benannt hat. Die Namen sind p (die Sie in einem Kommentar erwähnt haben) und b1 bis b5 . Sie sollten diese Namen im Code verwenden, da sie eine sehr klare Verknüpfung zur ursprünglichen Formeldefinition erstellen.

Als Sie entschieden, dass es eine gute Idee war, den Kommentar p = 0.2316419 hinzuzufügen, war es sehr überzeugend, dass die Nummer benannt werden sollte. (Sobald der -Code p = 0.2316419 lautet, sollte der Kommentar entfernt werden.)

Übrigens war es sehr gut von Ihnen, die genaue Abramowitz- und Stegun-Referenz in den Kommentar aufzunehmen.

18
hinzugefügt

Verwenden Sie anstelle von math.pow den integrierten Operator ** . Sie benötigen die \ s nicht in EOL, da die Klammern, die den Ausdruck umgeben, es erlauben, sich implizit über mehrere Zeilen zu erstrecken. Nachdem ich diese beiden Änderungen vorgenommen habe, komme ich zu folgendem Ergebnis:

def norm_cdf(z):
    """ Use the norm distribution functions as of Gale-Church (1993) srcfile. """
    # Equation 26.2.17 from Abramowitz and Stegun (1964:p.932)

    t = 1.0/(1 + 0.2316419*z) # t = 1/(1+pz) , p=0.2316419
    probdist = 1.0 - (   (0.319381530  * t)
                       + (-0.356563782 * t**2)
                       + (1.781477937  * t**3)
                       + (-1.821255978 * t**4)
                       + (1.330274429  * t**5)) * 0.3989423*math.exp(-z*z/2)
    return probdist

Ich ordnete auch eine der Multiplikationen an, um den Vorrang ein wenig deutlicher und lesbarer zu machen.

Nach diesen Änderungen sehe ich nur noch die magischen Zahlen. Ich weiß nicht, wie diese Konstanten zustande kommen, aber es kann der Lesbarkeit helfen, wenn den Konstanten sinnvolle Namen gegeben werden könnten. Manchmal mit Formeln gibt es jedoch nicht wirklich einen nennenswerten Namen zu geben.

16
hinzugefügt

Nicht sicher, ob das hilft, aber Sie könnten leicht eine Funktion definieren, um den Wert eines Polynoms an einer gegebenen Position zu bewerten

def evaluate_polynom(pol, x):
    return sum(a * math.pow(x, i) for i, a in enumerate(pol))

Dann

(0.319381530 * t) + (-0.356563782* math.pow(t,2)) + (1.781477937 * math.pow(t,3)) + (-1.821255978* math.pow(t,4)) + (1.330274429 * math.pow(t,5))

wird :

evaluate_polynom([0, 0.319381530, -0.356563782, 1.781477937, -1.821255978, 1.330274429], t)
15
hinzugefügt
Ich habe offensichtlich nicht genug Wissen, um dies in eine Funktion mit einem aussagekräftigen Namen zu bringen, aber ich bin mir nicht einmal sicher, ob das erforderlich ist. Ich denke, es bringt das Abstraktionsniveau, das erforderlich ist, um es wie die beteiligten mathematischen Objekte aussehen zu lassen, und das Verschieben an einen anderen Ort könnte die mathematische Formel auseinanderbrechen lassen.
hinzugefügt der Autor Mike, Quelle
Der einzige Nitpick, den ich habe, ist vielleicht umbenennen pol zu coeff oder coefficients , um es klarer zu machen, oder möglicherweise die eingebauten wie unten beschrieben?
hinzugefügt der Autor jmagnusson, Quelle
Wenn dies zutrifft, können Sie eine andere Funktion definieren, die das beschriebene Code-Snippet als eine Art Hilfsmethode aufruft.
hinzugefügt der Autor Pimgd, Quelle

Auf die Gefahr hin, die Moderatoren (weiter) zu verärgern, rate ich davon ab, irgendwelchen Ratschlägen zu Numerik zu folgen, die aus einem der Numeric Recipes -Bücher 1 stammen.

Während Horners Methode in einigen Fällen helfen kann, ist es weit von einem Allheilmittel entfernt. Anstatt das Problem der Abrundung beim Summieren von Werten zu beheben, versucht es, dieses Problem zu vermeiden. Leider ist das nur teilweise erfolgreich. Für die meisten Polynome gibt es immer noch Eingänge, für die die Ergebnisse selbst im besten Fall relativ schlecht sind.

Wenn die Werte, die durch die Terme des Polynoms erzeugt werden, zu numerischer Instabilität beim Summieren führen, können Sie in Betracht ziehen, jede einzeln zu generieren, und dann etwas wie Kahan-Summe , um diese Begriffe zusammenzufassen. Wenn Sie möchten, kann dies auch eine Fehlerspanne zusammen mit der Summe selbst geben.

Wahrscheinlich ist es noch besser, die Langlois zu benutzen, ua kompensierte Horners Plan . Zumindest beim letzten Mal, als ich genau hinsah, schien dies der Stand der Technik bei der Auswertung von Polynomen zu sein. Es behält ungefähr die gleiche Genauigkeit des Ergebnisses bei, wie Sie es mit Horners Schema unter Verwendung von Gleitkommazahlen mit doppelter Genauigkeit erhalten würden (z. B. mit einem 64-Bit-Double, gibt es ungefähr die gleiche Genauigkeit wie Horners Schema mit 128-Bit-Quadro- Präzisions-Gleitpunkt, aber ohne fast die Geschwindigkeitsstrafe, die normalerweise tragen würde). Wie bei der Kahan-Summierung unterstützt dies die Berechnung eines an das Ergebnis gebundenen Fehlers.


1. Als Referenz siehe Kritiken wie:
http : //www.stat.uchicago.edu/~lekheng/courses/302/wnnr/nr.html
http://www.lysator.liu.se/c/ num-recipes-in-c.html
Ich denke, eine genauere Zusammenfassung als "wundervoll" ist: "Ich habe festgestellt, dass Numerische Rezepte gerade genug Informationen für eine Person liefern, um sich in Schwierigkeiten zu bringen, denn nach dem Lesen von NR denkt man, dass man versteht Was ist los."

6
hinzugefügt

wohingegen:

a*x**3 + b*x**2 + c*x = ((a*x + b)*x + c)*x

h/t @ Emily L. für "Horner" Referenz:

https://en.wikipedia.org/wiki/Horner%27s_method

und h/t @ Davidmh, um Verbesserungen der rechnerischen Geschwindigkeit/Genauigkeit dieser Methode festzustellen

gale-church zitierte es 1990 so:

import math

def pnorm(z):

    t = 1/(1 + 0.2316419 * z)
    pd = (1 - 0.3989423 *
      math.exp(-z * z/2) *
        ((((1.330274429 * t - 1.821255978) * t
           + 1.781477937) * t - 0.356563782) * t + 0.319381530) * t)

    return pd

Diese Methode vermeidet bequem das Problem.

Zitat:

enter image description here

enter image description here

Quelle:

http://www.aclweb.org/anthology/J93-1004

Seite 21 von 28 im PDF

Seite 95 der Zeitschrift Computerlinguistik Band 19, Nummer 1

Ich könnte "verschönern" zu:

def pnorm(z):

t = 1/(1 + 0.2316419 * z)
pd = (1 - 0.3989423 * math.exp(-z * z/2) *
      ((((1.330274429 * t - 
          1.821255978) * t + 
          1.781477937) * t - 
          0.356563782) * t + 
          0.319381530) * t )

return pd

wenn Sie das überprüfen

Abromowitz und Stegun, Handbuch der mathematischen Funktionen

Seite 932 Gleichung 26.2.17

Zitat:

http://people.math.sfu.ca/~cbm/aands/ page_932.htm

Du wirst folgendes finden:

enter image description here

aus dem wir eine Tabelle erstellen können, die uns folgendes gibt:

def pnorm(z):

    p  =  0.2316419
    b1 =  0.319381530
    b2 = -0.356563782
    b3 =  1.781477937
    b4 = -1.821255978
    b5 =  1.330274429
    t = 1/(1 + p * z)
    pd = (1 - 0.3989423 * math.exp(-z * z/2) *
          ((((b5 * t + b4) * t + b3) * t + b2) * t + b1) * t )

    return pd

Dann von der vorherigen Seite; 931 finden Sie:

enter image description here

Zx = (1/√(2* π))*e(-z*z/2)

in Python:

Zx = (1/math.sqrt(2* math.pi))*math.exp(-z*z/2)

und wir finden, dass (1/√ (2 * π)) = 0,3989423

Ich denke auch, dass ich das mag:

t * (b1 + t * (b2 + t * (b3 + t * (b4 + t * b5))))

besser als:

(((b5 * t + b4) * t + b3) * t + b2) * t + b1) * t 

also dann, endlich:

import math

def pnorm(z):

    p  =  0.2316419
    b1 =  0.319381530
    b2 = -0.356563782
    b3 =  1.781477937
    b4 = -1.821255978
    b5 =  1.330274429
    t  = 1/(1 + p * z)
    Zx = (1/math.sqrt(2 * math.pi)) * math.exp(-z * z/2)
    pd = Zx *  t * (b1 + t * (b2 - t * (b3 + t * (b4 - t * b5))))

    return (1 - pd) 

überprüfe meine Arbeit gegen die Op's

import matplotlib.pyplot as plt
import numpy as np
import math




def norm_cdf(z):
  """ Use the norm distribution functions as of Gale-Church (1993) srcfile. """
  # Equation 26.2.17 from Abramowitz and Stegun (1964:p.932)

  t = 1.0/(1+0.2316419*z) # t = 1/(1+pz) , p=0.2316419
  probdist = 1 - 0.3989423*math.exp(-z*z/2) * ((0.319381530 * t)+ \
                                         (-0.356563782* math.pow(t,2))+ \
                                         (1.781477937 * math.pow(t,3)) + \
                                         (-1.821255978* math.pow(t,4)) + \
                                         (1.330274429 * math.pow(t,5)))

  return probdist

for z in np.arange (-3,3,0.01):
    zf = pnorm(z)
    plt.plot(z,zf, c='red', marker = '.', ms=1)

for z in np.arange (-3,3,0.01):
    zf = norm_cdf(z)+0.1 #offset 0.1
    plt.plot(z,zf, c='blue', marker = '.', ms=1)

plt.show()
plt.pause(0.1)

enter image description here

Ich hatte erwartet, dass die Horner-Methode schneller sein würde, also führte ich einen Zeittest durch und ersetzte:

#Zx = (1.0/math.sqrt(2.0 * math.pi)) * math.exp(-z * z/2.0)
Zx = 0.3989423* math.exp(-z * z/2.0)

um es fair zu machen und die Auflösung von np.arrange auf 0,0001 zu erhöhen:

t0 = time.time()
for z in np.arange (-3,3,0.0001):
    zf = pnorm(z)
t1 = time.time()
for z in np.arange (-3,3,0.0001):
    zf = norm_cdf(z)
t2 = time.time()

print ('pnorm time    : %s' % (t1-t0))
print ('norm_cdf time : %s' % (t2-t1))

und die Ergebnisse, meinen Quad Core AMD 7950 FM2 + w/16G ram ziemlich hart zu drehen (obwohl mit mehreren anderen Anwendungen läuft) ... trotzte meinen Erwartungen:

>>>
pnorm time    : 81.4725670815
norm_cdf time : 80.7865998745

Die Horner Methode war nicht schneller

2
hinzugefügt
Ich würde auch empfehlen, die Formeln hier mit MathJax zu verbessern. Wenn Sie nicht wissen, wie das geht, kann ich später daran arbeiten.
hinzugefügt der Autor Jamal, Quelle
Willkommen bei StackExchange Code Review! Cooles Stück Geschichte, danke fürs Teilen.
hinzugefügt der Autor Stephen Rauch, Quelle
hmm Ich habe noch nie mit Mathjax gearbeitet, wäre gespannt auf das Ergebnis Jamal; Danke für die Begrüßung Stephen Rauch
hinzugefügt der Autor litepresence, Quelle

Ich werde hier ehrlich sein: Ich bin total verrückt nach Python.

Ist es möglich, einige dieser numerischen Literale als Konstanten zu deklarieren? Das würde Ihren Code aufräumen und den Code selbst noch ein wenig genauer erklären.

1
hinzugefügt