Чи спробує комп’ютер розділити на нуль?


59

Ми всі знаємо, що 0/0це Undefinedі повертає помилку, якби я ставлю її до калькулятора, і якби я створив програму (принаймні на C), ОС би припинила її, коли я намагаюся розділити на нуль.

Але мені цікаво, чи комп’ютер навіть намагається розділити на нуль , чи він просто "вбудований у захист", так що коли він "бачить", 0/0він повертає помилку ще до спроби її обчислити?


10
0/0 не визначено, будь-яке інше число / 0 - це інший вид помилок, ви, здається, плутаєте два
edc65

7
Будь-яке число, поділене на 0, не визначене, математично кажучи.
ManoDestra

12
@jwg: "якби у нього було значення, воно було б 1" - не обов'язково; є цілі гілки математики, присвячені тому, яке значення може бути в різних обставинах :)
psmears

11
Для уточнення термінології тут 0/0 називається невизначеною формою, тоді як x / 0 для ненульового x - невизначеним . Обчислення, що закінчується 0/0, часто можна обчислити по-іншому, щоб дати реальну відповідь, тоді як x / 0 по суті безглуздий.
Ера

9
@jwg тоді вас може зацікавити правило l'hopital. Однозначно є випадки, коли 0/0 не означає значення 1.
d0nut

Відповіді:


74

Процесор вбудований в систему виявлення. Більшість архітектурних наборів інструкцій вказують, що процесор буде потрапляти в обробник винятків для цілого поділу на нуль (я не думаю, що це хвилює, якщо дивіденд дорівнює нулю).

Можливо, що перевірка нульового дільника відбувається паралельно апаратно разом із спробою зробити поділ, однак виявлення порушного стану ефективно скасовує поділ і замість цього пастки, тому ми не можемо точно сказати, чи є якась частина він намагався розділити чи ні.

(Апаратне забезпечення часто працює так, роблячи кілька речей паралельно, а потім вибираючи відповідний результат після цього, тому що тоді кожна операція може розпочатися відразу, а не серіалізуватись на вибір відповідної операції.)

Цей же механізм пастки до винятків також буде використовуватися, коли ввімкнено виявлення переповнення, яке ви вимагаєте, зазвичай, використовуючи різні інструкції add / sub / mul (або прапор цих інструкцій).

Поділ з плаваючою точкою також має вбудоване виявлення для ділення на нуль, але повертає інше значення ( IEEE 754 вказує NaN ) замість того, щоб захоплювати обробник винятків.


Гіпотетично кажучи, якщо ЦП опустив будь-яке виявлення для спроби поділу на нуль, проблеми можуть включати:

  • підвішування центрального процесора (наприклад, в інфляційному циклі) - це може статися, якщо ЦП використовує алгоритм ділення, який зупиняється, коли чисельник менший за дільник (в абсолютній величині). Таке зависання в значній мірі вважатиметься збійним процесором.
  • відповідь на сміття (можливо передбачувану), якщо ЦП використовує лічильник для припинення поділу на максимально можливій кількості діючих кроків (наприклад, 31 або 32 на 32-бітній машині).

51
@Ankush "Збій системи" насправді не те, що відбувається на рівні процесора. Найбільш вірогідною поведінкою центрального процесора, який не вловлює ділення на нуль, буде те, що він просто виконує ділення, створює якийсь дурницький результат і продовжує дію. Як і коли ви додаєте два цілих числа, які трапляються переповненими.
Іксрек

6
Для плаваючої точки вибір між "NaN" та "пасткою", як правило, встановлюється шляхом перегортання прапорів у FPU.
Ватін

10
@Ankush Якщо ви сказали lxrec, було незрозуміло: що стосується процесора, то тут немає такого поняття, як збій.
користувач253751

7
@Ankush Мало ситуацій спричиняють "краху системи" на рівні процесора. У таких випадках ми говоримо про такі речі, як відключення теплового захисту (захист від перегріву), потрійні несправності та подібні ситуації. Майже кожен збій, з яким ви зіткнетесь у звичайному використанні, включаючи недійсні опкоди , обробляється шляхом відловлення та відновлення певним чином або просто ігнорування помилки та продовження виконання в потенційно нечистому стані, можливо встановивши якийсь прапор помилки.
CVn

