Warum ist Math.pow (0, 0) === 1?

84

Wir alle wissen, dass 0 0 unbestimmt ist.

Aber , Javascript , sagt , dass:

Math.pow(0, 0) === 1 // true

und C ++ sagt dasselbe:

pow(0, 0) == 1 // true

WARUM?

Ich weiß das:

>Math.pow(0.001, 0.001)
0.9931160484209338

Aber warum Math.pow(0, 0)wirft man keine Fehler? Oder vielleicht NaNwäre ein besser als 1.

Ionică Bizău
quelle
3
@zzzzBov: Unter der Standarddefinition "a <sup> b </ sup> = exp (b ln (a))" ist es undefiniert. Der Versuch, es als "Grenze <sub> x-> 0 </ sub> f (x) <sup> g (x) </ sup>" zu definieren, wobei "f" und "g" beide Grenzen von Null haben, ergibt eine unbestimmte Wert, da es von Ihrer Wahl der Funktionen abhängt. (Entschuldigung für die verstümmelte Notation; ich kann nicht herausfinden, wie man hochgestellte Zeichen in Kommentaren erhält).
Mike Seymour
@MikeSeymour, ja, ich bin mir bewusst, dass 0⁰ (Unicode-Zeichen verwenden) angesichts dieser Definition undefiniert ist. Wenn Sie jedoch meinen Kommentar lesen, sollten Sie beachten, dass das Zitat eher auf die "Welt der Mathematik" als auf eine "Standarddefinition" verweist. Es ist dieser Unterschied, auf den ich mich ursprünglich bezog, und die Frage wurde aktualisiert, um diese Nuance zu korrigieren.
zzzzBov
2
@AJMansfield Um ... a ^ 0 = 1 für ungleich Null a.
Beska
Es ermöglicht Funktionen, die von Produkten mit Wahrscheinlichkeiten abhängen, sinnvolle Ergebnisse zu liefern. Es ist eine falsche Vorstellung, dass Computer symbolische Mathematikprozessoren sind. Die C-Sprache hat eine spezifische Implementierung in der realen Welt, während Ihre mathematische Welt möglicherweise zu ideal ist, um in Silizium implementiert zu werden.
IRTFM
26
Für die mathematische Version dieser Frage - "Warum definieren wir oft 0 ^ 0 = 1?" - math.stackexchange hat viele gute Antworten: math.stackexchange.com/questions/11150/…
PLL

Antworten:

78

In C ++ Das Ergebnis der pow (0, 0) ist das Ergebnis grundsätzlich Implementierung Verhalten definiert , da mathematisch haben wir eine widersprüchliche Situation , wo N^0immer sein soll , 1sondern 0^Nsollte immer sein , 0für N > 0, so dass Sie keine Erwartungen mathematisch als auf das Ergebnis dieser entweder haben sollten. Dieser Wolfram Alpha Forenbeiträge gehen auf etwas mehr Details ein.

Obwohl das pow(0,0)Ergebnis in 1für viele Anwendungen nützlich ist, wie in der Begründung für den internationalen Standard - Programmiersprachen - C im Abschnitt über die Gleitkomma-Arithmetikunterstützung nach IEC 60559 angegeben :

Im Allgemeinen meidet C99 ein NaN-Ergebnis, bei dem ein numerischer Wert nützlich ist. [...] Die Ergebnisse von pow (∞, 0) und pow (0,0) sind beide 1, da es Anwendungen gibt, die diese Definition ausnutzen können. Wenn beispielsweise x (p) und y (p) analytische Funktionen sind, die bei p = a Null werden, nähert sich pow (x, y), das exp (y * log (x)) entspricht, 1, wenn sich p nähert ein.

Aktualisieren Sie C ++

Wie Leemes richtig hervorhob, habe ich ursprünglich auf die Referenz für die komplexe Version von pow verwiesen, während die nicht komplexe Version behauptet, es handele sich um einen Domänenfehler. Der Entwurf des C ++ - Standards greift auf den Entwurf des C-Standards zurück und sowohl auf C99 als auch auf C11 im Abschnitt Absatz der 7.12.7.4 pow-Funktionen 2 sagt ( Hervorhebung von mir ):

[...] Ein Domänenfehler kann auftreten, wenn x Null und y Null ist. [...]

die, soweit ich das beurteilen kann mittels dieses Verhalten ist nicht spezifiziert Verhalten ein wenig Abschnitt Winding zurück 7.12.1 Behandlung von Fehlerzuständen , sagt:

