Почему Math.pow(0, 0) === 1?

Все мы знаем, что 00 неопределенно.

Но javascript говорит, что:

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

и C++ говорит то же самое:

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

ЗАЧЕМ?

Я знаю это:

>Math.pow(0.001, 0.001)
0.9931160484209338

Но почему Math.pow(0, 0) не выдает ошибок? Или, может быть, NaN будет лучше, чем 1.


person Ionică Bizău    schedule 13.11.2013    source источник
comment
@zzzzBov: Согласно стандартному определению, a‹sup›b‹/sup› = exp(b ln(a)), это не определено. Попытка определить его как limit‹sub›x-›0‹/sub›f(x)‹sup›g(x)‹/sup›, где f и g имеют нулевые пределы, дает неопределенное значение, поскольку оно зависит от выбор функций. (Извините за искаженное обозначение, я не могу понять, как получить надстрочные индексы в комментариях).   -  person Mike Seymour    schedule 13.11.2013
comment
@MikeSeymour, да, я знаю, что 0⁰ (использовать символы Юникода) не определено, учитывая это определение, однако, если вы читаете мой комментарий, вы должны заметить, что цитата относится к миру математики, а не к какому-либо стандартному определению. Именно эту разницу я изначально имел в виду, и вопрос был обновлен, чтобы исправить этот нюанс.   -  person zzzzBov    schedule 13.11.2013
comment
@AJMansfield Um...a^0 = 1 для ненулевого a.   -  person Beska    schedule 13.11.2013
comment
Это позволяет функциям, которые зависят от произведений вероятностей, давать разумные результаты. Представление о том, что компьютеры являются символьными математическими процессорами, неверно. Язык C имеет конкретную реализацию в реальном мире, в то время как ваш математический мир может быть слишком идеальным, чтобы его можно было реализовать на кремнии.   -  person IRTFM    schedule 14.11.2013
comment
Что касается математической версии этого вопроса — «почему мы часто определяем 0 ^ 0 = 1?» — на math.stackexchange есть много хороших ответов: math.stackexchange.com/questions/11150/   -  person PLL    schedule 14.11.2013
comment
IMHO 0^0 должен быть NaN, так же как 0/0 для с плавающей запятой, потому что предел не определен однозначно. Напротив, 1/0 IS четко определен как Бесконечность. Любой, кто утверждает, что 0 ^ 0 должно быть 1, потому что x ^ 0 = 1 для ненулевого x, смотрит только на половину - не забывайте, что 0 ^ y = 0 для y > 0. Я думаю, что настоящий ответ на этот вопрос заключается в том, что специальности CS больше не являются математическими специальностями, как это было в 1940-х годах.   -  person Matt    schedule 14.11.2013


Ответы (9)


В C++ результат pow(0, 0) результат в основном поведение, определяемое реализацией, поскольку математически у нас есть противоречивая ситуация, когда N^0 всегда должно быть 1, а 0^N всегда должно быть 0 для N > 0, поэтому у вас не должно быть никаких математических ожиданий относительно результата этого. В этих сообщениях на форуме Wolfram Alpha содержится более подробная информация.

Хотя результат pow(0,0) в 1 полезен для многих приложений, так как Обоснование для международного стандарта — Языки программирования — в разделе, посвященном поддержке IEC 60559 арифметики с плавающей запятой, C указывает:

Как правило, C99 избегает результата NaN, когда полезно числовое значение. [...] Результаты pow (∞, 0) и pow (0,0) равны 1, потому что есть приложения, которые могут использовать это определение. Например, если x(p) и y(p) — любые аналитические функции, обращающиеся в нуль при p = a, то pow(x,y), равная exp(y*log(x)), приближается к 1, когда p приближается к а.

Обновление C++

Как правильно заметил Лимес, я изначально ссылался на ссылку для сложной версии pow, в то время как несложная версия утверждает, что это ошибка домена проект стандарта C++ возвращается к черновик стандарта C, а также C99 и C11 в разделе 7.12.7.4 Функции pow параграф 2 говорит (выделено мной):

