¿Por qué Math.pow (0, 0) === 1?

85

Todos sabemos que 0 0 es indeterminado.

Pero , javascript dice que:

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

y C ++ dice lo mismo:

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

¿POR QUÉ?

Yo sé eso:

>Math.pow(0.001, 0.001)
0.9931160484209338

Pero, ¿por qué no Math.pow(0, 0)arroja errores? O tal vez NaNsería mejor que 1.

Ionică Bizău
fuente
3
@zzzzBov: Según la definición estándar, "a <sup> b </sup> = exp (b ln (a))", no está definido. Tratar de definirlo como "límite <sub> x-> 0 </sub> f (x) <sup> g (x) </sup>" donde "f" y "g" tienen límites de cero da un valor indeterminado valor, ya que depende de su elección de funciones. (Disculpas por la notación destrozada; no puedo averiguar cómo obtener superíndices en los comentarios).
Mike Seymour
@MikeSeymour, sí, soy consciente de que 0⁰ (usar caracteres Unicode) no está definido dada esa definición, sin embargo, si lees mi comentario, debes tener en cuenta que la cita hace referencia al "mundo de las matemáticas" en lugar de cualquier "definición estándar". Es esta diferencia a la que me refería originalmente, y la pregunta se ha actualizado para corregir este matiz.
zzzzBov
2
@AJMansfield Um ... a ^ 0 = 1 para un valor distinto de cero a.
Beska
Permite que las funciones que dependen de productos de probabilidades proporcionen resultados sensibles. Es una noción incorrecta que las computadoras sean procesadores matemáticos simbólicos. El lenguaje C tiene una implementación específica en el mundo real, mientras que su mundo matemático puede ser demasiado ideal para ser implementado en silicio.
IRTFM
26
Para la versión matemática de esta pregunta, "¿por qué a menudo definimos 0 ^ 0 = 1?" - math.stackexchange tiene muchas buenas respuestas: math.stackexchange.com/questions/11150/…
PLL

Respuestas:

78

En C ++ El resultado de pow (0, 0) el resultado es básicamente un comportamiento definido por la implementación ya que matemáticamente tenemos una situación contradictoria donde N^0siempre debería estar 1pero 0^Nsiempre debería ser 0para N > 0, por lo que tampoco debería tener expectativas matemáticas en cuanto al resultado de esto. Este Wolfram Alpha mensajes en el foro entra en un poco más de detalles.

Aunque tener un pow(0,0)resultado en 1es útil para muchas aplicaciones, ya que la Justificación de la Norma Internacional — Lenguajes de programación — C establece en la sección que cubre el soporte aritmético de coma flotante IEC 60559 :

Generalmente, C99 evita un resultado NaN donde un valor numérico es útil. [...] Los resultados de pow (∞, 0) y pow (0,0) son ambos 1, porque hay aplicaciones que pueden aprovechar esta definición. Por ejemplo, si x (p) y y (p) son funciones analíticas que se vuelven cero en p = a, entonces pow (x, y), que es igual a exp (y * log (x)), se acerca a 1 cuando p se acerca a.

Actualizar C ++

Como leemes señaló correctamente, originalmente me vinculé a la referencia para la versión compleja de pow mientras que la versión no compleja afirma que es un error de dominio, el borrador del estándar C ++ recurre al borrador del estándar C y tanto C99 como C11 en la sección 7.12.7.4 El párrafo de funciones de pow 2 dice ( énfasis mío ):

[...] Puede ocurrir un error de dominio si x es cero e y es cero. [...]

lo que, por lo que puedo decir, significa que este comportamiento es un comportamiento no especificado Rebobinando una sección de bits El 7.12.1 tratamiento de las condiciones de error dice:

[...] ocurre un error de dominio si un argumento de entrada está fuera del dominio sobre el que se define la función matemática. [...] En un error de dominio, la función devuelve un valor definido por la implementación; si la expresión entera math_errhandling & MATH_ERRNO es distinta de cero, la expresión entera errno adquiere el valor EDOM; [...]

Entonces, si hubiera un error de dominio , este sería un comportamiento definido por la implementación, pero tanto en las últimas versiones de gcccomo en clangel valor de errnoes, 0por lo que no es un error de dominio para esos compiladores.

Actualizar Javascript

Para Javascript, la Especificación del lenguaje ECMAScript® en la sección 15.8 El objeto matemático bajo 15.8.2.13 pow (x, y) dice, entre otras condiciones, que:

Si y es +0, el resultado es 1, incluso si x es NaN.

Shafik Yaghmour
fuente
1
@leemes Creo que la página está mal, el estándar no dice que se deba devolver NaN. El valor de retorno está definido por la implementación. cplusplus.com, que afirma que no es una fuente confiable, es en realidad más precisa aquí.
Interjay
@interjay Supongo que te refieres a la respuesta eliminada; Solo cité sobre su falta de confiabilidad, con la esperanza de que pudiera explicar el voto negativo (que no fue mío). Bueno, ambas páginas son wikis, por lo que su confiabilidad depende de sus editores que son humanos y cometen errores. ;)
leemes
@leemes, la comunidad de C ++ en SO definitivamente tiene una fuerte aversión por cplusplus.com
Shafik Yaghmour
@ShafikYaghmour Vinculé la misma pregunta (en la respuesta eliminada).
leemes
1
@Alek Aprecio los comentarios, trato de escribir las respuestas que me gustaría leer de otros. No siempre lo logro, pero lo intento. Escribir buenas preguntas es aún más difícil, solo lo he intentado una vez y pasé mucho más tiempo en ello que en mis respuestas.
Shafik Yaghmour
35