[...] Ein Domänenfehler tritt auf, wenn sich ein Eingabeargument außerhalb der Domäne befindet, für die die mathematische Funktion definiert ist. [...] Bei einem Domänenfehler gibt die Funktion einen implementierungsdefinierten Wert zurück. Wenn der ganzzahlige Ausdruck math_errhandling & MATH_ERRNO ungleich Null ist, erhält der ganzzahlige Ausdruck errno den Wert EDOM. [...]

Wenn also ein Domänenfehler aufgetreten wäre, wäre dies ein implementierungsdefiniertes Verhalten, aber sowohl in den neuesten Versionen gccals auch clangim Wert von errnoist 0es kein Domänenfehler für diese Compiler.

Aktualisieren Sie Javascript

Für Javascript gibt die ECMAScript®-Sprachspezifikation im Abschnitt 15.8 Das mathematische Objekt unter 15.8.2.13 pow (x, y) unter anderem Folgendes an:

Wenn y +0 ist, ist das Ergebnis 1, auch wenn x NaN ist.

Shafik Yaghmour
quelle
1
@leemes Ich glaube, dass die Seite falsch ist, der Standard sagt nicht, dass NaN zurückgegeben werden sollte. Der Rückgabewert ist implementierungsdefiniert. cplusplus.com, von dem Sie behaupten, es sei keine zuverlässige Quelle, ist hier tatsächlich genauer.
Interjay
@interjay Ich denke du meinst die gelöschte Antwort; Ich zitierte nur über seine Unzuverlässigkeit, in der Hoffnung, dass es die Abwertung erklären könnte (die nicht von mir war). Nun, beide Seiten sind Wikis, daher hängt ihre Zuverlässigkeit von ihren menschlichen Editoren ab, die Fehler machen. ;)
Leemes
@leemes die C ++ Community auf SO hat definitiv eine starke Abneigung gegen cplusplus.com
Shafik Yaghmour
@ShafikYaghmour Ich habe die gleiche Frage verlinkt (in der gelöschten Antwort).
Leemes
1
@Alek Ich freue mich über das Feedback, ich versuche die Antworten zu schreiben, die ich von anderen lesen möchte. Es gelingt mir nicht immer, aber ich versuche es. Gute Fragen zu schreiben ist noch schwieriger, das habe ich nur einmal versucht und viel länger damit verbracht als mit meinen Antworten.
Shafik Yaghmour
35

In JavaScript Math.powist wie folgt definiert :

  • Wenn y NaN ist, ist das Ergebnis NaN.
  • Wenn y +0 ist, ist das Ergebnis 1, auch wenn x NaN ist.
  • Wenn y –0 ist, ist das Ergebnis 1, selbst wenn x NaN ist.
  • Wenn x NaN und y ungleich Null ist, ist das Ergebnis NaN.
  • Wenn abs (x)> 1 und y + ∞ ist, ist das Ergebnis + ∞.
  • Wenn abs (x)> 1 und y −∞ ist, ist das Ergebnis +0.
  • Wenn abs (x) == 1 und y + ∞ ist, ist das Ergebnis NaN.
  • Wenn abs (x) == 1 und y −∞ ist, ist das Ergebnis NaN.
  • Wenn abs (x) <1 und y + ∞ ist, ist das Ergebnis +0.
  • Wenn abs (x) <1 und y −∞ ist, ist das Ergebnis + ∞.
  • Wenn x + ∞ und y> 0 ist, ist das Ergebnis + ∞.
  • Wenn x + ∞ und y <0 ist, ist das Ergebnis +0.
  • Wenn x −∞ und y> 0 ist und y eine ungerade ganze Zahl ist, ist das Ergebnis −∞.
  • Wenn x −∞ und y> 0 ist und y keine ungerade ganze Zahl ist, ist das Ergebnis + ∞.
  • Wenn x −∞ und y <0 ist und y eine ungerade ganze Zahl ist, ist das Ergebnis −0.
  • Wenn x −∞ und y <0 ist und y keine ungerade ganze Zahl ist, ist das Ergebnis +0.
  • Wenn x +0 und y> 0 ist, ist das Ergebnis +0.
  • Wenn x +0 und y <0 ist, ist das Ergebnis + ∞.
  • Wenn x –0 und y> 0 ist und y eine ungerade ganze Zahl ist, ist das Ergebnis –0.
  • Wenn x −0 und y> 0 ist und y keine ungerade ganze Zahl ist, ist das Ergebnis +0.
  • Wenn x –0 und y <0 ist und y eine ungerade ganze Zahl ist, ist das Ergebnis –∞.
  • Wenn x −0 und y <0 ist und y keine ungerade ganze Zahl ist, ist das Ergebnis + ∞.
  • Wenn x <0 und x endlich und y endlich ist und y keine ganze Zahl ist, ist das Ergebnis NaN.

Betonung meiner

