Wszyscy wiemy, że 0 0 jest nieokreślone.
Ale , javascript mówi, że:
Math.pow(0, 0) === 1 // true
a C ++ mówi to samo:
pow(0, 0) == 1 // true
CZEMU?
Wiem to:
>Math.pow(0.001, 0.001)
0.9931160484209338
Ale dlaczego nie Math.pow(0, 0)
rzuca żadnych błędów? A może NaN
byłoby lepsze niż 1
.
javascript
c++
language-agnostic
pow
Ionică Bizău
źródło
źródło
Odpowiedzi:
W C ++
wynikiem pow (0, 0),wynik jest w zasadzie realizacja zdefiniowane zachowanie ponieważ matematycznie mamy sprzeczne sytuacji, w którejN^0
powinien być zawsze1
, ale0^N
zawsze powinien być0
zaN > 0
, więc nie powinno być żadnych oczekiwań matematycznie co do wyniku tego obaj. Ten post na forum Wolfram Alpha zawiera nieco więcej szczegółów.Chociaż uzyskanie
pow(0,0)
wyniku1
jest przydatne w wielu aplikacjach, ponieważ uzasadnienie dla normy międzynarodowej - języki programowania - stwierdza C w sekcji dotyczącej obsługi arytmetyki zmiennoprzecinkowej normy IEC 60559 :Zaktualizuj C ++
Jak leemes prawidłowo wskazał, że pierwotnie związany z odniesieniem do złożonej wersji pow natomiast zakaz złożonych roszczeń wersji jest to błąd domeny projekt C średnia ++ wraca do normy projekt C i zarówno C99 i C11 w sekcji
7.12.7.4
Funkcje pow ustęp 2 mówi ( podkreślenie moje ):co, o ile wiem, oznacza, że to zachowanie jest zachowaniem nieokreślonym. Wycofanie sekcji nieco w sekcji
7.12.1
Traktowanie warunków błędu mówi:Jeśli więc wystąpił błąd domeny, byłoby to zachowanie zdefiniowane w ramach implementacji, ale zarówno w najnowszych wersjach, jak
gcc
iclang
wartośćerrno
jest0
taka, więc nie jest to błąd domeny dla tych kompilatorów.Zaktualizuj Javascript
Dla JavaScript ECMAScript® Language Specification w punkcie
15.8
obiektu Math pod15.8.2.13
pow (x, y) , mówi między innymi warunkami, że:źródło
W JavaScript
Math.pow
definiuje się następująco :podkreślenie moje
co do zasady, funkcje natywne dla dowolnego języka powinny działać zgodnie z opisem w specyfikacji języka. Czasami obejmuje to jawnie „niezdefiniowane zachowanie”, w którym implementacja określa, jaki powinien być wynik, jednak nie jest to przypadek niezdefiniowanego zachowania.
źródło
__STDC_IEC_559__
aby ogłosić, że jest zgodna z tą specyfikacją. Załącznik F opisuje arytmetykę zmiennoprzecinkową normy IEC 60559. Uważam, że specyfikacja C może być częściowo zgodna z załącznikiem F (np. Pow (0, 0) == 1), a nie zdefiniowana__STDC_IEC_559__
.To jest po prostu konwencja go zdefiniować jako
1
,0
lub go opuścićundefined
. Definicja jest szeroko rozpowszechniona ze względu na następującą definicję:Dokumentacja ECMA-Script mówi co następuje
pow(x,y)
:[ http://www.ecma-international.org/ecma-262/5.1/#sec-15.8.2.13 ]
źródło
Według Wikipedii:
Istnieje kilka możliwych sposobów traktowania
0**0
za i przeciw dla każdego z nich ( poszerzona dyskusja znajduje się w Wikipedii ).IEEE 754-2008 pływających standardowy punkt zaleca trzy różne funkcje:
pow
traktuje0**0
jako1
. To jest najstarsza zdefiniowana wersja. Jeśli potęga jest dokładną liczbą całkowitą, wynik jest taki sam jak forpown
, w przeciwnym razie wynik jest jak forpowr
(z wyjątkiem niektórych wyjątkowych przypadków).pown
traktuje 0 ** 0 jako 1. Potęga musi być dokładną liczbą całkowitą. Wartość jest określona dla zasad ujemnych; np .pown(−3,5)
jest−243
.powr
traktuje 0 ** 0 jako NaN (Not-a-Number - undefined). Wartość wynosi również NaN w przypadkach,powr(−3,2)
gdy podstawa jest mniejsza od zera. Wartość jest określona przez exp (potęga × log (podstawa)).źródło
Donald Knuth
w pewnym sensie rozstrzygnął tę debatę w 1992 r., co następuje:
Jeszcze więcej szczegółów przedstawił w swoim artykule Two Notes on Notation .
Zasadniczo, chociaż nie mamy 1 jako limitu
f(x)/g(x)
dla wszystkich nie wszystkich funkcjif(x)
ig(x)
nadal sprawia, że kombinatoryka jest o wiele prostsza do zdefiniowania0^0=1
, a następnie po prostu utwórz specjalne przypadki w kilku miejscach, w których należy wziąć pod uwagę funkcje, takie jak0^x
, i tak są dziwne. Przecieżx^0
pojawia się dużo częściej.Niektóre z najlepszych dyskusji, jakie znam na ten temat (poza artykułem Knutha), to:
źródło
Jeśli chcesz wiedzieć, jaką wartość należy nadać,
f(a)
gdyf
nie jest bezpośrednio obliczalna w programiea
, obliczasz granicę,f
kiedyx
zmierza w kierunkua
.W przypadku
x^y
, zwykłe granice zmierzają do1
kiedyx
iy
mają tendencję0
, a zwłaszczax^x
do1
kiedyx
mają tendencję0
.Zobacz http://www.math.hmc.edu/funfacts/ffiles/10005.3-5.shtml
źródło
Definicja języka C mówi (7.12.7.4/2):
Mówi również (7.12.1 / 2):
Domyślnie wartością
math_errhandling
jestMATH_ERRNO
, więc sprawdźerrno
wartośćEDOM
.źródło
g++ (Ubuntu/Linaro 4.8.1-10ubuntu8) 4.8.
Chciałbym nie zgodzić się z twierdzeniem niektórych z poprzednich odpowiedzi, że jest to kwestia konwencji lub wygody (obejmującej pewne szczególne przypadki dla różnych twierdzeń itp.), Że 0 ^ 0 należy zdefiniować jako 1 zamiast 0.
Potęgowanie nie pasuje tak dobrze do naszych innych notacji matematycznych, więc definicja, której wszyscy się uczymy, pozostawia miejsce na nieporozumienia. Nieco innym sposobem podejścia jest stwierdzenie, że a ^ b (lub exp (a, b), jeśli wolisz) zwraca wartość będącą zwielokrotnieniem równoważnej pomnożeniu jakiejś innej rzeczy przez a, powtórzone b razy.
Kiedy pomnożymy 5 przez 4, 2 razy, otrzymamy 80. Pomnożymy 5 przez 16. Zatem 4 ^ 2 = 16.
Kiedy pomnożymy 14 przez 0, 0 razy, zostaje nam 14. Pomnożymy to 1. Stąd 0 ^ 0 = 1.
Ten sposób myślenia może również pomóc w wyjaśnieniu ujemnych i ułamkowych wykładników. 4 ^ (- 2) to 16., ponieważ „mnożenie ujemne” to dzielenie - dzielimy przez cztery dwukrotnie.
a ^ (1/2) to pierwiastek (a), ponieważ pomnożenie czegoś przez pierwiastek a jest połową pracy mnożenia jako pomnożenie tego przez samo a - musiałbyś to zrobić dwukrotnie, aby pomnożyć coś przez 4 = 4 ^ 1 = (4 ^ (1/2)) ^ 2
źródło
Aby to zrozumieć, musisz rozwiązać rachunek różniczkowy:
Rozwijając
x^x
wokół zera za pomocą szeregu Taylora, otrzymujemy:Aby zrozumieć, co dzieje się z limitem, gdy
x
dochodzi do zera, musimy dowiedzieć się, co się dzieje z drugim członemx log(x)
, ponieważ inne terminy są proporcjonalne dox log(x)
podniesienia do pewnej potęgi.Musimy użyć transformacji:
Teraz po tej transformacji możemy użyć reguły L'Hôpitala , która mówi, że:
Tak więc różnicując tę transformację otrzymujemy:
Więc obliczyliśmy ten termin
log(x)*x
zbliża się do 0, gdy x zbliża się do 0. Łatwo zauważyć, że inne kolejne wyrazy również zbliżają się do zera, a nawet szybciej niż drugi człon.W pewnym momencie
x=0
szereg staje się,1 + 0 + 0 + 0 + ...
a zatem równy 1.źródło