8
Якби ви не вловили ділення на нуль, результатом програмування було б "Невизначена поведінка". Це означає, що комп'ютер може робити все, що завгодно. Можливо, як зазначає Бергі, увійти в баггі-петлю і повісити. Це може просто вивести певну серію бітів, яка сталася в результаті їхньої логіки поділу (пам'ятайте, комп'ютер не «ділиться» в математичному сенсі. Він робить операцію на два числа, що досить близьке до ділення що ми, як правило, називаємо його просто "поділом". Дивіться також округлення з плаваючою точкою).
Корт Аммон

34

Це залежить від мови, від компілятора, від того, чи використовуєте ви цілі числа чи числа з плаваючою комою тощо.

Для номера з плаваючою комою більшість реалізацій використовують стандарт IEEE 754 , де розділення на 0 добре визначено. 0/0 дає чітко визначений результат NaN (не-число), а x / 0 для x ≠ 0 дає або + Нескінченність, або -Безмежність, залежно від знака x.

У таких мовах, як C, C ++ тощо, поділ на нуль викликає не визначене поведінку. Тож згідно з мовним визначенням може статися все , що завгодно . Особливо речі, які ви не хочете, щоб вони відбувалися. Як і все, що працює прекрасно, коли ви пишете код і знищуєте дані, коли ваш клієнт ним користується. Тож з мовної точки зору не робіть цього . Деякі мови гарантують збій вашої програми; від них залежить, як це реалізується. Для цих мов поділ на нуль буде кращим.

У багатьох процесорах є якась вбудована інструкція "ділити", яка буде вести себе по-різному залежно від процесора. У процесорах Intel 32bit і 64 біт процесори інструкція "розділити" приведе до краху вашої програми, коли ви спробуєте поділити на нуль. Інші процесори можуть поводитись інакше.

Якщо компілятор виявить, що поділ на нуль відбудеться, коли ви виконаєте якийсь код, і компілятор приємний для своїх користувачів, він, ймовірно, подасть вам попередження та сформує вбудовану інструкцію "ділити", щоб поведінка була те саме.


22
"На 32-бітових та 64-бітних процесорах інструкція" розділити "приведе до краху вашої програми, коли ви спробуєте поділити на нуль." Потрібне цитування. Процесори не мають уявлення про програми, вони виконують інструкції і (якщо ми включаємо MMU) застосовують обмеження доступу до пам’яті (якщо не в кільці 0 або еквівалент в архітектурах, які не є Intel-x86). Те, що інструкція є частиною програми A, а не додатка B або компонента операційної системи C, не має значення для ЦП; чи відповідна інструкція може бути Інструкцією X чи використовувати адресу пам'яті Y.
CVn

1
Щоб додати до коментаря @ MichaelKjörling: В ОС є способи заборонити застосування цього (та інших помилок). У світі Windows це EXCEPTION_INT_DIVIDE_BY_ZEROзначення, в EXCEPTION_RECORDякому буде оброблятися (сподіваємось) встановлений Structed Exception Handling Handler
user45891

1
Іноді вони роблять інші речі, крім того, щоб гарантувати, що ваш додаток вийде з ладу. Наприклад, багато мов / платформ гарантують, що вони викинуть виняток при поділі на нуль. Потім ви можете зловити та обробити вказаний виняток без збоїв.
reirab

2
Ви можете видалити "може" в "Інші процесори можуть поводитись інакше": На платформі PowerPC поділ просто дає нульовий результат при поділі на нуль. Що набагато корисніше за панічну поведінку платформи X86.
cmaster

13

Здається, вам цікаво, що буде, якби хтось зробив процесор, який явно не перевіряє нуль перед поділом. Що трапиться, повністю залежить від здійснення підрозділу. Не вдаючись у деталі, один вид реалізації дасть результат, у якому встановлені всі біти, наприклад 65535 на 16-бітному процесорі. Інша може повісити трубку.


1

Але мені цікаво, чи комп’ютер навіть намагається розділити на нуль, чи просто "вбудований захист", і коли він "бачить" 0/0, він повертає помилку ще до спроби її обчислити?

