Чому важливий негативний нуль?


64

Мене бентежить питання, чому ми дбаємо про різні уявлення про позитивний та негативний нуль.

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

Стаття Вікіпедії про цю концепцію не особливо корисна; це лише робить неясні твердження про підписаний нуль, роблячи певні математичні операції простішими у плаваючій точці, якщо я правильно розумію. У цій відповіді перераховано пару функцій, які поводяться по-різному, і, можливо, щось можна зробити з прикладів, якщо ви знайомі з тим, як вони можуть бути використані. (Хоча конкретний приклад складних квадратних коренів виглядає невірно, оскільки два числа математично рівноцінні, якщо я не маю непорозуміння.) Але я не зміг знайти чіткого твердження про те, з якою проблемою ви могли б потрапити, якби її не було. Більше математичних ресурсів мені вдалося відзначити, що між математикою немає різниці між ними, а стаття у Вікіпедії, здається, дозволяє припустити, що це рідко можна побачити поза обчисленням, окрім опису меж.

То чому в обчислювальних цінах є цінним мінус нулем? Я впевнений, що мені просто щось не вистачає.


6
Негативний нуль може сигналізувати про перелив у плаваючій крапці IEEE, але крім цього, його використання виявляється суперечливим та малим. Якби я здогадувався, я б сказав, що негативний нуль представлений у плаваючій точці IEEE, тому що ... ну, ви можете. Для ще цікавішої їзди знайдіть інформацію про сигналізацію плаваючої точки NaN.
Роберт Харві

1
Якщо конкретним прикладом є "1 / 0,0" / "1 / -0,0", 0 - це розріз гілки для 1 / x, і межа залежить від того, якщо ви підходите до нього знизу або зверху.
Ватін

@Vatine Ні, конкретний приклад є, sqrt(-1+0i) = iі sqrt(-1-0i) = -i, хоча я одягнений з належним синтаксисом для деяких мов програмування, я вважаю. Я редагую, щоб бути більш зрозумілим.
jpmc26


Я дуже здивований, що складні числа взагалі не з’являються у відповідях, особливо з огляду на приклад квадратного кореня, який я зазначив.
jpmc26

Відповіді:


69

Потрібно пам’ятати, що в арифметиці FPU 0 не обов’язково означає точно нуль, але також занадто мало значення, щоб бути представленим за допомогою даного типу даних, наприклад

a = -1 / 1000000000000000000.0

a занадто малий, щоб правильно зобразити поплавком (32 біт), тому він "закруглений" до -0.

Скажімо, наше обчислення продовжується:

b = 1 / a

Оскільки a - плаваюче, це призведе до нескінченності, що досить далеко від правильної відповіді -1000000000000000000.0

Тепер давайте обчислимо b, якщо немає -0 (значить, округлюється до +0):

b = 1 / +0
b = +infinity

Результат знову помиляється через округлення, але зараз він "більш неправильний" - не тільки числово, але ще важливіше через різну ознаку (результат обчислення - нескінченність, правильний результат - 1000000000000000000.0).

Ви все ще можете сказати, що це насправді не має значення, оскільки обидва помиляються. Важливим є те, що існує безліч числових додатків, де найважливішим результатом обчислення є знак - наприклад, коли вирішувати, повернути ліворуч чи праворуч на перехресті за допомогою якогось алгоритму машинного навчання, ви можете інтерпретувати позитивне значення => поворот зліва, від'ємне значення => поворот праворуч, фактична "величина" значення - це лише "коефіцієнт довіри".


Чи є у вас ідеї щодо того, чи може знак підтоплення бути особливо важливим у уявних / складних обчисленнях чисел?
jpmc26

@qbd: Чи знаєте ви, що таке числові програми? Я б сказав, що програми, які спрацьовують і використовують +infі -infв нормальній роботі, помиляються.
Бьорн Ліндквіст

@ BjörnLindqvist Якщо ви хочете отримати конкретні програми, які можна завантажити - я не знаю жодного. Я не думаю, що це обов'язково баггі - замість float / double ви можете використовувати щось на кшталт BigDecimal з необмеженою точністю. Але чи варто того, коли програма дасть точно такі ж результати, як і з плаваючим / подвійним, але з набагато гіршими показниками?
qbd