En JavaScript Math.powse define de la siguiente manera :

  • Si y es NaN, el resultado es NaN.
  • Si y es +0, el resultado es 1, incluso si x es NaN.
  • Si y es −0, el resultado es 1, incluso si x es NaN.
  • Si x es NaN e y es distinto de cero, el resultado es NaN.
  • Si abs (x)> 1 e y es + ∞, el resultado es + ∞.
  • Si abs (x)> 1 y y es −∞, el resultado es +0.
  • Si abs (x) == 1 y y es + ∞, el resultado es NaN.
  • Si abs (x) == 1 y y es −∞, el resultado es NaN.
  • Si abs (x) <1 y y es + ∞, el resultado es +0.
  • Si abs (x) <1 y y es −∞, el resultado es + ∞.
  • Si x es + ∞ e y> 0, el resultado es + ∞.
  • Si x es + ∞ e y <0, el resultado es +0.
  • Si x es −∞ y y> 0 e y es un número entero impar, el resultado es −∞.
  • Si x es −∞ y y> 0 e y no es un número entero impar, el resultado es + ∞.
  • Si x es −∞ y y <0 e y es un entero impar, el resultado es −0.
  • Si x es −∞ y y <0 e y no es un número entero impar, el resultado es +0.
  • Si x es +0 e y> 0, el resultado es +0.
  • Si x es +0 e y <0, el resultado es + ∞.
  • Si x es −0 y y> 0 e y es un número entero impar, el resultado es −0.
  • Si x es −0 y y> 0 e y no es un número entero impar, el resultado es +0.
  • Si x es −0 y y <0 e y es un número entero impar, el resultado es −∞.
  • Si x es −0 e y <0 e y no es un número entero impar, el resultado es + ∞.
  • Si x <0 y x es finito e y es finito e y no es un número entero, el resultado es NaN.

énfasis mío

como regla general, las funciones nativas de cualquier idioma deberían funcionar como se describe en la especificación del idioma. A veces esto incluye explícitamente "comportamiento indefinido" en el que depende del implementador determinar cuál debería ser el resultado, sin embargo, este no es un caso de comportamiento indefinido.

zzzzBov
fuente
El anexo F de las normas C99 y C11 contiene esta misma especificación. Se supone que una implementación se define __STDC_IEC_559__para anunciar que se ajusta a esta especificación. El anexo F describe la aritmética de coma flotante IEC 60559. Creo que una especificación C puede cumplir parcialmente con el Anexo F (por ejemplo, pow (0, 0) == 1) y no definir __STDC_IEC_559__.
Howard Hinnant
@HowardHinnant hmmm, parece que en el caso de gcc y clang, esa información puede no ser totalmente útil, eso es desalentador.
Shafik Yaghmour
6
No sé si esta respuesta ayuda. Por supuesto, la función debe realizarse como se define en la especificación. Pero entonces la pregunta simplemente se convierte en "¿Por qué se definió de esta manera en la especificación?"
Beska
Lo bueno es que esto (probablemente) se hace en hardware, de lo contrario, afectaría el rendimiento con todos estos casos especiales :)
Thomas
16

Es una convención definirlo como 1, 0o dejarlo undefined. La definición pow (0,0)está muy extendida debido a la siguiente definición:

definición de potencia matemática


La documentación de ECMA-Script dice lo siguiente sobre pow(x,y):

  • Si y es +0, el resultado es 1, incluso si x es NaN.
  • Si y es −0, el resultado es 1, incluso si x es NaN.

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

schmijos
fuente
3
math.stackexchange tiene muchas buenas discusiones y explicaciones para la definición 0 ^ 0 = 1: math.stackexchange.com/questions/11150/…
PLL
14

Según Wikipedia:

En la mayoría de los escenarios que no involucran continuidad en el exponente, interpretar 0 0 como 1 simplifica las fórmulas y elimina la necesidad de casos especiales en los teoremas.

Hay varias formas posibles de tratar 0**0con los pros y los contras de cada uno (consulte Wikipedia para una discusión más extensa).

