stringtranslate.com

Реляционный оператор

В информатике реляционный оператор — это конструкция или оператор языка программирования , который проверяет или определяет некое отношение между двумя сущностями . К ним относятся числовые равенства ( например , 5 = 5 ) и неравенства ( например , 4 ≥ 3 ).

В языках программирования, которые включают в свою систему типов отдельный тип данных boolean , например Pascal , Ada или Java , эти операторы обычно оцениваются как true или false, в зависимости от того, выполняется ли условное отношение между двумя операндами или нет. В таких языках, как C , реляционные операторы возвращают целые числа 0 или 1, где 0 означает false, а любое ненулевое значение означает true.

Выражение , созданное с использованием реляционного оператора, образует то, что называется реляционным выражением или условием . Реляционные операторы можно рассматривать как особые случаи логических предикатов .

Равенство

Использование

Равенство используется во многих конструкциях языка программирования и типах данных. Оно используется для проверки того, существует ли элемент в наборе , или для доступа к значению через ключ. Оно используется в операторах switch для отправки потока управления на правильную ветвь и во время процесса унификации в логическом программировании.

Может быть несколько допустимых определений равенства, и любой конкретный язык может принять одно или несколько из них в зависимости от различных аспектов дизайна. Одно из возможных значений равенства заключается в том, что «если a равно b , то a или b могут быть использованы взаимозаменяемо в любом контексте без какой-либо разницы». Но это утверждение не обязательно выполняется, особенно если принять во внимание изменчивость вместе с равенством содержимого.

Равенство местоположения против равенства содержания

Иногда, особенно в объектно-ориентированном программировании , сравнение поднимает вопросы типов данных и наследования , равенства и идентичности . Часто необходимо различать:

Во многих современных языках программирования доступ к объектам и структурам данных осуществляется через ссылки . В таких языках возникает необходимость проверки на два различных типа равенства:

  • Структурное равенство (то есть их содержимое одинаково). которое может быть либо поверхностным (проверяя только непосредственные подчасти), либо глубоким (проверяя равенство подчастей рекурсивно). Простой способ достижения этого — через репрезентативное равенство: проверка того, что значения имеют одинаковое представление.
  • Некоторые другие индивидуальные равенства, сохраняющие внешнее поведение. Например, 1/2 и 2/4 считаются равными, если рассматривать их как рациональное число. Возможным требованием было бы, чтобы «A = B тогда и только тогда, когда все операции над объектами A и B будут иметь одинаковый результат», в дополнение к рефлексивности , симметрии и транзитивности .

Первый тип равенства обычно подразумевает второй (за исключением таких вещей, как не число ( NaN ), которые не равны сами себе), но обратное не обязательно верно. Например, два строковых объекта могут быть разными объектами (неравными в первом смысле), но содержать одну и ту же последовательность символов (равными во втором смысле). Подробнее об этой проблеме см. в разделе identity .

Действительные числа, включая множество простых дробей , не могут быть точно представлены в арифметике с плавающей точкой , и может потребоваться проверка на равенство в пределах заданного допуска. Однако такой допуск может легко нарушить желаемые свойства, такие как транзитивность, тогда как рефлексивность тоже нарушается: стандарт IEEE для плавающей точки требует, чтобы выполнялось NaN ≠ NaN . Напротив, частный стандарт (2022) для арифметики posit (сторонники posit имеют в виду замену чисел с плавающей точкой IEEE) имеет похожую концепцию, NaR (Not a Real), где выполняется NaR = NaR . [1]

Другие элементы программирования, такие как вычислимые функции, могут либо не иметь смысла равенства, либо равенство, которое невычислимо. По этим причинам некоторые языки определяют явное понятие «сравнимости» в форме базового класса, интерфейса, признака или протокола, который используется либо явно, путем объявления в исходном коде, либо неявно, через структуру задействованного типа.

Сравнение значений разных типов

В JavaScript , PHP , VBScript и некоторых других динамически типизированных языках стандартный оператор равенства следует так называемой свободной типизации , то есть он оценивается как истинный, даже если два значения не равны и имеют несовместимые типы, но могут быть приведены друг к другу некоторым набором специфичных для языка правил, например, делая число 4 равным текстовой строке «4». Хотя такое поведение обычно призвано сделать язык проще, оно может привести к неожиданным и труднопредсказуемым последствиям, о которых многие программисты не знают. Например, свободные правила равенства Javascript могут сделать равенство нетранзитивным (т. е. a == bи b == c, но a != c), или сделать определенные значения равными своему собственному отрицанию. [2]

