Ich suchte nach einem effizienten Ansatz zur Berechnung von a b (say a = 2
and b = 50
). Um die Dinge anzufangen, habe ich mich entschlossen, einen Blick auf die Implementierung der Math.Pow()
Funktion zu werfen . In .NET Reflector fand ich jedoch nur Folgendes:
[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical]
public static extern double Pow(double x, double y);
Was sind einige der Ressourcen, in denen ich sehen kann, was im Inneren vor sich geht, wenn ich Math.Pow()
function aufrufe?
InternalCall
mit einemextern
Modifikator verwechselt sind (da diese widersprüchlich zu sein scheinen ), lesen Sie bitte die Frage (und die daraus resultierenden Antworten) , die ich zu genau dieser Sache gepostet habe.2^x
wenn der Betriebx
ist das Ergebnis eine ganze Zahl Schaltvorgang. Vielleicht könnten Sie das Ergebnis mit einer Mantisse von2
und einem Exponenten von konstruierenx
.Antworten:
Das bedeutet, dass die Methode tatsächlich in der in C ++ geschriebenen CLR implementiert ist. Der Just-in-Time-Compiler konsultiert eine Tabelle mit intern implementierten Methoden und kompiliert den Aufruf der C ++ - Funktion direkt.
Für einen Blick auf den Code ist der Quellcode für die CLR erforderlich. Sie können dies von der SSCLI20-Distribution erhalten . Es wurde um den .NET 2.0-Zeitrahmen herum geschrieben. Ich habe festgestellt, dass die Implementierungen auf niedriger Ebene
Math.Pow()
für spätere Versionen der CLR immer noch weitgehend genau sind.Die Nachschlagetabelle befindet sich in clr / src / vm / ecall.cpp. Der Abschnitt, der für relevant ist,
Math.Pow()
sieht folgendermaßen aus:Wenn Sie nach "COMDouble" suchen, gelangen Sie zu clr / src / classlibnative / float / comfloat.cpp. Ich werde Ihnen den Code ersparen, sehen Sie selbst. Grundsätzlich wird nach Eckfällen gesucht und dann die CRT-Version von aufgerufen
pow()
.Das einzige andere interessante Implementierungsdetail ist das FCIntrinsic-Makro in der Tabelle. Dies ist ein Hinweis darauf, dass der Jitter die Funktion möglicherweise als intrinsisch implementiert. Mit anderen Worten, ersetzen Sie den Funktionsaufruf durch eine Gleitkomma-Maschinencode-Anweisung. Was nicht der Fall ist
Pow()
, gibt es keine FPU-Anweisung dafür. Aber sicherlich für die anderen einfachen Operationen. Bemerkenswert ist, dass dies die Gleitkomma-Mathematik in C # wesentlich schneller machen kann als der gleiche Code in C ++. Überprüfen Sie diese Antwort auf den Grund dafür.Der Quellcode für die CRT ist übrigens auch verfügbar, wenn Sie über die Vollversion des Verzeichnisses Visual Studio vc / crt / src verfügen. Sie werden jedoch an die Wand gehen
pow()
, Microsoft hat diesen Code von Intel gekauft. Es ist unwahrscheinlich, einen besseren Job als die Intel-Ingenieure zu machen. Obwohl die Identität meines Highschool-Buches doppelt so schnell war, als ich es versuchte:Aber kein echter Ersatz, da es Fehler aus 3 Gleitkommaoperationen akkumuliert und sich nicht mit den verrückten Domänenproblemen befasst, die Pow () hat. Wie 0 ^ 0 und -Infinity, die zu einer beliebigen Potenz erhoben werden.
quelle
pow
ist bekanntermaßen schwer genau zu implementieren, da es sich um eine transzendentale Funktion handelt (siehe Dilemma des Tischmachers ). Mit einer integralen Kraft ist es viel einfacher.Die Antwort von Hans Passant ist großartig, aber ich möchte hinzufügen, dass wenn
b
es sich um eine Ganzzahl handelt,a^b
diese mit binärer Zerlegung sehr effizient berechnet werden kann. Hier ist eine modifizierte Version von Henry Warrens Hacker's Delight :Er stellt fest, dass diese Operation für alle b <15 optimal ist (die minimale Anzahl von arithmetischen oder logischen Operationen ausführt). Es ist auch keine Lösung für das allgemeine Problem bekannt, eine optimale Folge von Faktoren zu finden, die
a^b
für ein anderes b als ein umfangreiches berechnet werden können Suche. Es ist ein NP-hartes Problem. Das bedeutet also im Grunde, dass die binäre Zerlegung so gut ist, wie es nur geht.quelle
a
es sich um eine Gleitkommazahl handelt.a
dass es sich um eine Ganzzahl handelt, der Code jedoch. Infolgedessen wundere ich mich über die Genauigkeit des Ergebnisses der "sehr effizienten" Berechnung des Textes.Wenn die frei verfügbare C-Version von
pow
ein Hinweis ist, sieht sie nicht wie erwartet aus. Es wäre für Sie nicht sehr hilfreich, die .NET-Version zu finden, da das Problem, das Sie lösen (dh das mit ganzen Zahlen), um Größenordnungen einfacher ist und mit der Potenzierung in wenigen Zeilen C # -Code gelöst werden kann durch Quadrieren des Algorithmus .quelle