Ви писали "числові додатки, де найважливішим результатом обчислення є знак" Я можу повірити в це, але не можу повірити, що є якісь написані програми, які покладаються на -0 і на значення " +infта" -inf. Якщо ваша програма викликає переповнення плаваючої точки, то помилка, і те, що станеться після цього, не так цікаво, імхо. Нам ще не вистачає практичних прикладів, в яких -0 корисно.
Бьорн Ліндквіст

1
@ BjörnLindqvist Значна частина x265 виконується в зборах, спираючись на її незрозумілі деталі (які залежать від архітектури процесора) мало хто знає про ім’я продуктивності. Це неправильно? Покладаючись на широко впроваджений 30-річний стандарт (який тут залишиться) для однієї простої, добре зрозумілої функції в ім'я виконання, раптом не здається такою поганою.
qbd

8

По-перше, як створити -0? Є два способи: (1) зробити операцію з плаваючою комою, де математичний результат негативний, але настільки близький до нуля, що він округляється до нуля, а не до ненульового числа. Цей розрахунок дасть -0. (b) Окремі операції, що включають нулі: Помножте позитивний нуль на від’ємне число, або розділіть позитивний нуль на від’ємне число, або відмініть позитивний нуль.

Якщо від'ємний нуль трохи спрощує множення і ділення, знак x * y або x / y завжди є знаком x, виключно або знаком y. Без від’ємного нуля доведеться додатково перевірити, щоб замінити -0 на +0.

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

Оптимізація компіляторів ненавидить -0. Наприклад, ви не можете замінити x + 0,0 на x, оскільки результат не повинен бути x, якщо x дорівнює -0,0. Ви не можете замінити х * 0,0 на 0,0, оскільки результат повинен бути -0,0, якщо x <0 або x -0,0.


7
Я хотів би, щоб IEEE-754 включав чотири нулі: "точні", позитивні нескінченно малі, негативні нескінченно малі та неподписані (останнє - різниця між нерозрізненими значеннями). Це призвело б до роботи багатьох аксіом з плаваючою комою - серед них x + 0,0 еквівалент x-0,0 еквівалент x, xy equiv x + (- 1,0) * y і 1,0 / x еквівалент -1,0 / (- 1,0 * x) [якщо x дорівнює нулю, обидва будуть позитивними; якщо neg-zero, обидва neg-inf; якщо точний або непідписаний, обидва NaN].
supercat

Я був в змозі отримати негативний нуль пропускання -5і 5в fmod(). Це дуже дратує моє використання.
Аарон Франке

6

C # Double, що відповідає IEEE 754

    double a = 3.0;
    double b = 0.0;
    double c = -0.0;

    Console.WriteLine(a / b);
    Console.WriteLine(a / c);

відбитки:

Infinity
-Infinity

власне, щоб трохи пояснити ...

Double d = -0.0; 

Це означає щось набагато ближче до d = The Limit of x as x approaches 0-або The Limit of x as x approaches 0 from the negatives.


Щоб вирішити коментар Філіпа ...

В основному від'ємний нуль означає перелив.

Існує дуже мало практичного використання для від'ємного нуля, якщо такий є ...