В этих языках также часто доступен оператор строгого равенства, возвращающий значение true только для значений с идентичными или эквивалентными типами (в PHP 4 === "4"это значение false, хотя 4 == "4"это значение true). [3] [4] Для языков, где число 0 может быть интерпретировано как false , этот оператор может упростить такие вещи, как проверка на ноль (как это x == 0было бы true для x, равного либо 0, либо «0» при использовании оператора равенства, не зависящего от типа).

Заказ

Сравнение «больше чем» и «меньше чем» нечисловых данных выполняется в соответствии с соглашением о сортировке (например, для текстовых строк — в лексикографическом порядке ), которое может быть встроено в язык программирования и/или настраиваться программистом.

Когда требуется связать числовое значение с результатом сравнения двух элементов данных, скажем, a и b , обычно присваивается −1, если a < b, 0, если a = b, и 1, если a > b. Например, функция C strcmpвыполняет трехстороннее сравнение и возвращает −1, 0 или 1 в соответствии с этим соглашением, а qsort ожидает, что функция сравнения вернет значения в соответствии с этим соглашением. В алгоритмах сортировки эффективность кода сравнения имеет решающее значение, поскольку это один из основных факторов, влияющих на производительность сортировки.

Сравнение типов данных , определенных программистом (типов данных, для которых язык программирования не имеет встроенного понимания), может осуществляться с помощью специально написанных или библиотечных функций (таких, как strcmpупомянутые выше) или, в некоторых языках, путем перегрузки оператора сравнения – то есть присвоения определенного программистом значения, которое зависит от сравниваемых типов данных. Другой альтернативой является использование некоторого соглашения, такого как сравнение по элементам.

Логическая эквивалентность

Хотя, возможно, на первый взгляд это неочевидно, как и булевы логические операторы XOR, AND, OR и NOT, реляционные операторы могут быть разработаны так, чтобы иметь логическую эквивалентность , так что все они могут быть определены в терминах друг друга. Следующие четыре условных оператора имеют одинаковую логическую эквивалентность E (либо все истинны, либо все ложны) для любых заданных значений x и y :

Это зависит от того, насколько хорошо упорядочен домен .

Стандартные реляционные операторы

Ниже показаны наиболее распространенные числовые реляционные операторы, используемые в языках программирования. Стандартный SQL использует те же операторы, что и BASIC, в то время как многие базы данных допускают !=в дополнение <>к стандарту. SQL следует строгой булевой алгебре , т. е. не использует сокращенную оценку , которая является общей для большинства языков ниже. Например, в PHP она есть, но в остальном у него есть те же два оператора, определенные как псевдонимы, как и во многих базах данных SQL.

  1. ^ Включая FORTRAN II, III, IV, 66 и 77.
  2. ^ АЛГОЛ 68 : режимы правки используются в коде на платформах с ограниченными наборами символов ( например , используйте >=или GEвместо ), платформах без bold выделения (используйте 'ge') или платформах только с ЗАГЛАВНЫМИ БУКВАМИ (используйте .GE или 'GE' ).
  3. ^ Включая ALGOL , Simula , Modula-2 , Eiffel , SQL , формулы электронных таблиц и другие.
  4. ^ Modula-2 также распознает#
  5. ^ Включая C , C++ , C# , Go , Java , JavaScript , Perl ( только численное сравнение), PHP , Python , Ruby и R.
  6. ^ Включая Bourne shell , Bash , KornShell и Windows PowerShell . Символы <и >обычно используются в оболочке для перенаправления , поэтому необходимо использовать другие символы. Без дефиса используется в Perl для сравнения строк.
  7. ^ MATLAB, хотя в других отношениях использует синтаксис, похожий на C, не использует !=, как !в MATLAB отправляет следующий текст в качестве командной строки операционной системе . Первая форма также используется в Smalltalk , за исключением равенства, которое является =.
  8. ^ Включая FORTRAN 95, 2003, 2008 и 2015.

Другие соглашения менее распространены: Common Lisp и Macsyma / Maxima используют операторы типа Basic для числовых значений, за исключением неравенства, которое есть /=в Common Lisp и #Macsyma / Maxima. Common Lisp имеет несколько других наборов операторов равенства и отношения, служащих различным целям, включая eq, eql, equal, equalp, и string=. [6] Более старые Lisp использовали equal, greaterp, и lessp; и отрицали их, используя notдля остальных операторов.