In der Regel sollten native Funktionen für jede Sprache wie in der Sprachspezifikation beschrieben funktionieren. Manchmal schließt dies explizit "undefiniertes Verhalten" ein, wobei es Sache des Implementierers ist, zu bestimmen, wie das Ergebnis aussehen soll. Dies ist jedoch kein Fall von undefiniertem Verhalten.

zzzzBov
quelle
Anhang F der Normen C99 und C11 enthält dieselbe Spezifikation. Eine Implementierung soll definieren __STDC_IEC_559__, dass sie dieser Spezifikation entspricht. Anhang F beschreibt die Gleitkomma-Arithmetik nach IEC 60559. Ich glaube, eine C-Spezifikation darf teilweise Anhang F entsprechen (z. B. pow (0, 0) == 1) und nicht definieren __STDC_IEC_559__.
Howard Hinnant
@HowardHinnant hmmm, es scheint, dass im Fall von gcc und clang diese Information möglicherweise nicht ganz hilfreich ist, was entmutigend ist.
Shafik Yaghmour
6
Ich weiß nicht, dass diese Antwort hilft. Natürlich sollte die Funktion so funktionieren, wie sie in der Spezifikation definiert ist. Aber dann wird die Frage einfach "Warum wurde es in der Spezifikation so definiert?"
Beska
Gut, dass dies (wahrscheinlich) in Hardware gemacht wird, sonst würde es die Leistung mit all diesen Sonderfällen beeinträchtigen :)
Thomas
16

Es ist nur Konvention zu definieren es als 1, 0oder es zu verlassen undefined. Die Definition pow (0,0)ist aufgrund der folgenden Definition weit verbreitet:

mathematische Potenzdefinition


In der ECMA-Script-Dokumentation wird Folgendes angegeben pow(x,y):

  • Wenn y +0 ist, ist das Ergebnis 1, auch wenn x NaN ist.
  • Wenn y –0 ist, ist das Ergebnis 1, selbst wenn x NaN ist.

