Unser Professor sagte, dass Sie ein b nicht berechnen können, wenn ein & lt; 0 mit pow()
, weil pow()
natürliche Logarithmen verwendet, um es zu berechnen (a b = e b ln a ) und da es für negative Zahlen nicht definiert ist, kann es nicht berechnet werden. Ich habe es versucht und es funktioniert, solange b eine ganze Zahl ist.
Ich habe math.h
und weitere Dateien durchsucht, konnte aber nicht herausfinden, wie die Funktion definiert ist und was sie zur Berechnung verwendet. Ich habe auch versucht, im Internet zu suchen, aber ohne Erfolg. Es gibt ähnliche Fragen zu Stack Overflow rechts hier und hier (für C # ). (Der letzte ist gut, aber ich konnte den Quellcode nicht finden.)
Die Frage ist also, wie wird pow()
tatsächlich in C berechnet? Und warum gibt es einen Domänenfehler zurück, wenn die Basis endlich und negativ ist und der Exponent endlich und nicht ganzzahlig ist?
Wenn Sie neugierig sind, wie die Funktion pow
in der Praxis implementiert wird, können Sie sich den Quellcode ansehen. Es gibt eine Art "Kniff", um unbekannte (und große) Codebasen zu durchsuchen, um den Abschnitt zu finden, nach dem Sie suchen, und es ist gut, etwas Übung zu bekommen.
Eine Implementierung der C-Bibliothek ist glibc, die Spiegel auf GitHub hat. Ich habe keinen offiziellen Spiegel gefunden, aber ein inoffizieller Spiegel ist Ссылка
Zuerst schauen wir uns die Datei math/w_pow.c
an, die einen vielversprechenden Namen hat. Es enthält eine Funktion __pow
, die __ieee754_pow
aufruft, die wir in sysdeps/ieee754/dbl-64/e_pow.c
(Denken Sie daran, dass nicht alle Systeme IEEE-754 sind, daher ist es sinnvoll, dass sich der IEEE-754-Code in einem eigenen Verzeichnis befindet).
Es beginnt mit einigen speziellen Fällen:
%Vor%Etwas weiter unten finden Sie einen Zweig mit einem Kommentar
%Vor%Was uns zu
führt %Vor% Sie können also sehen, dass für negative x
und integer y
die glibc-Version von pow
pow(-x,y)
berechnet und dann das Ergebnis negativ macht, wenn y
ungerade ist.
Dies ist nicht die einzige Möglichkeit, Dinge zu tun, aber ich vermute, dass dies vielen Implementierungen gemeinsam ist. Sie können sehen, dass pow
voller Sonderfälle ist. Dies ist in mathematischen Funktionen der Bibliothek üblich, die mit unfreundlichen Eingaben wie Denormalen und Unendlich korrekt funktionieren sollen.
Die pow
-Funktion ist besonders schwer zu lesen, da es sich um stark optimierten Code handelt, der Bit-Twiddling auf Fließkommazahlen durchführt.
Der C-Standard (n1548 §7.12.7.4) sagt Folgendes über pow
:
Ein Domänenfehler tritt auf, wenn x endlich und negativ ist und y endlich ist und kein ganzzahliger Wert.
Daher sollte nach dem C-Standard das negative x
funktionieren .
Es gibt auch die Frage von Anhang F, die viel engere Einschränkungen dafür gibt, wie pow
auf IEEE-754 / IEC-60559-Systemen funktioniert.
Die zweite Frage (warum gibt es einen Domänenfehler zurück) ist bereits in den Kommentaren behandelt, aber zur Vollständigkeit hinzugefügt: pow
nimmt zwei reelle Zahlen und gibt eine reelle Zahl zurück. Wenn Sie einen rationalen Exponenten auf eine negative Zahl anwenden, werden Sie aus der Domäne der reellen Zahlen in die Domäne der komplexen Zahlen übernommen, die das Ergebnis dieser Funktion (a double ) nicht darstellen kann.
Wenn Sie neugierig auf die tatsächliche Implementierung sind, dann gibt es viele, und es hängt von vielen Faktoren ab, wie Architektur und Grad der Optimierung. Es ist ziemlich schwierig, einen zu finden, der leicht lesbar ist, aber FDLIBM (frei verteilbare LIBM) hat einen, der zumindest eine gute Erklärung hat die Kommentare :
%Vor%Kurz gesagt, der Mechanismus ist so, wie Sie ihn beschrieben haben und beruht auf der Berechnung des Logarithmus zuerst, aber mit vielen speziellen Fällen, die berücksichtigt werden müssen.
Unter der Annahme eines Prozessors der x86-Serie entspricht pow
dem Wert von
Dabei sind exp2
und log2
CPU-Primitive für die Exponential- und Logarithmusoperationen in Basis 2.
Verschiedene CPUs haben von Natur aus unterschiedliche Implementierungen.
In der Theorie, wenn Sie pow
nicht hätten, könnten Sie schreiben:
aber dies verliert wegen der kumulativen Abrundung die Genauigkeit gegenüber der nativen Version.
Und Dietrich Epp hat ergeben, dass ich einige Sonderfälle verpasst habe. Nichtsdestotrotz habe ich etwas über Abrundung zu sagen, das sollte stehen bleiben.
pow
funktioniert für negative Zahlen. Es funktioniert einfach nicht, wenn die Basis negativ ist und der Exponent keine ganze Zahl ist.
Eine Zahl in der Form a x / y beinhaltet tatsächlich die y-te Wurzel von x. Zum Beispiel, wenn Sie versuchen, ein 1/2 zu berechnen, suchen Sie tatsächlich nach der Quadratwurzel von a.
Was passiert also, wenn Sie eine negative Basis und einen nicht ganzzahligen Exponenten haben? Sie erhalten eine y-te Wurzel einer negativen Zahl, die eine komplexe nicht-reelle Zahl ist. pow()
funktioniert nicht mit komplexen Zahlen, daher wird wahrscheinlich NaN zurückgegeben.