Чому 0 помилково?


115

Це питання може здатися німим, але чому для більшості мов програмування 0оцінюється значення falseта яке інше [ціле число] true?

Порівняння рядків

Оскільки питання видається занадто простим, я поясню себе трохи більше: по-перше, це може здатися очевидним для будь-якого програміста, але чому б не було мови програмування - насправді вона може бути, але не будь-яка Я використав - де 0оцінюється trueта всі інші [цілі числа] значення false? Це одне зауваження може здатися випадковим, але у мене є кілька прикладів, де це, можливо, було гарною ідеєю. Перш за все, візьмемо для прикладу тристороннє порівняння рядків, я візьму для strcmpприкладу C : будь-який програміст, який намагається C як його першою мовою, може спокуситись написати наступний код:

if (strcmp(str1, str2)) { // Do something... }

Оскільки strcmpповернення, 0які оцінюються, falseколи рядки рівні, те, що починаючий програміст намагався зробити, виходить з ладу і він взагалі не розуміє, чому спочатку. Якби натомість 0оцінили true, цю функцію можна було б використати у найпростішому вираженні - тому, що було вище - при порівнянні рівності, а належні перевірки -1та 1були б виконані лише за потреби. Ми вважали б тип повернення boolбільшою частиною часу (на нашу думку, я маю на увазі).

Крім того, давайте введемо новий тип sign, який просто приймає значення -1, 0і 1. Це може бути дуже зручно. Уявіть, що в C ++ є оператор космічного корабля, і ми цього хочемо std::string(ну, compareфункція вже є , але оператор космічного корабля - це веселіше). Наразі декларація буде такою:

sign operator<=>(const std::string& lhs, const std::string& rhs);

Як 0би оцінювали true, оператор космічного корабля навіть не існував, і ми могли заявити про operator==таке:

sign operator==(const std::string& lhs, const std::string& rhs);

Це operator==обробляло б тристоронне порівняння одразу, і все-таки його можна було б використовувати для виконання наступної перевірки, в той час як ще можна перевірити, яка рядок лексикографічно перевершує іншу, коли це потрібно:

if (str1 == str2) { // Do something... }

Старі помилки в обробці

Зараз у нас є винятки, тому ця частина стосується лише старих мов, де подібного немає (наприклад, C). Якщо ми подивимось на стандартну бібліотеку C (і POSIX - теж), то зможемо переконатися, що функції maaaaany повертаються 0при успішному, а будь-яке ціле число в іншому випадку. Я з сумом бачив, як деякі люди роблять такі речі:

#define TRUE 0
// ...
if (some_function() == TRUE)
{
    // Here, TRUE would mean success...
    // Do something
}

Якщо ми думаємо про те, як ми думаємо в програмуванні, ми часто маємо таку схему міркувань:

Do something
Did it work?
Yes ->
    That's ok, one case to handle
No ->
    Why? Many cases to handle

Якщо ми ще раз подумаємо про це, було б доцільно поставити єдине нейтральне значення, 0на yes(і саме так функціонують функції C), тоді як усі інші значення можуть бути там, щоб вирішити багато випадків no. Тим НЕ менше, у всіх мовах програмування я знаю ( за винятком , можливо , деякі експериментальні esotheric мови), що має yesзначення falseв ifстані, в той час як всі noвипадки обчислюватися true. Існує багато ситуацій, коли "працює" представляє один випадок, а "не працює" - це багато ймовірних причин. Якщо ми будемо думати про це таким чином, 0оцінюючи trueта інше, falseбуло б набагато більше сенсу.

Висновок

Мій висновок, по суті, є моїм оригінальним запитанням: чому ми створили мови, де 0є, falseта інші значення true, беручи до уваги мої декілька прикладів вище та, можливо, ще кілька, про які я не думав?

Подальші дії: Приємно бачити, що існує багато відповідей з багатьма ідеями та якомога більше причин, щоб воно було таким. Мені подобається, наскільки ви пристрасно ставитеся до цього. Я оригінально задав це питання від нудьги, але оскільки ви здаєтеся таким пристрасним, я вирішив піти трохи далі і запитати про обґрунтування вибору булевого вибору 0 і 1 на Math.SE :)


32
strcmp()не є хорошим прикладом для істинного чи хибного, оскільки він повертає 3 різних значення. І ви здивуєтеся, коли почнете використовувати оболонку, де 0 означає істину, а все інше означає помилкове.
ott--

52
@ ott--: в оболонках Unix 0 означає успіх, а не нуль означає збій - не зовсім те саме, що "вірно" і "помилково".
Кіт Томпсон

14
@KeithThompson: У Bash (та інших оболонках) "успіх" і "провал" насправді збігаються з "справжніми" і "помилковими". Розглянемо, наприклад, оператор if true ; then ... ; fi, де trueкоманда, яка повертає нуль, і ця команда ifвиконує ....
ruakh

13
У апаратних засобах немає булевих, а лише двійкові числа, а в більшості історичних ISA ненульове число вважається "справжнім" у всіх інструкціях з умовного розгалуження (якщо вони замість них не використовують прапори). Отже, мови низького рівня зобов'язані слідувати основним властивостям обладнання.
SK-логіка

2
@MasonWheeler Наявність булевого типу нічого не означає. Наприклад пітон дійсно має boolтипу , але порівняння / , якщо умови і т.д. можуть мати будь-який повертається значення.
Бакуріу

Відповіді:


98

0це falseтому, що вони обоє нульових елементів у загальних півколах . Незважаючи на те, що вони є різними типами даних, має інтуїтивний сенс конвертувати між ними, оскільки вони належать до ізоморфних алгебраїчних структур.

  • 0- тотожність для додавання і нуль для множення. Це справедливо для цілих чисел і раціоналів, але не числа IEEE-754 з плаваючою комою: 0.0 * NaN = NaNі 0.0 * Infinity = NaN.

  • falseє тотожністю для булевого xor (⊻) і нульовим для Boolean і (∧). Якщо булеві символи представлені як {0, 1} - набір цілих чисел за модулем 2 - ви можете вважати ⊻ як додавання без перенесення, а ∧ як множення.

  • ""і []є ідентичністю для конкатенації, але є кілька операцій, для яких вони мають сенс як нуль. Повторення - це одне, але повторення та конкатенація не поширюються, тому ці операції не утворюють семірування.

Такі неявні перетворення корисні для малих програм, але у великих можуть зробити програми складнішими. Лише одна з багатьох компромісів у мовному дизайні.


1
Приємно, що ви згадали списки. (BTW - nilце і порожній список, []і falseзначення у Common Lisp; чи є тенденція до об'єднання ідентифікацій з різними типами даних?) Ви все ще повинні пояснити, чому природно вважати помилковим як ідентифікацію добавки, а true як мультиплікативну ідентичність а не навпаки. Неможливо вважати trueідентифікатором для ANDі нулем для OR?
Джорджіо

3
+1 для посилання на подібні особи. Нарешті, відповідь, яка не просто зводиться до "конвенції, вирішуй".
l0b0

5
+1 за надання деталей конкретної та дуже старої математики, в якій цього дотримувались і давно має сенс
Джиммі Хоффа

1
Ця відповідь не має сенсу. trueтакож тотожність і нуль піврічок (булева та / або). Немає жодної причини, згідно з умовами звітності, falseближче до 0, ніж true.
TonioElGringo

1
@TonioElGringo: Різниця між true та false - це різниця між XOR та XNOR. Можна формувати ізоморфні кільця, використовуючи AND / XOR, де істинним є мультиплікативна ідентичність, а помилкова добавка, або з OR і XNOR, де false - мультиплікативна ідентичність, а true - добавка, але XNOR зазвичай не вважається загальним фундаментальна операція, як XOR.
суперкат

74

Тому що математика працює.

FALSE OR TRUE is TRUE, because 0 | 1 is 1.

... insert many other examples here.

Традиційно програми C мають такі умови

if (someFunctionReturningANumber())

а не

if (someFunctionReturningANumber() != 0)

тому що поняття нуля, еквівалентне хибному, добре зрозуміло.


21
Мови створені так, тому що математика має сенс. Це прийшло першим.
Роберт Харві

26
@Morwenn, це сягає 19 століття і Джорджа Була. Люди представляли False як 0 та True як! 0 довше, ніж там були комп’ютери.
Чарльз Е. Грант

11
Я не бачу, чому математика не працює іншим способом, якщо ви просто змінюєте всі визначення, щоб AND було +, АБО є *.
Ніл Г

7
Саме так: математика працює обома способами, і відповідь на це питання, здається, суто умовна.
Ніл Г

6
@Robert Було б чудово, якби ви могли прописати "математичні основи" у своєму дописі.
phant0m

38

Як говорили інші, математика вийшла першою. Ось чому 0 є falseі 1 є true.

Про яку математику ми говоримо? Булеві алгебри, що датуються серединою 1800-х років, задовго до появи цифрових комп'ютерів.

Можна також сказати, що конвенція вийшла із логіки пропозицій , яка навіть старша булевих алгебр. Це формалізація безлічі логічних результатів, які програмісти знають і люблять ( false || xдорівнює x, true && xдорівнює xтощо).

В основному ми говоримо про арифметику на множині з двома елементами. Подумайте про підрахунок у двійковій формі. Булеві алгебри є джерелом цієї концепції та її теоретичною основою. Конвенції таких мов, як C, є просто прямим додатком.


2
Ви могли б точно. Але дотримання цього "стандартного" способу добре відповідає загальній арифметиці (0 + 1 = 1, а не 0 + 1 = 0).
joshin4colours

2
Так, але, мабуть, ви пишете І з + і АБО з *, якщо ви також переймените визначення.
Ніл Г

3
Математика прийшла не першою. Математика визнала, що 0 і 1 утворюють поле, в якому AND є як множення, а OR - як додавання.
Каз

1
@Kaz: Але {0, 1} з OR і AND не утворює поля.
Джорджіо

2
Мене трохи турбує, що про це говорять більше відповідей та коментарів true = 1. Це не зовсім точно, тому true != 0що це не зовсім те саме. Одна з причин (не єдина), чому слід уникати подібних порівнянь if(something == true) { ... }.
JensG

26

Я думав, що це стосується "спадкування" від електроніки, а також булевої алгебри, де

  • 0= off, negative, no,false
  • 1= on, positive, yes,true

strcmp повертає 0, коли рядки рівні, це пов'язано з його реалізацією, оскільки те, що він насправді робить, - це обчислити "відстань" між двома рядками. Те, що 0 також вважається помилковим, - просто збіг.

повернення 0 на успіх має сенс, оскільки 0 у цьому випадку означає, що немає помилки, а будь-яке інше число буде кодом помилки. Використовувати будь-яке інше число для успіху було б менше сенсу, оскільки у вас є лише один код успіху, тоді як у вас може бути кілька кодів помилок. Ви використовуєте "Це спрацювало?" як вираз висловлення if і сказати 0 = так, було б більше сенсу, але вираз правильніше "Чи щось пішло не так?" і тоді ви бачите, що 0 = ні має великого сенсу. Думати про false/trueце насправді не має сенсу, як це насправді no error code/error code.


Ха-ха, ти перший, хто чітко заявляє питання про помилку повернення. Я вже знав, що інтерпретував це по-своєму, і це міг, попросивши інший шлях, але ти перший, хто це чітко висловив (з багатьох відповідей та коментарів). Насправді я б не сказав, що той чи інший спосіб не має сенсу, але більше того, що обидва мають сенс по-різному :)
Morwenn

1
На самом деле я б сказав , що 0для success/no errorцього єдиним , що має сенс , коли інші цілі числа представляють собою коди помилок. Це 0також трапляється для репрезентації falseв інших випадках насправді не має значення, оскільки ми тут зовсім не говоримо про істинне чи неправдиве;)
Свиш