Синтаксис

Реляционные операторы также используются в технической литературе вместо слов. Реляционные операторы обычно записываются в инфиксной нотации , если она поддерживается языком программирования, что означает, что они появляются между своими операндами (два выражения связаны). Например, выражение в Python выведет сообщение, если x меньше y :

если  x  <  y :  print ( "x меньше y в этом примере" )

Другие языки программирования, такие как Lisp , используют префиксную нотацию следующим образом:

( >= X Y )  

Цепочка операторов

В математике общепринятой практикой является цепочка реляционных операторов, например, 3 < x < y < 20 (что означает 3 < x и x < y и y < 20). Синтаксис ясен, поскольку эти реляционные операторы в математике являются транзитивными.

Однако многие современные языки программирования рассматривают выражение типа 3 < x < y как состоящее из двух лево- (или право-) ассоциативных операторов, интерпретируя его как что-то вроде (3 < x) < y. Если мы говорим, что x=4, то получаем (3 < 4) < y, и оценка даст true < yчто, как правило, не имеет смысла. Однако это компилируется в C/C++ и некоторых других языках, давая удивительный результат (поскольку true будет представлено здесь числом 1).

Можно придать выражению x < y < zего привычное математическое значение, и некоторые языки программирования, такие как Python и Raku, делают это. Другие, такие как C# и Java, не делают этого, отчасти потому, что это будет отличаться от того, как работают большинство других инфиксных операторов в языках типа C. Язык программирования D этого не делает, поскольку он сохраняет некоторую совместимость с C, и «разрешение выражений C, но с тонко отличающейся семантикой (хотя, возможно, в правильном направлении) добавило бы больше путаницы, чем удобства». [7]

Некоторые языки, например Common Lisp , используют для этого многоаргументные предикаты. В Lisp (<= 1 x 10)истинно, когда x находится между 1 и 10.

Путаница с операторами присваивания

Ранний FORTRAN (1956–57) был ограничен сильно ограниченными наборами символов, где =был доступен только один реляционный оператор. Не было <or >(и, конечно, не было or ). Это заставило разработчиков определить такие символы, как .GT., .LT., .GE., .EQ.и т. д., и впоследствии создало соблазн использовать оставшийся =символ для копирования, несмотря на очевидную несогласованность с математическим использованием ( X=X+1должно быть невозможно).

Таким образом, Международный алгебраический язык (IAL, ALGOL 58 ) и ALGOL (1958 и 1960) были введены :=для присваивания, оставив стандарт =доступным для равенства, соглашение, которому последовали CPL , ALGOL W , ALGOL 68 , Basic Combined Programming Language ( BCPL ), Simula , SET Language ( SETL ), Pascal , Smalltalk , Modula-2 , Ada , Standard ML , OCaml , Eiffel , Object Pascal ( Delphi ), Oberon , Dylan , VHSIC Hardware Description Language ( VHDL ) и несколько других языков.

Б и С

Этот единый фактический стандарт большинства языков программирования в конечном итоге был изменен, косвенно, минималистским компилируемым языком под названием B. Его единственным предполагаемым применением было средство для первого порта (тогда очень примитивного) Unix , но он также превратился в очень влиятельный язык C.

B начинался как синтаксически измененный вариант языка системного программирования BCPL , упрощенной (и бестиповой) версии CPL . В том, что было описано как процесс "урезания", операторы andи orиз BCPL [8] были заменены на &и |(которые позже стали &&и ||, соответственно. [9] ). В том же процессе стиль ALGOL :=из BCPL был заменен на =в B. Причина всего этого неизвестна. [10] Поскольку обновления переменных не имели специального синтаксиса в B (такого как letили подобного) и были разрешены в выражениях, это нестандартное значение знака равенства означало, что традиционная семантика знака равенства теперь должна была быть связана с другим символом. Кен Томпсон использовал для этого специальную ==комбинацию.

Поскольку позднее была введена небольшая система типов, B стал C. Популярность этого языка, а также его связь с Unix привели к тому, что Java, C# и многие другие языки последовали его примеру синтаксически, несмотря на этот ненужный конфликт с математическим значением знака равенства.

Языки