наприклад, цей код (знову ж таки C #):

double a = -0.0;
double b = 0.0;

Console.WriteLine(a.Equals(b));
Console.WriteLine(a==b);
Console.WriteLine(Math.Sign(a));

дає цей результат:

True
True
0

Неофіційно пояснюючи, що всі спеціальні значення плаваючої точки IEEE 754 можуть мати (позитивна нескінченність, негативна нескінченність, NAN, -0,0) у практичному розумінні не мають значення. Вони не можуть представляти будь-яку фізичну цінність або будь-яку цінність, яка має сенс у розрахунку "реального світу". Що вони означають, в основному це:

  • Позитивна нескінченність означає переповнення на позитивному кінці, яку може представляти плаваюча точка
  • негативна нескінченність означає переповнення на позитивному кінці, яку може представляти плаваюча точка
  • від'ємний нуль означає підтік, і операнди мали протилежні знаки
  • позитивний нуль може означати підтік, і операнди мали однаковий знак
  • NAN означає, що ваш розрахунок незадовільно визначений, наприклад sqrt(-7), або він не має межі, подібної 0/0або подібноїPositiveInfinity/PositiveInfinity

7
Так, але чому це важливо? Чи можете ви надати практичний приклад у реальному світі, коли різниця має значення?
Філіп

5

Питання про те, як це стосується обчислень зі складними числами, дійсно лежить в основі того, чому обидва +0 і -0 існують у плаваючій точці. Якщо ви взагалі вивчаєте комплексний аналіз, ви швидко виявите, що безперервні функції від складних до складних зазвичай не можна трактувати як «однозначні», якщо не прийняти «ввічливу вигадку», що виходи утворюють те, що відомо як «поверхня Рімана». Наприклад, складний логарифм призначає кожному входу нескінченно багато виходів; коли ви 'з'єднуєте їх', щоб утворити безперервний вихід, ви закінчите, щоб усі справжні частини утворювали навколо невідкладеної поверхні "нескінченний штопор". Суцільна крива, яка перетинає реальну вісь "вниз від позитивно-уявної сторони" та іншу криву, яка "обертається навколо полюса" і перетинає реальну вісь "

Тепер застосуйте це до чисельної програми, яка обчислює за допомогою складної плаваючої точки. Дія, вжита після даного розрахунку, може бути дуже різною, залежно від того, на якому "аркуші" програма наразі "включена", і знак останнього обчисленого результату, ймовірно, говорить вам, який "аркуш". Тепер припустимо, що результат був нульовим? Пам'ятайте, тут "нуль" насправді означає "занадто малий, щоб правильно представити". Але якщо розрахунок міг би організувати -збереження знака- (тобто запам’ятати, який 'аркуш'), коли результат дорівнює нулю, тоді код може перевірити знак і виконати правильну дію навіть у цій ситуації.


1

Причина простіша, ніж зазвичай

Звичайно , є багато хаков , які шукають дійсно гарні , і вони корисні (наприклад , округлення до -0.0або , +0.0але припустимо , що ми маємо уявлення підписаного межд з мінусом / плюс знак на початку (я знаю , що вирішується U2 двійкового коду у цілих числах, але припускають менш складне подання подвійного):

0 111 = 7
^ sign

Що робити, якщо є від’ємне число?

1 111 = -7

Гаразд, це просто. Тож давайте представити 0:

0 000 = 0

Це теж добре. А як же 1 000? Чи повинен це бути заборонений номер? Краще ні.

Тож припустимо, що існує два типи нуля:

0 000 = +0
1 000 = -0

Що ж, це спростить наші розрахунки та надасть деяке закріплення додаткових функцій. Тож +0і -0виходять лише з питань бінарного представлення.


6
Якщо я читаю це правильно, ви, по суті, просто говорите, що люди, що визначають або впроваджують стандарти, не хотіли йти на проблему заборонити це. Я не думаю, що це міркування доводить до того, що доповнення 2 використовує подання "негативний нуль" для зовсім іншого числа і не має представлення негативного нуля. Дивіться статтю Вікіпедії, яку я пов’язав.
jpmc26

1
@ Jpmc26 Я думаю , що на насправді деякі правда , що в тому , що ні забороняючи це означає , що не потребують реалізації мати особливий випадок. Як і є, кожне число має біт знаків і його можна заперечувати, перемикаючи біт знака. Навіть NaN підписані, і реалізації можуть (але не вимагати) вибрати відповідний знак при створенні NaN. Якщо від’ємного нуля не існувало, для кожного обчислення, в результаті якого було 0, потрібно було б виконати додаткову роботу, щоб виправити біт знаків тощо
hobbs

4
@ jpmc26 (тобто в кожному іншому множенні двох чисел знак результату є xor знаку множин, а величина - добуток двох величин. У реальному житті це працює для -1 * 0 = - 0. Але якщо нуль із біткою знака перевернув якусь особливу ненульову цінність, кожен продукт, який міг би отримати 0, повинен був би перевірити і переконатися, що він не дає цього особливого значення помилково.)
hobbs
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.