У мене була та сама ідея, тому я піднявся
user60812

1
Ваша думка щодо strcmp()обчислення відстані є досить хорошою. Якби було названо strdiff()те if (!strdiff())було б дуже логічно.
Кевін Кокс

"електроніка [...] де 0 = [...] неправда, 1 = [...] правда" - навіть в електроніці це лише умова , і не єдина. Ми називаємо цю позитивну логіку, але ви також можете використовувати негативну логіку, де позитивна напруга вказує на помилкове, а негативне - на істинне. Тоді схема, яку ви використовуєте для І, стає АБО, АБО стає І, і так далі. Завдяки закону Де Моргана, все закінчується рівнозначним. Іноді ви знайдете частину електронної схеми, реалізованої в негативній логіці для зручності, і тоді назви сигналів у цій частині відзначаються смужкою над ними.
Jules

18

Як пояснено в цій статті , значення falseі trueне слід плутати з цілими числами 0 і 1, але їх можна ототожнювати з елементами поля Галуа (кінцеве поле) двох елементів (див. Тут ).

Поле - це набір з двома операціями, які задовольняють певні аксіоми.

Символи 0 і 1 умовно використовуються для позначення адитивної та мультиплікативної тотожностей поля, оскільки дійсні числа також є полем (але не кінцевим), ідентичністю яких є числа 0 і 1.