[...] Ошибка домена может возникнуть, если x равно нулю и y равно нулю.[...]

что, насколько я могу судить, означает, что такое поведение является неопределенным поведением Немного назад раздел 7.12.1 Обработка условий ошибки говорит:

[...] ошибка домена возникает, если входной аргумент находится за пределами домена, в котором определена математическая функция.[...] При ошибке домена функция возвращает значение, определяемое реализацией; если целочисленное выражение math_errhandling & MATH_ERRNO не равно нулю, целочисленное выражение errno получает значение EDOM; [...]

Таким образом, если была ошибка домена, то это было бы поведение, определяемое реализацией, но в обеих последних версиях gcc и clang значение errno равно 0, поэтому это не < em>ошибка домена для этих компиляторов.

Обновить Javascript

Для Javascript Спецификация языка ECMAScript® в разделе 15.8 < em>Математический объект под 15.8.2.13 pow (x, y) говорит среди прочих условий, что:

Если y равно +0, результатом будет 1, даже если x равно NaN.

person Shafik Yaghmour    schedule 13.11.2013
comment
@leemes Я считаю, что страница неверна, стандарт не говорит, что следует возвращать NaN. Возвращаемое значение определяется реализацией. cplusplus.com, который, как вы утверждаете, не является надежным источником, на самом деле является более точным. - person interjay; 13.11.2013
comment
@interjay Я думаю, вы имеете в виду удаленный ответ; Я только процитировал его ненадежность, надеясь, что это может объяснить отрицательное мнение (которое было сделано не мной). Что ж, обе страницы являются вики, поэтому их надежность зависит от их редакторов, которые тоже люди и допускают ошибки. ;) - person leemes; 13.11.2013
comment
@ShafikYaghmour Я связал тот же вопрос (в удаленном ответе). - person leemes; 13.11.2013
comment
@Shafik: отличный ответ; по существу (со ссылкой на авторитетный источник), но и информативно (со ссылкой на обоснование). - person alecov; 14.11.2013
comment
@Alek Я ценю обратную связь, я стараюсь писать ответы, которые я хотел бы прочитать от других. У меня не всегда получается, но я стараюсь. Писать хорошие вопросы еще сложнее, я пытался это сделать только один раз и потратил на это гораздо больше времени, чем на свои ответы. - person Shafik Yaghmour; 14.11.2013

В JavaScript Math.pow определяется следующим образом:

  • Если y равно NaN, результатом будет NaN.
  • Если y равно +0, результатом будет 1, даже если x равно NaN.
  • Если y равно −0, результатом будет 1, даже если x равно NaN.
  • Если x равно NaN, а y отлично от нуля, результатом будет NaN.
  • Если abs(x)>1 и y равно +∞, результат равен +∞.
  • Если abs(x)>1 и y равно −∞, результат равен +0.
  • Если abs(x)==1 и y равно +∞, результатом будет NaN.
  • Если abs(x)==1 и y равно −∞, результатом будет NaN.
  • Если abs(x)‹1 и y равно +∞, результат равен +0.
  • Если abs(x)‹1 и y равно −∞, результат равен +∞.
  • Если x равно +∞ и y>0, результат равен +∞.
  • Если x равно +∞, а y‹0, результат равен +0.
  • Если x равно −∞, y>0 и y является нечетным целым числом, результат равен −∞.
  • Если x равно −∞, y>0 и y не является нечетным целым числом, результат равен +∞.
  • Если x равно −∞, y‹0 и y является нечетным целым числом, результат равен −0.
  • Если x равно −∞, y‹0 и y не является нечетным целым числом, результат равен +0.
  • Если x равно +0 и y>0, результат равен +0.
  • Если x равно +0 и y‹0, результат равен +∞.
  • Если x равно −0, y>0 и y является нечетным целым числом, результат равен −0.
  • Если x равно −0, y>0 и y не является нечетным целым числом, результат равен +0.
  • Если x равно −0, y‹0 и y является нечетным целым числом, результат равен −∞.
  • Если x равно −0, y‹0 и y не является нечетным целым числом, результат равен +∞.
  • Если x‹0 и x конечно, а y конечно и y не является целым числом, результатом будет NaN.

