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

85

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

Но , 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.

Ионика Бизэу
источник
3
@zzzzBov: Согласно стандартному определению «a <sup> b </sup> = exp (b ln (a))», он не определен. Попытка определить его как «limit <sub> x-> 0 </sub> f (x) <sup> g (x) </sup>», где «f» и «g» имеют нулевые пределы, дает неопределенный значение, поскольку оно зависит от вашего выбора функций. (Прошу прощения за искаженную нотацию; я не могу понять, как получить надстрочные индексы в комментариях).
Майк Сеймур,
@MikeSeymour, да, я знаю, что 0⁰ (использовать символы Unicode) не определено с учетом этого определения, однако, если вы прочитаете мой комментарий, вы должны заметить, что цитата ссылается на «мир математики», а не на какое-либо «стандартное определение». Это различие, о котором я говорил изначально, и вопрос был обновлен, чтобы исправить этот нюанс.
zzzzBov
2
@AJMansfield Um ... a ^ 0 = 1 для ненулевого a.
Beska
Это позволяет функциям, зависящим от произведений вероятностей, предоставлять разумные результаты. Это неправильное представление о компьютерах как о символьных математических процессорах. Язык C имеет конкретную реализацию в реальном мире, в то время как ваш математический мир может быть слишком идеальным, чтобы быть реализованным в кремнии.
IRTFM
26
Что касается математической версии этого вопроса - «почему мы часто определяем 0 ^ 0 = 1?» - У math.stackexchange много хороших ответов: math.stackexchange.com/questions/11150/…
PLL

Ответы:

78

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

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

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

Обновить C ++

Как leemes правильно указал , что я изначально связанно с ссылкой на комплексную версию мощна в то время как несложная версию утверждает , что это ошибка домена проекта стандарта C ++ возвращается к проекту стандарта C и как С99 и С11 в разделе 7.12.7.4 военнопленной функции пункт 2 говорит ( выделено мной ):

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

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

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

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

Обновить Javascript

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

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

Шафик Ягмур
источник
1
@leemes Я считаю, что страница неправильная, стандарт не говорит, что NaN следует возвращать. Возвращаемое значение определяется реализацией. cplusplus.com, который, по вашему мнению, не является надежным источником, на самом деле более точен.
Interjay
@interjay Думаю, вы имеете в виду удаленный ответ; Я только процитировал его ненадежность, надеясь, что он может объяснить отрицательный голос (который был не мной). Что ж, обе страницы являются вики, поэтому их надежность зависит от их редакторов, которые люди и делают ошибки. ;)
leemes
@leemes сообщество C ++ на SO определенно сильно не любит cplusplus.com
Шафик Ягмор
@ShafikYaghmour Я связал тот же вопрос (в удаленном ответе).
leemes
1
@Alek Я ценю отзывы, я стараюсь писать ответы, которые я хотел бы прочитать от других. У меня не всегда получается, но я стараюсь. Писать хорошие вопросы еще сложнее, я попробовал это только один раз и потратил на это гораздо больше времени, чем на свои ответы.
Shafik Yaghmour
35

В 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.

акцент мой

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

zzzzBov
источник
Приложение F к стандартам C99 и C11 содержит ту же спецификацию. Предполагается, что реализация __STDC_IEC_559__объявляет, что она соответствует этой спецификации. Приложение F описывает арифметические операции с плавающей запятой МЭК 60559. Я считаю, что спецификации C разрешено частично соответствовать Приложению F (например, pow (0, 0) == 1), а не определять __STDC_IEC_559__.
Говард Хиннант
@HowardHinnant хммм, кажется, что в случае gcc и clang эта информация может быть не совсем полезной, что обескураживает.
Shafik Yaghmour
6
Не знаю, поможет ли этот ответ. Конечно, функция должна работать так, как определено в спецификации. Но тогда возникает вопрос: «Почему в спецификации это было определено таким образом?»
Beska
Хорошо, что это (вероятно) реализовано аппаратно, иначе это снизит производительность во всех этих особых случаях :)
Thomas
16

Это просто условность определить его как 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 ]

Schmijos
источник
3
В math.stackexchange есть много хороших обсуждений и объяснений определения 0 ^ 0 = 1: math.stackexchange.com/questions/11150/…
PLL
14

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

В большинстве случаев, не связанных с непрерывностью показателя степени, интерпретация 0 0 как 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)).
NPE
источник
6

Дональд Кнут

В 1992 году эти дебаты были решены следующим образом:

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

И еще более подробно описал в своей статье Две заметки о нотации. .

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

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

Томас Але
источник
Если вы еще не читали, то читаете ответы в Ноль в нулевую степень ...? который был связан с вопросом, на который вы должны ответить, также этот подход.
Shafik Yaghmour
5

Когда вы хотите знать, какое значение вы должны дать, 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.

Дени Сегюре
источник
5

Определение языка 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.

Пит Беккер
источник
1
Бах! Это действительно интересно! Я скомпилировал свой файл cpp с помощьюg++ (Ubuntu/Linaro 4.8.1-10ubuntu8) 4.8.
Ionică Bizău
0

Я хотел бы не согласиться с утверждением некоторых из предыдущих ответов о том, что это вопрос соглашения или удобства (охватывающий некоторые особые случаи для различных теорем и т.д.), что 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

NiloCK
источник
0

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

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

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

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

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

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

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

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

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

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

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

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

Итак, в данный момент x=0серия становится 1 + 0 + 0 + 0 + ...равной 1.

Агниус Василяускас
источник
Хотя этот ответ впечатляет, стоит отметить, что в математике предел как x-> a для f (x) не обязательно равен f (a), если только функция не является непрерывной в x.
jasonszhao