Оскільки x/0немає сенсу, період, комп'ютери повинні завжди перевіряти на поділ на нуль. Тут є проблема: програмісти хочуть проводити обчислення (a+b)/cбез необхідності перевіряти, чи має такий розрахунок навіть сенс. Відповідь під капотом на поділ на нуль процесором + тип типу + операційна система + мова - це або зробити щось досить драстичне (наприклад, збій програми), або зробити щось надмірно доброякісне (наприклад, створити значення, яке не робить такий сенс, як IEEE з плаваючою точкою NaN, число, яке є "Не числом").

У звичайній обстановці від програміста очікується знати, чи (a+b)/cє сенс. У цьому контексті немає підстав перевіряти ділення на нуль. Якщо поділ на нуль трапляється, і якщо машинна мова + мова реалізації + тип даних + відповідь операційної системи на це - зробити програму збоєм, це добре. Якщо відповідь полягає у створенні значення, яке може врешті забруднити кожне число програми, це теж нормально.

Ні "щось драстичне", ні "надмірно доброякісне" не є правильним ділом у світі з обчисленнями з високою надійністю. Ці відповіді за замовчуванням можуть вбити пацієнта, розбити авіалайнер або змусити вибухнути бомбу в неправильному місці. У середовищі з високою надійністю програміст, який пише, (a+b)/cбуде підбитий до смерті під час перегляду коду, або в сучасний час, можливо, автоматично підбирається до смерті інструментом, який перевіряє конструктивність верболетів. У цьому середовищі цей програміст повинен замість цього щось написати div(add(a,b),c)(та, можливо, перевірити стан помилок). Під кришкою div(/ а також add) функції / макроси захищають від поділу на нуль (або переповнення у випадку add). Те, що передбачає цей захист, є специфічним для здійснення.


Це тому, що NaN не підкоряється арифметиці, яку ви вивчили в школі, не означає, що це не має сенсу. Він підпорядковується різній арифметиці
Калет

-2

На сьогодні ми знаємо це x/0і 0/0не маємо чітко визначених відповідей. Що станеться, якщо ви 0/0все одно спробуєте розрахувати ?

У сучасній системі обчислення передаються до MPU в межах CPU і позначаються як незаконна операція, повертаючись NaN.

У значно старшій системі, наприклад домашніх комп’ютерах 80-х років, які не мали мікросхеми, розрахунок проводився будь-яким програмним забезпеченням. Є кілька можливих варіантів:

  • Віднімайте все менші та менші копії дільника, поки значення не досягне нуля, і відслідковуйте, які розміри копій були відняті
    • Якщо він перевірить нуль до першого віднімання, він швидко вийде, і результат буде 0
    • Якщо він припускає, що він повинен бути здатний відняти хоча б один раз, результат буде 1
  • Обчисліть логарифми обох чисел, віднімайте їх і піднімайте е до сили результату. Дуже неефективний метод порівняно з вищевказаним методом віднімання, але математично достовірний
    • При спробі обчислити може виникнути переповнення, log(0)і програмне забезпечення буде використовувати підходи під керуванням помилок, або виходить з ладу
    • Програмне забезпечення може припустити, що всі логарифми можна обчислити за фіксованою кількістю кроків і повернути велике, але неправильне значення. Оскільки обидва логарифми були б однаковими, різниця була б 0і e 0 = 1, даючи результат1

Іншими словами, від того, що відбудеться, залежатиме від реалізації, і можна було б написати програмне забезпечення, яке дасть правильні та передбачувані результати для кожного значення, але, здається, дивні значення для 0/0цього все-таки все ще є послідовними.


3
Це питання стосується ділення нуля на цілі числа, і немає такого поняття, як NaNу цілих числах.
Девід Хаммен

3
Жоден процесор не збирається обчислювати журнали та віднімати обчислення результату ділення. Терміни навчання логарифмів на кілька порядків перевищують поділ. Яке значення журналу (0)?
wallyk

1
@DavidHammen В ОП жодного разу не згадували цілі числа, і ніхто не коментував це питання. Цілі особи згадуються лише у відповідях.
CJ Dennis

@wallyk Я вже сказав у своїй відповіді, що логарифми - це very inefficientрозділення. Вартість на арифметику становить (додавання = віднімання) <= множення <= ділення. Якщо у вас немає MPU, який би міг виконувати поділ за тією ж кількістю тактових циклів, що і додавання (зазвичай один), то поділ дорожче додавання і віднімання і, як правило, дорожче, ніж множення.
CJ Dennis
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.