Ідентифікація добавки - це елемент 0 поля, такий, що для всіх x:

x + 0 = 0 + x = x

а мультиплікативна ідентичність - це елемент 1 поля, такий, що для всіх x:

x * 1 = 1 * x = x

Кінцеве поле двох елементів має лише ці два елементи, а саме адитивну тотожність 0 (або false) та мультиплікативну тотожність 1 (або true). Дві операції цього поля - логічний XOR (+) та логічний AND (*).

Примітка. Якщо ви перевернете операції (XOR - це множення, а AND - додавання), то множення не є розподільним на додавання, і у вас більше немає поля. У такому випадку у вас немає підстав називати два елементи 0 і 1 (у будь-якому порядку). Зауважте також, що ви не можете вибрати операцію АБО замість XOR: незалежно від того, як ви інтерпретуєте OR / AND як додавання / множення, результуюча структура не є полем (не всі обернені елементи існують, як того вимагають аксіоми поля).

Щодо функцій C:

  • Багато функцій повертають ціле число, яке є кодом помилки. 0 означає відсутність помилки.
  • Інтуїтивно, функція strcmpобчислює різницю між двома рядками. 0 означає, що немає різниці між двома рядками, тобто два рядки рівні.

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


1
+1 - показує, що якщо їх довільно поміняти, математика більше не виходить.
Джиммі Хоффа