выделено мной

как правило, нативные функции для любого языка должны работать так, как описано в спецификации языка. Иногда это включает явное «неопределенное поведение», когда разработчик должен определить, каким должен быть результат, однако это не случай неопределенного поведения.

person zzzzBov    schedule 13.11.2013
comment
Приложение F к стандартам C99 и C11 содержит ту же самую спецификацию. Предполагается, что реализация определяет __STDC_IEC_559__, чтобы объявить, что она соответствует этой спецификации. Приложение F описывает арифметику с плавающей запятой стандарта IEC 60559. Я считаю, что спецификация C может частично соответствовать Приложению F (например, pow(0, 0) == 1) и не определять __STDC_IEC_559__. - person Howard Hinnant; 13.11.2013
comment
@HowardHinnant хммм, похоже, что в случае с gcc и clang эта часть информации может быть не совсем полезной, т.е. обескураживающий. - person Shafik Yaghmour; 13.11.2013
comment
Я не знаю, поможет ли этот ответ. Конечно, функция должна работать так, как определено в спецификации. Но тогда возникает вопрос: Почему это было определено именно так в спецификации? - person Beska; 13.11.2013
comment
Хорошо, что это (вероятно) сделано на аппаратном уровне, иначе производительность со всеми этими особыми случаями снизилась бы :) - person Thomas; 14.11.2013

Это просто соглашение определить его как 1, 0 или оставить его undefined. Определение pow(0,0)широко распространено из-за следующего определения:

определение математической мощности


В документации ECMA-Script о pow(x,y) говорится следующее:

  • Если y равно +0, результатом будет 1, даже если x равно NaN.
  • Если y равно −0, результатом будет 1, даже если x равно NaN.

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

person schmijos    schedule 13.11.2013
comment
На math.stackexchange есть много хороших обсуждений и объяснений определения 0^0=1: math.stackexchange.com/questions/11150/ - person PLL; 14.11.2013

Согласно Википедии:

В большинстве случаев, не связанных с непрерывностью показателя степени, интерпретация 00 как 1 упрощает формулы и устраняет необходимость в особых случаях в теоремах.

Существует несколько возможных способов трактовки 0**0 со всеми плюсами и минусами (подробное обсуждение см. в Википедии).