[ http://www.ecma-international.org/ecma-262/5.1/#sec-15.8.2.13 ]

schmijos
quelle
3
math.stackexchange hat viele gute Diskussionen und Erklärungen für die Definition 0 ^ 0 = 1: math.stackexchange.com/questions/11150/…
PLL
14

Laut Wikipedia:

In den meisten Einstellungen ohne Kontinuität im Exponenten vereinfacht die Interpretation von 0 0 als 1 die Formeln und macht Sonderfälle in Theoremen überflüssig.

Es gibt verschiedene Möglichkeiten, 0**0mit Vor- und Nachteilen umzugehen (siehe Wikipedia für eine ausführliche Diskussion).

Der Gleitkomma-Standard IEEE 754-2008 empfiehlt drei verschiedene Funktionen:

  • powbehandelt 0**0als 1. Dies ist die älteste definierte Version. Wenn die Potenz eine exakte Ganzzahl ist, ist das Ergebnis das gleiche wie für pown, andernfalls ist das Ergebnis wie für powr(mit Ausnahme einiger Ausnahmefälle).
  • pownbehandelt 0 ** 0 als 1. Die Potenz muss eine exakte ganze Zahl sein. Der Wert ist für negative Basen definiert; zB pown(−3,5)ist −243.
  • powrbehandelt 0 ** 0 als NaN (Not-a-Number - undefined). Der Wert ist auch NaN für Fälle, in powr(−3,2)denen die Basis kleiner als Null ist. Der Wert wird durch exp (Leistung '× log (Basis)) definiert.
NPE
quelle
6

Donald Knuth

Diese Debatte wurde 1992 mit folgenden Mitteln beigelegt:

Geben Sie hier die Bildbeschreibung ein

Und ging in seiner Arbeit Two Notes on Notation noch näher auf Details ein .

Grundsätzlich haben wir zwar nicht 1 als Grenze f(x)/g(x)für alle, nicht alle Funktionen f(x)und g(x), aber es macht die Kombinatorik immer noch so viel einfacher zu definieren 0^0=1und dann nur Sonderfälle an den wenigen Stellen, an denen Sie Funktionen wie z. B. 0^xwelche berücksichtigen müssen sind sowieso komisch. Immerhin x^0kommt viel öfter auf.

Einige der besten Diskussionen, die ich zu diesem Thema kenne (außer dem Knuth-Papier), sind:

Thomas Ahle
quelle
Wenn Sie einige nicht gelesen haben, lesen Sie die Antworten in Null auf die Nullleistung ...? Was mit der Frage verknüpft war, sollten einige der Antworten auch diesen Ansatz abdecken.
Shafik Yaghmour
5

Wenn Sie wissen möchten , welchen Wert sollten Sie geben , f(a)wenn fnicht direkt berechenbar ist a, berechnen Sie die Grenze , fwenn xzustrebta .

Im Falle von x^ytendieren die üblichen Grenzen dazu, 1wann xund zu ytendieren 0, und x^xtendieren insbesondere dazu, 1wann xdazu tendiert 0.

Siehe http://www.math.hmc.edu/funfacts/ffiles/10005.3-5.shtml

Denys Séguret
quelle
5

Die C-Sprachdefinition lautet (7.12.7.4/2):

Ein Domänenfehler kann auftreten, wenn x Null und y Null ist.

Es heißt auch (7.12.1 / 2):

Bei einem Domänenfehler gibt die Funktion einen implementierungsdefinierten Wert zurück. Wenn der Ganzzahlausdruck math_errhandling & MATH_ERRNO ungleich Null ist, erhält der Ganzzahlausdruck errno den Wert EDOM. Wenn der ganzzahlige Ausdruck math_errhandling & MATH_ERREXCEPT ungleich Null ist, wird die Gleitkomma-Ausnahme '' ungültig '' ausgelöst.

Standardmäßig ist der Wert von math_errhandlingIS MATH_ERRNOzu überprüfen, also errnofür den Wert EDOM.

Pete Becker
quelle
1
Whoups! Das ist wirklich interessant! Ich habe meine CPP-Datei mitg++ (Ubuntu/Linaro 4.8.1-10ubuntu8) 4.8.
Ionică Bizău
0

Ich möchte mit der Behauptung einiger der vorherigen Antworten nicht einverstanden sein, dass es eine Frage der Konvention oder der Zweckmäßigkeit ist (einige Sonderfälle für verschiedene Theoreme usw.), dass 0 ^ 0 als 1 anstelle von 0 definiert wird.

Die Potenzierung passt nicht so gut zu unseren anderen mathematischen Notationen, daher lässt die Definition, die wir alle lernen, Raum für Verwirrung. Eine etwas andere Herangehensweise besteht darin, zu sagen, dass a ^ b (oder exp (a, b), wenn Sie möchten) den Wert zurückgibt multiplikativ äquivalent zum Multiplizieren einer anderen Sache mit a wiederholt b-mal .

Wenn wir 5 mit 4, 2 mal multiplizieren, erhalten wir 80. Wir haben 5 mit 16 multipliziert. Also 4 ^ 2 = 16.

Wenn Sie 14 mit 0, 0 mal multiplizieren, bleibt 14 übrig. Wir haben es mit 1 multipliziert. Daher ist 0 ^ 0 = 1.

Diese Denkweise könnte auch dazu beitragen, negative und gebrochene Exponenten zu klären. 4 ^ (- 2) ist ein 16., weil 'negative Multiplikation' Division ist - wir teilen zweimal durch vier.

a ^ (1/2) ist Wurzel (a), weil das Multiplizieren von etwas mit der Wurzel von a die Hälfte der multiplikativen Arbeit ist, als das Multiplizieren mit a selbst - Sie müssten es zweimal tun, um etwas mit 4 = 4 ^ 1 = zu multiplizieren (4 ^ (1/2)) ^ 2

NiloCK
quelle
0

Damit dies verstanden wird, müssen Sie den Kalkül lösen:

Geben Sie hier die Bildbeschreibung ein

Wenn x^xwir mit Taylor-Reihen um Null expandieren, erhalten wir:

Geben Sie hier die Bildbeschreibung ein

Um zu verstehen, was mit dem Limit los ist, wenn es xauf Null geht, müssen wir herausfinden, was mit dem zweiten Term los istx log(x) , da andere Terme proportional zu sindx log(x) einer gewissen Potenz sind.

Wir müssen Transformation verwenden:

Geben Sie hier die Bildbeschreibung ein

Nach dieser Transformation können wir nun die Regel von L'Hôpital verwenden , die besagt:

Geben Sie hier die Bildbeschreibung ein

So differenzieren wir diese Transformation, die wir bekommen:

Geben Sie hier die Bildbeschreibung ein

Also haben wir diesen Begriff berechnet log(x)*x 0 nähert, wenn sich x 0 nähert. Es ist leicht zu erkennen, dass andere aufeinanderfolgende Terme sich ebenfalls Null nähern und sogar schneller als der zweite Term sind.

An diesem Punkt x=0wird die Reihe 1 + 0 + 0 + 0 + ...und ist somit gleich 1.

Agnius Vasiliauskas
quelle
Obwohl diese Antwort beeindruckend ist, ist es erwähnenswert, dass in der Mathematik die Grenze als x-> a von f (x) nicht unbedingt gleich f (a) ist, es sei denn, die Funktion ist bei x stetig.
Jasonszhao