Этот вопрос может показаться глупым, но почему 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
. Тем не менее, во всех языках программирования, которые я знаю (за исключением, может быть, некоторых экспериментальных эзотерических языков), который yes
оценивается false
как if
условие, а все no
случаи - как условие true
. Есть много ситуаций, когда «это работает» представляет один случай, в то время как «это не работает» представляет много вероятных причин. Если мы думаем об этом таким образом, то иметь 0
оценку true
и все остальное false
имело бы гораздо больше смысла.
Заключение
По сути, мой вывод - это мой первоначальный вопрос: почему мы разрабатывали языки там, где 0
есть false
и другие значения true
, принимая во внимание мои несколько приведенных выше примеров и, может быть, некоторые другие, о которых я не думал?
Продолжение: Приятно видеть, что есть много ответов с множеством идей и как можно больше причин для этого. Мне нравится, насколько ты увлечен этим. Изначально я задавал этот вопрос от скуки, но, поскольку вы кажетесь настолько страстным, я решил пойти немного дальше и спросить об обосновании логического выбора для 0 и 1 на Math.SE :)
источник
strcmp()
плохой пример для истины или ложи, так как он возвращает 3 разных значения. И вы будете удивлены, когда начнете использовать оболочку, где 0 означает true, а все остальное означает false.if true ; then ... ; fi
, гдеtrue
- это команда, которая возвращает ноль, и это указываетif
на выполнение...
.bool
типа , но сравнения / , если условия и т.д. могут иметь любое возвращаемое значение.Ответы:
0
этоfalse
потому , что они оба нулевые элементы в общих полукольцами . Несмотря на то, что они являются различными типами данных, имеет смысл интуитивно понимать преобразование между ними, поскольку они принадлежат изоморфным алгебраическим структурам.0
это тождество для сложения и ноль для умножения. Это верно для целых и рациональных чисел, но не для чисел с плавающей точкой IEEE-754:0.0 * NaN = NaN
и0.0 * Infinity = NaN
.false
является тождеством для логического xor (⊻) и нуля для логического и (∧). Если логические значения представлены как {0, 1} - набор целых чисел по модулю 2 - вы можете рассматривать ⊻ как сложение без переноса и ∧ как умножение.""
и[]
являются идентичностью для объединения, но есть несколько операций, для которых они имеют смысл как ноль. Повторение одно, но повторение и конкатенация не распределяются, поэтому эти операции не образуют полукольца.Такие неявные преобразования полезны в небольших программах, но в целом могут затруднить анализ программ. Просто один из многих компромиссов в языковом дизайне.
источник
nil
это и пустой список,[]
иfalse
значение в Common Lisp; есть ли тенденция объединять тождества из разных типов данных?) Вам все еще нужно объяснить, почему естественно рассматривать false как аддитивную идентичность и true как мультипликативную идентичность и не наоборот. Не возможно ли считатьtrue
идентификатором дляAND
и ноль дляOR
?true
также тождество и ноль полуколец (булево и / или). Нет никакой причины, по соглашению appart, рассмотретьfalse
ближе к 0, чемtrue
.Потому что математика работает.
Традиционно, программы на С имеют такие условия, как
скорее, чем
потому что концепция нуля, эквивалентного ложному, хорошо понятна.
источник
Как уже говорили другие, математика пришла первой. Вот почему 0 есть,
false
а 1 естьtrue
.О какой математике мы говорим? Булевы алгебры, которые датируются серединой 1800-х годов, задолго до появления цифровых компьютеров.
Можно также сказать, что конвенция возникла из логики высказываний , которая даже старше, чем булевы алгебры. Это формализация многих логических результатов, которые программисты знают и любят (
false || x
равноx
,true && x
равноx
и так далее).В основном мы говорим об арифметике на множестве из двух элементов. Подумайте о подсчете в двоичном виде. Булевы алгебры являются источником этой концепции и ее теоретической основой. Соглашения о языках, таких как C, являются простым приложением.
источник
true = 1
. Это не совсем точно, потомуtrue != 0
что это не совсем то же самое. Одна причина (не единственная), почему следует избегать подобных сравненийif(something == true) { ... }
.Я думал, что это связано с «наследованием» от электроники, а также с булевой алгеброй, где
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
.источник
0
дляsuccess/no error
этого единственным , что имеет смысл , когда другие целые числа представляют собой коды ошибок. Это0
также означает, чтоfalse
в других случаях это не имеет большого значения, так как мы вообще не говорим об истинном или ложном;)strcmp()
расчете расстояния довольно хорошая. Если бы было названоstrdiff()
тоif (!strdiff())
было бы очень логично.Как поясняется в этой статье , значения
false
иtrue
не следует путать с целыми числами 0 и 1, но их можно отождествлять с элементами поля Галуа (конечного поля) из двух элементов (см. Здесь ).Поле - это набор с двумя операциями, которые удовлетворяют определенным аксиомам.
Символы 0 и 1 обычно используются для обозначения аддитивных и мультипликативных тождеств поля, поскольку действительные числа также являются полем (но не конечным), тождествами которого являются числа 0 и 1.
Аддитивным тождеством является элемент 0 поля, такой что для всех x:
и мультипликативная идентичность - это элемент 1 поля, такой что для всех x:
Конечное поле из двух элементов имеет только эти два элемента, а именно аддитивное тождество 0 (или
false
) и мультипликативное тождество 1 (илиtrue
). Две операции в этом поле - логический XOR (+) и логический AND (*).Запись. Если вы переворачиваете операции (XOR - это умножение, а AND - это сложение), то умножение не является дистрибутивным по сравнению с сложением, и у вас больше нет поля. В таком случае у вас нет причин называть два элемента 0 и 1 (в любом порядке). Также обратите внимание, что вы не можете выбрать операцию ИЛИ вместо XOR: независимо от того, как вы интерпретируете ИЛИ / И как сложение / умножение, результирующая структура не является полем (не все обратные элементы существуют, как того требуют аксиомы поля).
Относительно функций C:
strcmp
вычисляет разницу между двумя строками. 0 означает, что нет никакой разницы между двумя строками, т.е. что две строки равны.Приведенные выше интуитивные объяснения могут помочь запомнить интерпретацию возвращаемых значений, но еще проще просто проверить документацию библиотеки.
источник
Следует учитывать, что альтернативные системы также могут быть приемлемыми проектными решениями.
Оболочки: 0 выходной статус истина, ненулевое значение ложь
Пример оболочек, рассматривающих состояние выхода 0 как true, уже упоминался.
Основанием для этого является то, что есть один способ добиться успеха, но есть много способов потерпеть неудачу, поэтому прагматично использовать 0 в качестве специального значения, означающего «нет ошибок».
Рубин: 0, как и любой другой номер
Среди «нормальных» языков программирования есть некоторые выбросы, такие как Ruby, которые рассматривают 0 как истинное значение.
Обоснованием является то , что только
false
иnil
должно быть ложным. Для многих новичков в Ruby это гоча. Однако в некоторых случаях приятно, что 0 обрабатывается так же, как и любое другое число.Однако такая система работает только на языке, который может отличать логические значения как отдельный тип от чисел. На заре вычислительной техники программисты, работающие на ассемблере или на машинном языке, не имели такой роскоши. Вероятно, вполне естественно рассматривать 0 как «пустое» состояние и устанавливать бит в 1 как флаг, когда код обнаружил, что что-то произошло. Таким образом, согласно соглашению, ноль считался ложным, а ненулевые значения считались истинными. Тем не менее, это не должно быть так.
Java: числа вообще не могут рассматриваться как логические
В Java,
true
иfalse
являются единственными булевы значения. Числа не являются логическими значениями и даже не могут быть преобразованы в логические значения ( спецификация языка Java, раздел 4.2.2 ):Это правило просто избегает вопроса - все логические выражения должны быть явно написаны в коде.
источник
if (thing === 0)
, это просто не круто.0
этоtrue
(как и любое другое целое число) в динамическом языке. Иногда мне приходилось ловить0
при попытке пойматьNone
в Python, и это иногда бывает довольно трудно обнаружить.if [ 0 ] ; then echo this executes ; fi
. Значение ложных данных представляет собой пустую строку, а проверяемая ложность - состояние неудачного завершения команды, которое представлено ненулевым значением.Перед рассмотрением общего случая мы можем обсудить ваши контрпримеры.
Строковые сравнения
То же самое верно для многих сравнений. Такие сравнения вычисляют расстояние между двумя объектами. Когда объекты равны, расстояние минимально. Поэтому , когда «сравнение успешно», то значение равно 0. Но на самом деле, возвращаемое значение
strcmp
является не логическим значением, это расстояние, и то , что ловушки не знающие программисты делаютif (strcmp(...)) do_when_equal() else do_when_not_equal()
.В C ++ мы могли бы перепроектировать,
strcmp
чтобы вернутьDistance
объект, который переопределяет,operator bool()
чтобы возвратить true, когда 0 (но тогда вы будете укушены другим набором проблем). Или в простом C просто естьstreq
функция, которая возвращает 1, когда строки равны, и 0 в противном случае.Вызовы API / код выхода из программы
Здесь вас волнует причина, по которой что-то пошло не так, потому что это приведет к ошибкам при принятии решений. Когда все получается, вы не хотите знать ничего конкретного - ваше намерение реализовано. Поэтому возвращаемое значение должно передавать эту информацию. Это не логическое значение, это код ошибки. Значение специальной ошибки 0 означает «нет ошибки». Остальная часть диапазона представляет локально значимые ошибки, с которыми вам приходится иметь дело (включая 1, что часто означает «неопределенная ошибка»).
Общий случай
Это оставляет нас с вопросом: почему логические значения
True
иFalse
обычно представлены с 1 и 0, соответственно?Ну, кроме субъективного аргумента "так лучше", есть несколько причин (в том числе и субъективных), о которых я могу подумать:
аналогия электрической цепи. Ток включен в течение 1 с и выключен в течение 0 с. Мне нравится иметь (1, Да, True, On) вместе и (0, No, False, Off), а не другой микс
инициализация памяти. Когда я получаю
memset(0)
кучу переменных (будь то целые числа, числа с плавающей запятой, значения типа bools), я хочу, чтобы их значение соответствовало самым консервативным предположениям. Например, моя сумма изначально равна 0, предикат равен False и т. Д.Возможно, все эти причины связаны с моим образованием - если бы меня с самого начала учили ассоциировать 0 с Истиной, я бы пошел другим путем.
источник
bool
.int
кbool
во многих языках программирования. Сравнение и анализ ошибок - это просто примеры мест, где было бы целесообразно приводить их не так, как это делается в настоящее время.С точки зрения высокого уровня, вы говорите о трех совершенно разных типах данных:
Логическое. Математическое соглашение в булевой алгебре состоит в том, чтобы использовать 0 для
false
и 1 дляtrue
, поэтому имеет смысл следовать этому соглашению. Я думаю, что этот путь также имеет больше смысла интуитивно.Результат сравнения. Это имеет три значения:
<
,=
и>
(заметьте , что ни один из них не являетсяtrue
). Для них имеет смысл использовать значения -1, 0 и 1 соответственно (или, в более общем случае, отрицательное значение, ноль и положительное значение).Если вы хотите проверить на равенство, и у вас есть только функция, которая выполняет общее сравнение, я думаю, вы должны сделать это явно, используя что-то вроде
strcmp(str1, str2) == 0
. Я нахожу использование!
в этой ситуации запутанным, потому что оно обрабатывает не логическое значение, как если бы оно было логическим.Также имейте в виду, что сравнение и равенство не обязательно должны совпадать. Например, если вы заказываете людей по дате их рождения,
Compare(me, myTwin)
должны вернуться0
, ноEquals(me, myTwin)
должны вернутьсяfalse
.Успех или неудача функции, возможно, также с подробностями об этом успехе или неудаче. Если вы говорите о Windows, то этот тип вызывается,
HRESULT
и ненулевое значение не обязательно означает сбой. Фактически, отрицательное значение указывает на неудачу и неотрицательный успех. Значение успеха очень частоS_OK = 0
, но это могут быть, напримерS_FALSE = 1
, или другие значения.Путаница возникает из-за того, что три логически совершенно разных типа данных фактически представлены как один тип данных (целое число) в C и некоторых других языках и что вы можете использовать целое число в условии. Но я не думаю, что имеет смысл переопределять логическое значение, чтобы упростить использование некоторых не-логических типов в условиях.
Также рассмотрим другой тип, который часто используется в условии в C: указатель. Там естественно считать
NULL
-пойнт (который представлен как0
) какfalse
. Поэтому следование вашему предложению также затруднит работу с указателями. (Хотя лично я предпочитаю явно сравнивать указателиNULL
, а не рассматривать их как логические значения.)источник
Ноль может быть ложным, потому что большинство процессоров имеют флаг ZERO, который можно использовать для ветвления. Это сохраняет операцию сравнения.
Посмотрим почему.
Какой-то псевдокод, так как публика, вероятно, не читает сборку
c- исходный простой цикл вызывает колебания 10 раз
какая-то притворная сборка для этого
c- источник еще один простой цикл вызывает колебания 10 раз
какая-то притворная сборка для этого случая
еще немного c источником
и сборка
видите, как это коротко?
еще немного c источником
и сборка (предположим, что немного умный компилятор может заменить == 0 без сравнения)
Теперь давайте попробуем соглашение об истинности = 1
еще немного c source #define TRUE 1 int foo = TRUE; if (foo == TRUE) wibble ()
и сборка
видите, насколько коротким является случай с ненулевым значением true?
Действительно ранние процессоры имели небольшие наборы флагов, прикрепленных к Аккумулятору.
Чтобы проверить, что a> b или a = b, обычно требуется инструкция сравнения.
Давайте повторим это. На некоторых старых процессорах вам не приходилось использовать инструкцию сравнения для аккумулятора, равного нулю, или аккумулятора меньше нуля.
Теперь вы понимаете, почему ноль может быть ложным?
Обратите внимание, что это псевдо-код, и никакой реальный набор инструкций не выглядит так. Если вы знаете сборку, вы знаете, я здесь многое упрощаю. Если вы знаете что-нибудь о дизайне компилятора, вам не нужно было читать этот ответ. Любой, кто знает что-либо о развертывании цикла или предсказании ветвления, продвинутый класс идет по коридору в комнате 203.
источник
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;
jz
инструкция, но нетjnz
? (или любой другой асимметричный набор условных инструкций)Есть много ответов, которые предполагают, что соответствие между 1 и истиной обусловлено некоторым математическим свойством. Я не могу найти такую собственность и предполагаю, что это чисто историческое соглашение.
Для поля с двумя элементами у нас есть две операции: сложение и умножение. Мы можем отобразить логические операции с этим полем двумя способами:
Традиционно мы отождествляем True с 1 и False с 0. Мы отождествляем AND с * и XOR с +. Таким образом, OR является насыщающим дополнением.
Однако мы могли бы так же легко идентифицировать True с 0 и False с 1. Затем мы идентифицируем OR с * и XNOR с +. Таким образом, И является насыщающим дополнением.
источник
Странно, ноль не всегда ложен.
В частности, соглашение Unix и Posix должно быть определено
EXIT_SUCCESS
как 0 (иEXIT_FAILURE
как 1). На самом деле это даже стандартное соглашение C !Таким образом, для оболочек Posix и системных вызовов exit (2) 0 означает «успешный», что наглядно скорее верно, чем ложно.
В частности, оболочка
if
хочет , чтобы возвращаемый процессEXIT_SUCCESS
(то есть 0) следовал за своей ветвью "then"!В Схеме (но не в Common Lisp или в MELT ) 0 и nil (т.е.
()
в Схеме) являются истинными, поскольку единственное ложное значение#f
Я согласен, я придираюсь!
источник
C используется для низкоуровневого программирования, близкого к аппаратному, - область, в которой иногда нужно переключаться между битовыми и логическими операциями над одними и теми же данными. Необходимость преобразования числового выражения в логическое просто для выполнения теста может привести к засорению кода.
Вы можете написать такие вещи, как:
скорее, чем
В одном отдельном примере это не так уж и плохо, но необходимость делать это становится утомительной.
Аналогично, обратные операции. Для результата логической операции, такой как сравнение, полезно просто получить 0 или 1: Предположим, мы хотим установить третий бит некоторого слова в зависимости от того,
modemctrl
имеет ли бит обнаружения несущей:Здесь мы должны иметь
!= 0
, чтобы уменьшить результат&
выражения biwise до0
или1
, но поскольку результатом является просто целое число, мы избавлены от необходимости добавлять некоторое раздражающее приведение для дальнейшего преобразования логического значения в целое.Несмотря на то, что современный C теперь имеет
bool
тип, он все еще сохраняет достоверность кода, подобного этому, и потому, что это хорошо, и из-за огромного сбоя с обратной совместимостью, который мог бы возникнуть в противном случае.Еще один пример, где C ловко: тестирование двух логических условий в качестве четырехходового переключателя:
Вы не могли бы отнять это у программиста C без боя!
Наконец, C иногда служит своего рода языком ассемблера высокого уровня. В языках ассемблера у нас также нет логических типов. Логическое значение - это всего лишь бит или ноль в сравнении с ненулевым значением в ячейке памяти или регистре. Целый ноль, логический ноль и нулевой адрес проверяются одинаково в наборах команд на ассемблере (и, возможно, даже с плавающей точкой ноль). Сходство между C и ассемблером полезно, например, когда C используется в качестве целевого языка для компиляции другого языка (даже того, который имеет строго типизированные логические значения!)
источник
Логическое или истинное значение имеет только 2 значения. Правда и ложь.
Они должны не быть представлены в виде целых чисел, но в качестве битов (0 и 1).
Сказать, что любое другое целое число, кроме 0 или 1, не является ложным, является ошибочным утверждением. Таблицы истинности имеют дело со значениями истинности, а не целыми числами.
С точки зрения истинного значения -1 или 2 сломают все таблицы истинности и любую логическую логику, связанную с ними.
Большинство языков обычно имеют
boolean
тип, который при приведении к числовому типу, такому как целое число, показывает ложь, которая будет приведена к целочисленному значению 0.источник
TRUE
илиFALSE
. Никогда я не говорил - может быть, я и сделал, но это не было предназначено - целые числа были истинными или ложными, я спросил о том, почему они оценивают, в зависимости от того, что приведено к логическому значению.В конечном счете, вы говорите о взломе основного языка, потому что некоторые API являются дерьмовыми. Crappy API не новы, и вы не можете исправить их, нарушив язык. Это математический факт, что 0 ложно, а 1 верно, и любой язык, который не уважает это, в корне нарушен. Трехстороннее сравнение является нишевым и не имеет никакого смысла, поскольку его результат неявно конвертируется,
bool
поскольку он возвращает три возможных результата. Старые API-интерфейсы C просто ужасно обрабатывают ошибки, а также имеют проблемы, потому что C не имеет необходимых языковых возможностей, чтобы не иметь ужасных интерфейсов.Обратите внимание, что я не говорю, что для языков, которые не имеют неявного целочисленного -> логического преобразования.
источник
+
символ обозначает ИЛИ. Так, например,abc + a'b'c
означает(a and b and c) or (a and (not b) and (not c))
.