Стандарт IEEE 754-2008 с плавающей запятой рекомендует три разные функции:

  • pow рассматривает 0**0 как 1. Это самая старая определенная версия. Если мощность является точным целым числом, результат будет таким же, как для pown, в противном случае результат будет таким же, как для powr (за исключением некоторых исключительных случаев).
  • pown обрабатывает 0**0 как 1. Степень должна быть точным целым числом. Значение определяется для отрицательных оснований; например, pown(−3,5) равно −243.
  • powr обрабатывает 0**0 как NaN (Not-a-Number — undefined). Значение также равно NaN для таких случаев, как powr(−3,2), где основание меньше нуля. Значение определяется выражением exp(power'×log(base)).
person NPE    schedule 13.11.2013

Дональд Кнут

вроде как урегулировал этот спор в 1992 году следующим:

введите здесь описание изображения

И еще больше углубился в детали в своей статье Two Notes on Notation< /а>.

По сути, хотя у нас нет 1 в качестве предела f(x)/g(x) для всех, а не для всех функций f(x) и g(x), это по-прежнему делает комбинаторику намного проще для определения 0^0=1, а затем просто создавать специальные случаи в тех немногих местах, где вам нужно учитывать функции. такие как 0^x, которые в любом случае странные. Ведь x^0 встречается гораздо чаще.

Некоторые из лучших известных мне дискуссий по этой теме (кроме статьи Кнута):

person Thomas Ahle    schedule 04.12.2013
comment
Если вы не читали некоторые из них, прочитайте ответы в Zero to the Zero power...? который был связан с вопросом, который вы должны использовать, некоторые ответы также охватывают этот подход. - person Shafik Yaghmour; 06.12.2013

Когда вы хотите знать, какое значение вы должны присвоить f(a), когда f не вычисляется напрямую в a, вы вычисляете предел f, когда x стремится к a.

В случае x^y обычные пределы стремятся к 1, когда x и y стремятся к 0, и особенно x^x стремится к 1, когда x стремится к 0.

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

person Denys Séguret    schedule 13.11.2013

Определение языка C гласит (7.12.7.4/2):

Ошибка домена может возникнуть, если x равно нулю, а y равно нулю.

В нем также говорится (7.12.1/2):

При ошибке домена функция возвращает значение, определяемое реализацией; если целочисленное выражение math_errhandling & MATH_ERRNO не равно нулю, целочисленное выражение errno получает значение EDOM; если целочисленное выражение math_errhandling & MATH_ERREXCEPT не равно нулю, возникает «недопустимое» исключение с плавающей запятой.

По умолчанию значение math_errhandling равно MATH_ERRNO, поэтому проверьте errno на значение EDOM.

person Pete Becker    schedule 13.11.2013
comment
Упс! Это действительно интересно! Я скомпилировал свой файл cpp, используя g++ (Ubuntu/Linaro 4.8.1-10ubuntu8) 4.8. - person Ionică Bizău; 13.11.2013

Я хотел бы не согласиться с некоторыми утверждениями предыдущих ответов о том, что это вопрос соглашения или удобства (охватывающий некоторые особые случаи для различных теорем и т. д.), что 0 ^ 0 определяется как 1 вместо 0.

Возведение в степень на самом деле не очень хорошо сочетается с другими нашими математическими обозначениями, поэтому определение, которое мы все выучили, оставляет место для путаницы. Немного другой способ приблизиться к этому — сказать, что a^b (или exp(a, b), если хотите) возвращает значение, мультипликативно эквивалентное умножению какой-то другой вещи на a, повторенный b раз.

Когда мы умножаем 5 на 4, 2 раза, мы получаем 80. Мы умножили 5 на 16. Итак, 4^2 = 16.

Когда вы умножаете 14 на 0,0 раз, у нас остается 14. Мы умножили это на 1. Следовательно, 0^0 = 1.

Этот ход мыслей также может помочь прояснить отрицательные и дробные показатели. 4^(-2) — это 16-е, потому что «отрицательное умножение» — это деление — мы дважды делим на четыре.

a^(1/2) — это корень (a), потому что умножение чего-то на корень a — это половина мультипликативной работы по сравнению с умножением на само a — вам придется сделать это дважды, чтобы что-то умножить на 4 = 4^1 = (4^(1/2))^2

person NiloCK    schedule 06.12.2013

Чтобы это понять, нужно решить исчисление:

введите здесь описание изображения

Расширяя x^x вокруг нуля с помощью ряда Тейлора, мы получаем:

введите здесь описание изображения

Итак, чтобы понять, что происходит с пределом, когда x стремится к нулю, нам нужно выяснить, что происходит со вторым членом x log(x), потому что другие члены пропорциональны x log(x), возведенному в некоторую степень.

Нам нужно использовать преобразование:

введите здесь описание изображения

Теперь после этого преобразования мы можем использовать правило Лопиталя, в котором говорится, что:

введите здесь описание изображения

Таким образом, дифференцируя это преобразование, мы получаем:

введите здесь описание изображения

Итак, мы подсчитали, что член log(x)*x приближается к 0, когда x приближается к 0. Легко видеть, что другие последовательные члены также стремятся к нулю и даже быстрее, чем второй член.

Таким образом, в точке x=0 ряд становится 1 + 0 + 0 + 0 + ... и, таким образом, равен 1.

person Agnius Vasiliauskas    schedule 03.11.2015
comment
Хотя этот ответ впечатляет, стоит отметить, что в математике предел x->a функции f(x) не обязательно равен f(a), если только функция не является непрерывной в точке x. - person user; 23.04.2017