Почему 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
,
9 ответов
В C++ Результатом pow(0, 0) является в основном поведение, определяемое реализацией, поскольку математически мы имеем противоречивую ситуацию, когда N^0
всегда должен быть 1
но 0^N
всегда должен быть 0
за N > 0
Таким образом, у вас также не должно быть математических ожиданий относительно результата этого. В этом сообщении на форуме Wolfram Alpha есть немного больше деталей.
Хотя имея pow(0,0)
результат в 1
полезен для многих приложений, так как обоснование международного стандарта - языков программирования - C указывает в разделе, посвященном поддержке арифметики с плавающей точкой в IEC 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++
Как правильно указал Лимес, я изначально ссылался на ссылку для сложной версии pow, в то время как для некомплексной версии утверждается, что это ошибка домена, черновой стандарт C++ возвращается к черновому стандарту C, а также к C99 и C11 в разделе. 7.12.7.4
Пункт2 функций pow говорит (выделение мое):
[...] Ошибка домена может возникнуть, если 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.
В 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.
акцент мой
Как правило, нативные функции любого языка должны работать, как описано в спецификации языка. Иногда это включает явно "неопределенное поведение", когда разработчик должен определить, каким должен быть результат, однако это не случай неопределенного поведения.
Это просто соглашение, чтобы определить его как 1
, 0
или оставить это undefined
, Определение широко распространен из-за следующего определения:
В документации ECMA-Script сказано следующее pow(x,y)
:
- Если y равно +0, результат равен 1, даже если x равен NaN.
- Если y равен −0, результат равен 1, даже если x равен NaN.
Согласно Википедии:
В большинстве случаев, не связанных с непрерывностью показателя степени, интерпретация 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)).
Дональд Кнут
В 1992 году эта дискуссия была решена следующим образом:
И еще больше углубился в детали в своей статье " Две заметки о записи".
По сути, пока у нас нет 1 в качестве предела f(x)/g(x)
для всех не всех функций f(x)
а также g(x)
это все еще делает комбинаторику намного проще определить 0^0=1
, а затем просто сделать особые случаи в тех немногих местах, где вам нужно рассмотреть такие функции, как 0^x
, которые странные в любом случае. В конце концов x^0
появляется намного чаще.
Некоторые из лучших дискуссий, которые я знаю по этой теме (кроме статьи Кнута):
Когда вы хотите знать, какую ценность вы должны дать f(a)
когда f
не вычисляется напрямую в a
Вы вычисляете предел f
когда x
стремится к a
,
В случае x^y
, обычные пределы имеют тенденцию к 1
когда x
а также y
как правило 0
, и особенно x^x
стремится к 1
когда x
как правило 0
,
Определение языка 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
,
Я хотел бы не согласиться с утверждением некоторых предыдущих ответов о том, что это вопрос соглашения или удобства (охватывающий некоторые особые случаи для различных теорем и т. Д.), Что 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) - это root (a), потому что умножение чего-либо на корень a - это половина умножения на умножение его на a - вам придется сделать это дважды, чтобы умножить что-то на 4 = 4^1 = (4^(1/2))^2
Чтобы это понять, нужно решить исчисление:
расширяющийся x^x
около нуля, используя ряды Тейлора, получаем:
Чтобы понять, что происходит с лимитом, когда x
идет к нулю, нам нужно выяснить, что происходит со вторым сроком x log(x)
потому что другие термины пропорциональны x log(x)
возведен в какую-то власть.
Нам нужно использовать преобразование:
Теперь после этой трансформации мы можем использовать правило Л'Опитала, которое гласит:
Таким образом, дифференцируя это преобразование, мы получаем:
Итак, мы рассчитали этот термин log(x)*x
приближается к 0, когда x приближается к 0. Легко видеть, что другие последовательные слагаемые также приближаются к нулю и даже быстрее, чем второе слагаемое.
Итак, в момент x=0
сериал становится 1 + 0 + 0 + 0 + ...
и, таким образом, равен 1.