Wszyscy wiemy, że 0/0
jest Undefined
i zwraca błąd, gdybym włożył go do kalkulatora, a gdybym stworzył program (przynajmniej w C), system operacyjny zakończyłby go, gdy spróbuję podzielić przez zero.
Zastanawiam się jednak, czy komputer nawet próbuje podzielić przez zero , czy też po prostu ma „wbudowaną ochronę”, więc kiedy „widzi” 0/0
, zwraca błąd nawet przed próbą jego obliczenia?
math
error-handling
arithmetic
Ankush
źródło
źródło
Odpowiedzi:
Procesor ma wbudowane wykrywanie. Większość architektur zestawu instrukcji określa, że procesor będzie przechwytywał procedurę obsługi wyjątków dla dzielenia liczb całkowitych przez zero (nie sądzę, że to obchodzi, czy dywidenda wynosi zero).
Możliwe jest, że sprawdzenie zerowego dzielnika odbywa się równolegle sprzętowo wraz z próbą wykonania podziału, jednak wykrycie warunku skutecznego anuluje podział i pułapki, więc nie możemy tak naprawdę stwierdzić, czy jakaś część z tego podjęto próbę podziału, czy nie.
(Sprzęt często działa w ten sposób, wykonując wiele czynności równolegle, a następnie wybierając odpowiedni wynik, ponieważ wtedy każda z operacji może rozpocząć się od razu, zamiast serializować wybór odpowiedniej operacji).
Ten sam mechanizm pułapki na wyjątek będzie również używany, gdy włączone jest wykrywanie przepełnienia, o które zwykle prosisz, używając różnych instrukcji add / sub / mul (lub flagi na tych instrukcjach).
Dzielenie zmiennoprzecinkowe ma również wbudowane wykrywanie dzielenia przez zero, ale zwraca inną wartość ( IEEE 754 określa NaN ) zamiast wychwytywania do procedury obsługi wyjątku.
Hipotetycznie rzecz biorąc, jeśli procesor pominąłby jakiekolwiek wykrycie przy próbie podzielenia przez zero, problemy mogą obejmować:
źródło
Zależy to od języka, od kompilatora, od tego, czy używasz liczb całkowitych czy liczb zmiennoprzecinkowych i tak dalej.
W przypadku liczby zmiennoprzecinkowej większość implementacji używa standardu IEEE 754 , w którym podział przez 0 jest dobrze zdefiniowany. 0/0 daje dobrze zdefiniowany wynik NaN (nie-liczba), a x / 0 dla x ≠ 0 daje + Infinity lub -Infinity, w zależności od znaku x.
W językach takich jak C, C ++ itp. Dzielenie przez zero wywołuje niezdefiniowane zachowanie. Zgodnie z definicją języka wszystko może się zdarzyć. Zwłaszcza rzeczy, których nie chcesz się wydarzyć. Jak wszystko, co działa idealnie dobrze, gdy piszesz kod i niszczy dane, gdy klient go używa. Z punktu widzenia języka nie rób tego . Niektóre języki gwarantują, że aplikacja się zawiesi; jak to zostanie wdrożone, zależy od nich. W przypadku tych języków podział przez zero ulegnie awarii.
Wiele procesorów ma wbudowaną instrukcję „dzielenia”, która zachowuje się inaczej w zależności od procesora. W 32-bitowych i 64-bitowych procesorach Intel instrukcje „dzielenia” powodują awarię aplikacji podczas próby dzielenia przez zero. Inne procesory mogą zachowywać się inaczej.
Jeśli kompilator wykryje, że wystąpi dzielenie przez zero, gdy wykonasz jakiś kod, a kompilator jest miły dla użytkowników, prawdopodobnie wyświetli ostrzeżenie i wygeneruje wbudowaną instrukcję „dzielenia”, aby zachowanie było podobnie.
źródło
EXCEPTION_INT_DIVIDE_BY_ZERO
wartość wEXCEPTION_RECORD
które będą obsługiwane przez (miejmy nadzieję) zainstalowany Structed Exception Handling HandlerWygląda na to, że zastanawiasz się, co by się stało, gdyby ktoś wykonał procesor, który nie sprawdza wprost zerowania przed podziałem. To, co by się stało, zależy całkowicie od wdrożenia podziału. Bez wchodzenia w szczegóły jeden rodzaj implementacji dałby wynik, który ma ustawione wszystkie bity, np. 65535 na 16-bitowym procesorze. Inny może się rozłączyć.
źródło
Ponieważ
x/0
nie ma sensu, kropka, komputery zawsze muszą sprawdzać podział przez zero. Jest tu problem: programiści chcą obliczać(a+b)/c
bez konieczności sprawdzania, czy te obliczenia mają sens. Podstawowa reakcja na dzielenie przez zero przez procesor + typ liczb + system operacyjny + język polega na zrobieniu czegoś dość drastycznego (np. Awaria programu) lub zrobieniu czegoś zbyt łagodnego (np. Utworzenie wartości, która nie powoduje sens, taki jak zmiennoprzecinkowy IEEENaN
, liczba „Nie jest liczbą”).W zwykłym otoczeniu programista powinien wiedzieć, czy
(a+b)/c
ma to sens. W tym kontekście nie ma powodu, aby sprawdzać podział przez zero. Jeśli dojdzie do podziału przez zero i jeśli język maszynowy + język implementacji + typ danych + odpowiedź systemu operacyjnego na to spowoduje awarię programu, to jest w porządku. Jeśli odpowiedzią jest utworzenie wartości, która może ostatecznie skazić każdą liczbę w programie, to też jest w porządku.Ani „coś drastycznego”, ani „zbyt łagodnego” nie jest właściwą rzeczą w świecie komputerów o wysokiej niezawodności. Te domyślne odpowiedzi mogą zabić pacjenta, rozbić samolot lub spowodować wybuch bomby w niewłaściwym miejscu. W środowisku o wysokiej niezawodności programista, który pisze,
(a+b)/c
zostanie zabity podczas przeglądania kodu, lub w czasach współczesnych, być może automatycznie zabity przez narzędzie sprawdzające konstrukcje verboten. W tym środowisku programista powinien zamiast tego napisać coś w styludiv(add(a,b),c)
(i ewentualnie sprawdzając status błędu). Pod maskądiv
(/ równieżadd
) funkcje / makra chronią przed dzieleniem przez zero (lub przepełnieniem w przypadkuadd
). To, co obejmuje ta ochrona, jest ściśle związane z implementacją.źródło
Wiemy już o tym
x/0
i0/0
nie mamy dobrze zdefiniowanych odpowiedzi. Co się stanie, jeśli0/0
mimo to spróbujesz obliczyć ?W nowoczesnym systemie obliczenia są przekazywane do jednostki MPU w procesorze i są oznaczane jako operacja niedozwolona, zwracana
NaN
.W dużo starszym systemie, takim jak komputery domowe z lat 80., które nie miały podziału na chipy, obliczenia były wykonywane przez dowolne oprogramowanie. Istnieje kilka możliwych opcji:
0
1
log(0)
a oprogramowanie albo użyje procedur obsługi błędów, albo ulegnie awarii0
e 0 = 1, dając wynik1
Innymi słowy, zależałoby od implementacji, co się stanie, i byłoby możliwe napisanie oprogramowania, które daje poprawne i przewidywalne wyniki dla każdej wartości, ale pozornie dziwne wartości,
0/0
które są jednak nadal wewnętrznie spójne.źródło
NaN
w liczbach całkowitych.very inefficient
do podziału. Koszt arytmetyki wynosi (dodawanie = odejmowanie) <= mnożenie <= dzielenie. Jeśli nie masz jednostki MPU, która może wykonywać dzielenie w tej samej liczbie cykli zegara, co dodawanie (zwykle jeden), dzielenie jest droższe niż dodawanie i odejmowanie i zwykle również droższe niż mnożenie.