2
Перевернуте: Давши поле з двома елементами та операціями * і +, ми ідентифікуємо True з 0, а False - з 1. Ми ототожнюємо АБО з *, а XOR з +.
Ніл Г

1
Ви побачите, що обидва ці ідентифікації проводяться в одному полі і обидва відповідають правилам булевої логіки. Ваша примітка, на жаль, неправильна :)
Neil G

1
Якщо припустити, що True = 0, а XOR +, то True має бути тотожністю для XOR. Але це не тому, що True XOR True = False. Якщо ви не визначите операцію XOR на True так, що True XOR True = True. Тоді, звичайно, ваша конструкція працює, тому що ви щойно перейменували речі (у будь-якій математичній структурі ви завжди можете успішно зробити перестановку імені та отримати ізоморфну ​​структуру). З іншого боку, якщо дозволити True, False та XOR мати своє звичне значення, то True XOR True = False та True не можуть бути ідентичністю добавки, тобто True не може бути 0.
Giorgio

1
@Giorgio: Я виправив свою конструкцію на ваш коментар у своєму останньому коментарі…
Ніл G

13

Вам слід врахувати, що альтернативні системи також можуть бути прийнятними проектними рішеннями.

Оболонки: 0 статус виходу є істинним, не нульовий - хибним

Приклад снарядів, що вважають справжнім статус виходу 0, вже згадувався.

$ ( exit 0 ) && echo "0 is true" || echo "0 is false"
0 is true
$ ( exit 1 ) && echo "1 is true" || echo "1 is false"
1 is false

Обґрунтування цього полягає в тому, що є один спосіб досягти успіху, але існує багато способів невдачі, тому використання 0 як спеціального значення, що означає "без помилок", є прагматичним.

Ruby: 0 - це як і будь-яке інше число

Серед "звичайних" мов програмування є деякі люди, що переживають, наприклад, Ruby, які трактують 0 як справжнє значення.

$ irb
irb(main):001:0> 0 ? '0 is true' : '0 is false'
=> "0 is true"

Обгрунтуванням є те , що тільки falseі nilмає бути хибним. Для багатьох початківців Рубі це гатча. Однак в деяких випадках приємно, що 0 трактується так само, як і будь-яке інше число.