El estándar de punto flotante IEEE 754-2008 recomienda tres funciones diferentes:

  • powtrata 0**0como 1. Ésta es la versión definida más antigua. Si la potencia es un entero exacto, el resultado es el mismo que para pown, de lo contrario, el resultado es como para powr(salvo algunos casos excepcionales).
  • powntrata 0 ** 0 como 1. La potencia debe ser un número entero exacto. El valor se define para bases negativas; por ejemplo, pown(−3,5)es −243.
  • powrtrata 0 ** 0 como NaN (Not-a-Number - undefined). El valor también es NaN para casos como powr(−3,2)donde la base es menor que cero. El valor está definido por exp (potencia '× log (base)).
NPE
fuente
6

Donald Knuth

de alguna manera resolvió este debate en 1992 con lo siguiente:

ingrese la descripción de la imagen aquí

Y entró aún más en detalles en su artículo Two Notes on Notation .

Básicamente, mientras que no tenemos 1 como el límite de f(x)/g(x)para todos no todas las funciones f(x)y g(x), todavía tiene la combinatoria de manera mucho más simple de definir 0^0=1, y luego simplemente hacemos casos especiales en los pocos lugares donde se necesita tener en cuenta las funciones, tales como 0^x, la cual son raros de todos modos. Después de todo, x^0surge mucho más a menudo.

Algunas de las mejores discusiones que conozco sobre este tema (además del artículo de Knuth) son:

Thomas Ahle
fuente
Si no has leído alguno lee las respuestas en Cero a la potencia cero ...? que se vinculó con la pregunta, algunas de las respuestas también cubren este enfoque.
Shafik Yaghmour
5

Cuando desee saber a qué valor debe dar f(a)cuando fno es directamente computable a, calcula el límite de fcuando xtiende hacia a.

En el caso de x^y, los límites habituales tienden hacia 1cuándo xy ytienden 0, y sobre todo x^xtiende hacia 1cuándo xtiende 0.

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

Denys Séguret
fuente
5

La definición del lenguaje C dice (7.12.7.4/2):

Puede ocurrir un error de dominio si x es cero e y es cero.

También dice (7.12.1 / 2):

En un error de dominio, la función devuelve un valor definido por la implementación; si la expresión entera math_errhandling & MATH_ERRNO es distinta de cero, la expresión entera errno adquiere el valor EDOM; si la expresión de entero math_errhandling & MATH_ERREXCEPT es distinta de cero, se genera la excepción de punto flotante '' no válido ''.

De forma predeterminada, el valor de math_errhandlinges MATH_ERRNO, así que verifique errnoel valor EDOM.

Pete Becker
fuente
1
¡Whoups! ¡Eso es realmente interesante! g++ (Ubuntu/Linaro 4.8.1-10ubuntu8) 4.8.
Compilé
0

Me gustaría no estar de acuerdo con la afirmación de algunas de las respuestas anteriores de que es una cuestión de convención o conveniencia (que cubre algunos casos especiales para varios teoremas, etc.) que 0 ^ 0 se defina como 1 en lugar de 0.

La exponenciación en realidad no encaja tan bien con nuestras otras notaciones matemáticas, por lo que la definición que todos aprendemos deja lugar a la confusión. Una forma ligeramente diferente de abordarlo es decir que a ^ b (o exp (a, b), si lo desea) devuelve el valor multiplicativamente equivalente a multiplicar alguna otra cosa por a, repetido b veces.

Cuando multiplicamos 5 por 4, 2 veces, obtenemos 80. Hemos multiplicado 5 por 16. Entonces 4 ^ 2 = 16.

Cuando multiplica 14 por 0, 0 veces, nos queda 14. Lo hemos multiplicado 1. Por lo tanto, 0 ^ 0 = 1.

Esta línea de pensamiento también podría ayudar a aclarar exponentes negativos y fraccionarios. 4 ^ (- 2) es un dieciseisavo, porque la 'multiplicación negativa' es una división; dividimos por cuatro dos veces.

a ^ (1/2) es raíz (a), porque multiplicar algo por la raíz de a es la mitad del trabajo multiplicativo que multiplicarlo por a sí mismo; tendrías que hacerlo dos veces para multiplicar algo por 4 = 4 ^ 1 = (4 ^ (1/2)) ^ 2

NiloCK
fuente
0

Para que esto se entienda, necesitas resolver cálculo:

ingrese la descripción de la imagen aquí

Al expandir x^xalrededor de cero usando la serie de Taylor, obtenemos:

ingrese la descripción de la imagen aquí

Entonces, para entender qué está sucediendo con el límite cuando xllega a cero, necesitamos averiguar qué está sucediendo con el segundo término x log(x), porque otros términos son proporcionales a x log(x)elevar a alguna potencia.

Necesitamos usar la transformación:

ingrese la descripción de la imagen aquí

Ahora, después de esta transformación, podemos usar la regla de L'Hôpital , que establece que:

ingrese la descripción de la imagen aquí

Así que diferenciando esa transformación obtenemos:

ingrese la descripción de la imagen aquí

Así que hemos calculado que el término se log(x)*xacerca a 0 cuando x se acerca a 0. Es fácil ver que otros términos consecutivos también se acercan a cero e incluso más rápido que el segundo término.

Entonces, en el punto x=0, la serie se vuelve 1 + 0 + 0 + 0 + ...y, por lo tanto, es igual a 1.

Agnius Vasiliauskas
fuente
Si bien esta respuesta es impresionante, vale la pena señalar que en matemáticas, el límite como x-> a de f (x) no es necesariamente igual a f (a), a menos que la función sea continua en x.
jasonszhao