Присваивания в C имеют значение , и поскольку любое ненулевое скалярное значение интерпретируется как истинное в условных выражениях , [11] код if (x = y)является допустимым, но имеет совсем другой смысл, чем if (x == y). Первый фрагмент кода означает «присвоить y значению x , и если новое значение x не равно нулю, выполнить следующий оператор». Последний фрагмент означает « если и только если x равно y , выполнить следующий оператор». [12]

 int x = 1 ; int y = 2 ; if ( x = y ) { /* Этот код всегда будет выполняться, если y не равен 0*/ printf ( "x is %d and y is %d \n " , x , y ); }                 

Хотя Java и C# имеют те же операторы, что и C, эта ошибка обычно вызывает ошибку компиляции в этих языках, потому что условие if должно иметь тип boolean, и не существует неявного способа преобразования из других типов ( например , чисел) в booleans. Таким образом, если переменная, которой присваивается, не имеет типа boolean(или типа оболочки Boolean), возникнет ошибка компиляции.

В языках типа ALGOL, таких как Pascal, Delphi и Ada (в том смысле, что они допускают вложенные определения функций ), а также в Python и многих функциональных языках, среди прочих, операторы присваивания не могут появляться в выражении ( включая ifпредложения), тем самым исключая этот класс ошибок. Некоторые компиляторы, такие как GNU Compiler Collection (GCC), выдают предупреждение при компиляции кода, содержащего оператор присваивания внутри оператора if, хотя существуют некоторые допустимые применения присваивания внутри условия if. В таких случаях присваивание должно быть явно заключено в дополнительную пару скобок, чтобы избежать предупреждения.

Аналогично, некоторые языки, такие как BASIC, используют только один =символ для присваивания и равенства, поскольку они синтаксически разделены (как в Pascal, Ada, Python и т. д., операторы присваивания не могут появляться в выражениях).

Некоторые программисты привыкли писать сравнения с константой в обратном обычному порядке:

 if ( 2 == a ) { /* Ошибочное использование = вместо == приведет к ошибке времени компиляции */ }      

Если =используется случайно, полученный код недействителен, поскольку 2 не является переменной. Компилятор выдаст сообщение об ошибке, в котором можно заменить правильный оператор. Такой стиль кодирования называется сравнением левой рукой или условиями Йоды .

В этой таблице перечислены различные механизмы проверки этих двух типов равенства в разных языках:

  1. ^ Заявка на патент: 14 мая 2003 года сотрудниками Microsoft была подана заявка США 20,040,230,959  "IS NOT OPERATOR" на оператора . Этот патент был выдан 18 ноября 2004 года.ISNOT

Ruby использует a === bдля обозначения того, что «b является членом множества a», хотя детали того, что означает быть членом, значительно различаются в зависимости от используемых типов данных. ===здесь известен как оператор «равенства регистров» или «категории регистров».

Смотрите также

Примечания и ссылки

  1. ^ Стандарт для арифметики Posit (2022)
  2. ^ Денис, Довгань. "ВТФДЖС". Гитхаб . Проверено 25 июля 2024 г.
  3. ^ Участники. "Сравнение объектов". PHP Manual . PHP Group . Получено 29 июня 2014 г. {{cite web}}: |author=имеет общее название ( помощь ) ; Внешняя ссылка в |author=( помощь )
  4. ^ "PHP: Операторы сравнения - Руководство" . Получено 31 июля 2008 г.
  5. ^ Реляционные и логические операторы Mathematica
  6. ^ «Почему существует так много способов сравнения на предмет равенства?». Stack Overflow . Получено 25 июля 2024 г.
  7. ^ Александреску, Андрей (2010). Язык программирования D. Эддисон Уэсли. стр. 58. ISBN 978-0-321-63536-5.
  8. ^ Используется не только в языках типа ALGOL, но также в FORTRAN и BASIC.
  9. ^ Поскольку некоторые программисты были сбиты с толку двойным значением (побитовый оператор и логическая связка) этих новых символов (согласно Деннису Ритчи ). Были сохранены только побитовые значения & и |.
  10. ^ Хотя Деннис Ритчи предположил, что это могло быть связано с «экономией набора текста», поскольку обновления переменных могут происходить чаще, чем сравнения в некоторых типах программ.
  11. ^ Нулевое скалярное значение интерпретируется как ложь, тогда как любое ненулевое скалярное значение интерпретируется как истина; это обычно используется с целочисленными типами, аналогично идиомам языка ассемблера .
  12. ^ Брайан Керниган и Деннис Ритчи (1988) [1978]. Язык программирования C (второе издание). Prentice Hall., 19