irb(main):002:0> (pos = 'axe' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "Found x at position 1"
irb(main):003:0> (pos = 'xyz' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "Found x at position 0"
irb(main):004:0> (pos = 'abc' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "x not found"

Однак така система працює лише мовою, яка здатна відрізняти булеві як окремий тип від чисел. У попередні часи обчислень програмісти, які працювали з мовою складання або сирою машиною, не мали такої розкоші. Ймовірно, просто природно трактувати 0 як "порожній" стан і встановити біт на 1 як прапор, коли код виявив, що щось сталося. Згідно з розширенням, конвенція виробила, що нуль трактується як хибне, а ненульові значення трактуються як істинні. Однак це не повинно бути таким.

Java: Числа взагалі не можна вважати булевими

В Java, trueі falseє єдиними булеві значення. Числа не булеві, і навіть не можуть бути передані в булеві ( специфікація мови Java, розділ 4.2.2 ):

Між інтегральними типами та типом не існує жодних ролей boolean.

Це правило взагалі уникає питання - усі булеві вирази повинні бути чітко записані в коді.


1
Ребол і Червоний обидва трактують 0-цільний ІНТЕГЕР! цінності як істинні та мають окремий НІТО! тип (із лише одним значенням, NONE), крім LOGIC! трактується як умовна помилка! помилковий. Я виявив значні розчарування у спробі написати код JavaScript, який трактує 0 як хибний; це неймовірно незграбне рішення для динамічно набраної мови. Якщо ви хочете перевірити щось, що може бути нульовим, або 0, ви закінчите писати if (thing === 0), це просто не круто.
HostileFork

@HostileFork я не знаю. Я вважаю, що є сенс, що 0це true(як і будь-яке інше ціле число) в динамічній мові. Мені іноді траплялося ловити, 0коли я намагався спіймати NonePython, і це іноді може бути досить важко помітити.
Морвен

2
Рубі - не чужа людина. Рубі бере це від Ліспа (Рубі навіть таємно називається "MatzLisp"). Лісп - основна мова інформатики. Нуль також тільки справжнє значення в оболонці POSIX, тому що це частина тексту: if [ 0 ] ; then echo this executes ; fi. Значення помилкових даних - це порожня рядок, а перевіряемая неправдивість - невдалий стан завершення команди, яка представлена не- нульовим рівнем.
Каз

8

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

Строкові порівняння

Те саме стосується багатьох видів порівнянь. Такі порівняння обчислюють відстань між двома об'єктами. Коли об'єкти рівні, відстань мінімальна. Тому , коли «порівняння успішно», то значення дорівнює 0. Але на самому справі, яке значення strcmpє НЕ логічним значенням, яку, і то , що пастки які не знають програмісти роблять if (strcmp(...)) do_when_equal() else do_when_not_equal().

У C ++ ми могли б переробити дизайн, strcmpщоб повернути Distanceоб'єкт, який переосмислює operator bool()повернення істини, коли 0 (але потім вас би покусав інший набір проблем). Або в простому C просто є streqфункція, яка повертає 1, коли рядки рівні, а 0 в іншому випадку.

API-дзвінки / код виходу з програми

Тут ви дбаєте про причину того, що щось пішло не так, оскільки це призведе до помилок. Коли все вдається, ви не хочете нічого особливо знати - ваш намір реалізується. Тому повернене значення повинно передавати цю інформацію. Це не булева, це код помилки. Спеціальне значення помилки 0 означає "немає помилки". Решта діапазону являють собою локально значущі помилки, з якими вам доведеться зіткнутися (включаючи 1, що часто означає "невказану помилку").

Загальний випадок

Це залишає перед нами питання: чому булеві значення Trueі Falseзазвичай представлені відповідно 1 і 0?

Ну, окрім суб'єктивного аргументу "так почувається краще", ось кілька причин (суб'єктивних), про які я можу подумати:

  • аналогія електричного кола. Струм увімкнено протягом 1 с, а вимкнено - для 0 с. Мені подобається, що разом (1, так, істинно, увімкнено) разом, і (0, ні, помилково, вимкнено), а не інша суміш

  • ініціалізації пам'яті. Коли я memset(0)купую змінних (будь то int, floats, bools), я хочу, щоб їх значення відповідало найбільш консервативним припущенням. Наприклад, моя сума є початковою 0, присудок - Неправдивий тощо.

Можливо, всі ці причини пов'язані з моєю освітою - якби мене з самого початку вчили асоціювати 0 з True, я б пішов навпаки.


2
Насправді існує принаймні одна мова програмування, яка вважає 0 істинним. Оболонка Unix.
Ян Худек

+1 для вирішення реальної проблеми: Більшість питань Морвенна зовсім не стосується bool.
dan04

@ dan04 Це так. У всьому дописі йдеться про обґрунтування вибору акторів intдля boolбагатьох мов програмування. Порівняння та помилки, що містять помилки, - це лише приклади місць, де їх викладають іншим способом, ніж той, який зараз робиться, матиме сенс.
Морвен

6

З точки зору високого рівня, ви говорите про три досить різні типи даних:

  1. Булевий. Математична умова булевої алгебри полягає у використанні 0 для falseта 1 для true, тому є сенс дотримуватися цієї конвенції. Я думаю, що цей спосіб також має більше сенсу інтуїтивно.

  2. Результат порівняння. Це має три значення: <, =і >(зауважте , що жоден з них не є true). Для них є сенс використовувати значення -1, 0 і 1 відповідно (або, загалом, негативне значення, нуль і додатне значення).

    Якщо ви хочете перевірити рівність і у вас є лише функція, яка виконує загальне порівняння, я думаю, ви повинні зробити це явним, використовуючи щось подібне strcmp(str1, str2) == 0. Я вважаю, що використання !в цій ситуації заплутане, тому що воно трактує не булеве значення, як ніби булеве.

    Також майте на увазі, що порівняння та рівність не повинні бути одне і те ж. Наприклад, якщо ви замовляєте людей за їх датою народження, Compare(me, myTwin)повинні повернутися 0, але Equals(me, myTwin)повинні повернутися false.

  3. Успіх чи зрив функції, можливо, також із деталями про цей успіх чи провал. Якщо ви говорите про Windows, то цей тип викликається, HRESULTа ненульове значення не обов'язково вказує на збій. Насправді негативне значення вказує на невдачу та неотрицальний успіх. Значення успіху дуже часто S_OK = 0, але воно може бути, наприклад S_FALSE = 1, або іншими значеннями.

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

Також розглянемо інший тип, який часто використовується в умові в C: покажчик. Там природно трактувати NULL-показник (який представлений як 0) як false. Тому виконання вашої пропозиції також ускладнить роботу з покажчиками. (Хоча особисто я вважаю за краще явно порівнювати покажчики NULL, а не трактувати їх як булеві.)


4

Нуль може бути помилковим, оскільки більшість процесорів мають прапор ZERO, який можна використовувати для розгалуження. Це економить операцію порівняння.

Давайте розберемося, чому.

Деякий psuedocode, оскільки аудиторія, ймовірно, не читає складання

c- джерело простого циклу дзвінки віє 10 разів

for (int foo =10; foo>0; foo-- ) /* down count loop is shorter */
{  
   wibble();
}

деякі прикидаються збіркою для цього

0x1000 ld a 0x0a      'foo=10
0x1002 call 0x1234    'call wibble()
0x1005 dec a          'foo--
0x1006 jrnz -0x06      'jump back to 0x1000 if not zero
0x1008  

c- джерело ще одного простого циклу дзвінки віє 10 разів

for (int foo =0; foo<10; foo-- ) /* up count loop is longer  */
{  
   wibble();
}

деякі прикидаються збіркою для цієї справи

0x1000 ld a 0x00      'foo=0
0x1002 call 0x1234    'call wibble()
0x1005 dec a          'foo--
0x1006 cmp 0x0a       'compare foo to 10 ( like a subtract but we throw the result away)
0x1008 jrns -0x08      'jump back to 0x1000 if compare was negative
0x100a  

ще кілька джерел c

int foo=10;
if ( foo ) wibble()

і складання

0x1000 ld a 0x10
0x1002 jz 0x3
0x1004 call 0x1234
0x1007  

бачите, як це коротко?

ще кілька джерел c

int foo=10;
if ( foo==0 ) wibble()

і збірка (давайте припустимо гранично розумний компілятор, який може замінити == 0 без порівняння)

0x1000 ld a 0x10
0x1002 jz 0x3
0x1004 call 0x1234
0x1007  

Тепер давайте спробуємо конвенцію true = 1

ще деяке джерело c #define TRUE 1 int foo = TRUE; if (foo == TRUE) wibble ()

і складання

0x1000 ld a 0x1
0x1002 cmp a 0x01
0x1004 jz 0x3
0x1006 call 0x1234
0x1009 

подивіться, наскільки короткий випадок із ненульовою правдою?

Дійсно на ранніх процесорах були невеликі набори прапорів, прикріплених до акумулятора.

Щоб перевірити, чи a> b або a = b, як правило, має інструкцію порівняння.

  • Якщо B не є або ZERO - у цьому випадку прапор ZERO встановлений Реалізовано як простий логічний NOR або всі біти в Акумуляторі.
  • Або НЕГАТИВНО, в якому просто використовуйте "біт знака", тобто найбільш значущий біт Акумулятора, якщо ви використовуєте арифметику комплементу двох. (Здебільшого ми це робимо)

Давайте перезавантажимо це. У деяких старих процесорах вам не довелося використовувати інструкцію порівняння для акумулятора, рівного ZERO, або акумулятора менше нуля.

Тепер ви бачите, чому нуль може бути помилковим?

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


2
Ваша думка тут недостатньо чітка, оскільки для однієї речі if (foo)і if (foo != 0)повинен генеруватися той самий код, по-друге, ви показуєте, що використовувана мова складання насправді має явні булеві операнди та тести для них. Наприклад, jzозначає jump if zero. Іншими словами if (a == 0) goto target;. А кількість навіть не перевіряється безпосередньо; умова перетворюється на його буловий прапор, який зберігається у спеціальному машинному слові. Це насправді більше схожеcpu.flags.zero = (a == 0); if (cpu.flags.zero) goto target;
Каз

Ніякий Kaz, старший процесор не працював так. Jz / jnz можна виконати, не виконуючи інструкцій порівняння. Що було справді точкою мого цілого посту насправді.
Тім Вілліскрофт

2
Я нічого не писав про інструкцію зі порівняння.
Каз

Чи можете ви навести процесор, який має jzінструкцію, але ні jnz? (або будь-який інший асиметричний набір умовних вказівок)
Toby Speight

3

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

Дано поле з двома елементами, ми маємо дві операції: додавання та множення. Ми можемо відобразити булеві операції на цьому полі двома способами:

Традиційно ми ототожнюємо True з 1 і False з 0. Ми ототожнюємо AND з * і XOR з +. Таким чином, АБО є насичуючим доповненням.

Однак ми можемо так само легко ідентифікувати True з 0 і False з 1. Тоді ми ототожнюємо АБО з *, а XNOR з +. Таким чином, І є насичуючим доповненням.


4
Якби ви перейшли за посиланням на wikipedia, ви могли б виявити, що поняття булевої алгебри закрито, пов'язане з поняттям поля Галуа з двох елементів ( en.wikipedia.org/wiki/GF%282%29 ). Символи 0 і 1 умовно використовуються для позначення адитивної та мультиплікативної тотожностей відповідно, оскільки дійсні числа також є полем, ідентичності яких є числа 0 і 1.
Джорджо

1
@NeilG Я думаю, що Джорджо намагається сказати, що це більше, ніж просто конвенція. 0 і 1 булевої алгебри в основному такі ж, як 0 і 1 у GF (2), які відносно додавання та множення ведуть себе майже так само, як 0 і 1.
svick

1
@svick: Ні, тому що ви можете просто перейменувати додавання множення та насичення на АБО та І, а потім перевернути мітки так, щоб 0 було істинним, а 1 - помилковим. Джорджіо каже, що це була конвенція булевої логіки, яка була прийнята як конвенція інформатики.
Ніл Г

1
@Neil G: Ні, ви не можете перевернути + і * і 0 і 1, оскільки поле вимагає розподілу множення на додавання (див. En.wikipedia.org/wiki/Field_%28mathematics%29 ), але якщо встановити +: = AND і *: = XOR, ви отримуєте T XOR (T AND F) = T XOR F = T, тоді як (T XOR T) І (T XOR F) = F І T = F. Тому, перегортаючи операції та тотожність, яку ви більше не матимуть поля. Таким чином, IMO, що визначає 0 та 1 як ідентичність відповідного поля, схоже, фіксує помилкове та справжнє досить вірно.
Джорджіо

1
@giorgio: Я відредагував відповідь, щоб зрозуміти, що відбувається.
Ніл Г

3

Як не дивно, нуль не завжди є хибним.

Зокрема, умова Unix і Posix визначається EXIT_SUCCESSяк 0 (і EXIT_FAILUREяк 1). Насправді це навіть стандартна конвенція C !

Отже, для оболонок Posix та виходу (2) системних дзвінків 0 означає «успішний», що інтуїтивно більше правдиво, ніж помилково.

Зокрема, оболонка ifхоче, щоб процес повернення EXIT_SUCCESS(тобто 0) слідував за її гілкою "тоді"!

У Схемі (але не в Common Lisp або MELT ) 0 і nil (тобто ()в Scheme) є істинними, оскільки єдиним хибним значенням є#f

Я погоджуюсь, я ниппелю!


3

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

Ви можете писати такі речі, як:

if (modemctrl & MCTRL_CD) {
   /* carrier detect is on */
}

а не

if ((modemctrl & MCTRL_CD) != 0) {
    /* carrier detect is on */
}

В одному ізольованому прикладі це не так вже й погано, але робити це стане неприємним.

Так само і зворотні операції. Корисно для результату булевої операції, як порівняння, просто створити 0 або 1: Припустимо, ми хочемо встановити третій біт якогось слова на основі того, чи modemctrlмає біт виявлення носія:

flags |= ((modemctrl & MCTRL_CD) != 0) << 2;

Тут ми повинні мати != 0, щоб зменшити результат довільного &вираження до 0або 1, але оскільки результат є лише цілим числом, нам не доводиться додавати деякий дратівливий склад для подальшого перетворення булевого в ціле число.

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

Ще один приклад, де C гладкий: тестування двох булевих умов як чотиристоронній комутатор:

switch (foo << 1 | bar) {  /* foo and bar booleans are 0 or 1 */
case 0: /* !foo && !bar */
   break;
case 1: /* !foo && bar */
   break;
case 2: /* foo && !bar */
   break;
case 3: /* foo && bar */
   break;
}

Ви не могли відібрати це від програміста С без бою!

Нарешті, C іноді виступає як своєрідна мова складання високого рівня. У мовах складання у нас також немає булевих типів. Булеве значення - це лише біт або нуль проти ненульового значення в пам'яті або регістрі. Цілий нуль, булевий нуль і нульовий адрес усі перевіряються однаково в наборах інструкцій з мовної збірки (і, можливо, навіть нуль з плаваючою точкою). Подібність між C і мовою складання корисна, наприклад, коли C використовується як цільова мова для компіляції іншої мови (навіть тієї, яка має сильно набрані булеві символи!)


0

Булева чи істинна величина має лише 2 значення. Справжнє і хибне.

Вони не повинні бути представлені як цілі числа, а як біти (0 і 1).

Сказати, що будь-яке інше ціле число, що знаходиться поряд із 0 або 1, не є помилковим, це заплутане твердження. Таблиці істини стосуються значень істини, а не цілих чисел.

З потенційного значення істини -1 або 2 розбиває всі таблиці істинності та будь-яку булеву логіку, пов'язану з ними.

  • 0 І -1 == ?!
  • 0 АБО 2 == ?!

Більшість мов зазвичай мають booleanтип, який при передачі на тип числа, такий як ціле число, виявляє хибність для передавання як ціле значення 0.


1
0 І -1 == яке б булеве значення ви їм не кидали. Це те, що моє запитання про те , чому лиття їх TRUEабо FALSE. Ніколи я не говорив - можливо, я так і робив, але це не було призначено - цілі числа були правдивими чи хибними, я запитав, чому вони вважають, що залежно від того, що стосується булевих.
Морвен

-6

Зрештою, ви говорите про злам основної мови, оскільки деякі API-файли хитрі. Crappy API не нові, і ви не можете їх виправити, порушивши мову. Математичний факт, що 0 неправдиво, а 1 - правда, і будь-яка мова, яка цього не поважає, принципово порушена. Тристороння порівняння є нішевою і не має бізнесу, маючи результат неявно перетворений, boolоскільки він повертає три можливі результати. Старі API API просто мають жахливу обробку помилок, а також є зруйнованими, оскільки C не має необхідних мовних функцій, щоб не мати жахливих інтерфейсів.

Зауважте, що я не кажу, що для мов, які не мають явного цілочисельного-> булевого перетворення.


11
"Математичний факт, що 0 помилково, а 1 - правда" Ерм.
Р. Мартіньо Фернандес

11
Чи можете ви навести посилання на ваш "математичний факт, що 0 неправда, а 1 - правда"? Ваша відповідь звучить небезпечно, як зухвала.
Ден Пішельман

14
Це не математичний факт, але це математична умова з 19 століття.
Чарльз Е. Грант

1
Булева алгебра представлена ​​кінцевим полем, в якому 0 і 1 є елементами ідентичності для операцій, що нагадують адитон і множення. Ці операції, відповідно, АБО і І. Насправді булева алгебра пишеться так само, як звичайна алгебра, де поєднання позначає І, а +символ позначає АБО. Так, наприклад, abc + a'b'cозначає (a and b and c) or (a and (not b) and (not c)).
Каз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.