Operador relacional - Relational operator

En informática , un operador relacional es una construcción u operador de lenguaje de programación que prueba o define algún tipo de relación entre dos entidades . Estos incluyen igualdad numérica ( por ejemplo , 5 = 5 ) y desigualdades ( por ejemplo , 4 ≥ 3 ).

En los lenguajes de programación que incluyen un tipo de datos booleano distinto en su sistema de tipos , como Pascal , Ada o Java , estos operadores generalmente evalúan como verdadero o falso, dependiendo de si la relación condicional entre los dos operandos se cumple o no. En lenguajes como C , los operadores relacionales devuelven los números enteros 0 o 1, donde 0 significa falso y cualquier valor distinto de cero significa verdadero.

Una expresión creada usando un operador relacional forma lo que se denomina expresión relacional o condición . Los operadores relacionales pueden verse como casos especiales de predicados lógicos .

Igualdad

Uso

La igualdad se utiliza en muchos tipos de datos y construcciones de lenguajes de programación. Se utiliza para probar si un elemento ya existe en un conjunto , o para acceder a un valor a través de una clave. Se utiliza en declaraciones de conmutación para enviar el flujo de control a la rama correcta y durante el proceso de unificación en la programación lógica.

Un posible significado de igualdad es que "si a es igual a b , entonces a o b pueden usarse indistintamente en cualquier contexto sin notar ninguna diferencia". Pero esta afirmación no es necesariamente válida, especialmente cuando se tiene en cuenta la mutabilidad junto con la igualdad de contenido.

Igualdad de ubicación frente a igualdad de contenido

A veces, particularmente en la programación orientada a objetos , la comparación plantea preguntas sobre tipos de datos y herencia , igualdad e identidad . A menudo es necesario distinguir entre:

  • dos objetos diferentes del mismo tipo, por ejemplo, dos manos
  • dos objetos iguales pero distintos, por ejemplo, dos billetes de $ 10
  • dos objetos son iguales pero tienen una representación diferente, por ejemplo, un billete de $ 1 y una moneda de $ 1
  • dos referencias diferentes al mismo objeto, por ejemplo, dos apodos para la misma persona

En muchos lenguajes de programación modernos, se accede a los objetos y estructuras de datos a través de referencias . En tales lenguajes, se hace necesario probar dos tipos diferentes de igualdad:

  • Igualdad de ubicación (identidad): si dos referencias (A y B) hacen referencia al mismo objeto. Las interacciones con el objeto a través de A son indistinguibles de las mismas interacciones a través de B, y en particular los cambios en el objeto a través de A se reflejan a través de B.
  • Igualdad de contenido: si los objetos referenciados por dos referencias (A y B) son equivalentes en algún sentido:
  • Igualdad estructural (es decir, sus contenidos son los mismos). que puede ser superficial (probar solo subpartes inmediatas) o profundo (probar la igualdad de las subpartes de forma recursiva). Una forma sencilla de conseguirlo es mediante la igualdad de representación: comprobando que los valores tengan la misma representación.
  • Alguna otra igualdad a medida, preservando el comportamiento externo. Por ejemplo, 1/2 y 2/4 se consideran iguales cuando se ven como un número racional. Un posible requisito sería que "A = B si y solo si todas las operaciones sobre los objetos A y B tendrán el mismo resultado", además de la reflexividad , simetría y transitividad .

El primer tipo de igualdad generalmente implica el segundo (a excepción de cosas como no un número ( NaN ) que son desiguales entre sí), pero lo contrario no es necesariamente cierto. Por ejemplo, dos objetos de cadena pueden ser objetos distintos (desiguales en el primer sentido) pero contienen la misma secuencia de caracteres (iguales en el segundo sentido). Consulte identidad para obtener más información sobre este tema.

Los números reales, incluidas muchas fracciones simples , no se pueden representar exactamente en aritmética de punto flotante y puede ser necesario probar la igualdad dentro de una tolerancia dada. Sin embargo, dicha tolerancia puede romper fácilmente propiedades deseadas como la transitividad, mientras que la reflexividad también se rompe: el estándar de punto flotante IEEE requiere que NaN ≠ NaN se mantenga.

Otros elementos de programación, como las funciones computables, pueden no tener un sentido de igualdad o una igualdad que no se puede calcular. Por estas razones, algunos lenguajes definen una noción explícita de "comparable", en la forma de una clase base, una interfaz, un rasgo o un protocolo, que se usa explícitamente, por declaración en el código fuente, o implícitamente, a través de la estructura del tipo involucrado.

Comparando valores de diferentes tipos

En JavaScript , PHP , VBScript y algunos otros lenguajes tipados dinámicamente , el operador de igualdad estándar se evalúa como verdadero si dos valores son iguales, incluso si tienen diferentes tipos, por lo que el número 4 se compara con la cadena de texto "4", por ejemplo. . Un operador de igualdad escrito a menudo también está disponible, en dichos lenguajes, devolviendo verdadero solo para valores con tipos idénticos o equivalentes (en PHP, 4 === "4"es falso aunque 4 == "4"es verdadero). Para los lenguajes donde el número 0 se puede interpretar como falso , este operador puede simplificar cosas como verificar cero (como x == 0sería cierto si x es 0 o "0" usando el operador de igualdad de tipo agnóstico).

Ordenando

La comparación mayor que y menor que de datos no numéricos se realiza de acuerdo con una convención de clasificación (tal como, para cadenas de texto, orden lexicográfico ) que puede ser incorporada en el lenguaje de programación y / o configurable por un programador.

Cuando se desea asociar un valor numérico con el resultado de una comparación entre dos elementos de datos, por ejemplo un y b , la convención habitual es asignar -1 si a <b, 0 si a = b y 1 si a> b. Por ejemplo, la función C strcmprealiza una comparación de tres vías y devuelve -1, 0 o 1 de acuerdo con esta convención, y qsort espera que la función de comparación devuelva valores de acuerdo con esta convención. En los algoritmos de clasificación , la eficiencia del código de comparación es fundamental, ya que es uno de los principales factores que contribuyen al rendimiento de la clasificación.

La comparación de tipos de datos definidos por el programador ( tipos de datos para los que el lenguaje de programación no tiene un conocimiento incorporado) puede llevarse a cabo mediante funciones de biblioteca o escritas personalizadas (como las strcmpmencionadas anteriormente) o, en algunos lenguajes, sobrecargando una comparación operador, es decir, asignar un significado definido por el programador que depende de los tipos de datos que se comparan. Otra alternativa es utilizar alguna convención, como la comparación por miembros.

Equivalencia lógica

Aunque quizás no sean obvios al principio, como los operadores lógicos booleanos XOR, AND, OR y NOT, los operadores relacionales pueden diseñarse para tener equivalencia lógica , de modo que todos puedan definirse en términos entre sí. Los siguientes cuatro sentencias condicionales todos tienen la misma equivalencia lógica E (ya sea todo cierto o todas falsas) para cualquier dado x y Y valores:

Esto depende de que el dominio esté bien ordenado .

Operadores relacionales estándar

Los operadores relacionales numéricos más comunes utilizados en lenguajes de programación se muestran a continuación.

Operadores relacionales comunes
Convención igual a no igual a mas grande que menos que mayor
o igual a
menor
o igual a
En la impresión = > <
FORTRAN .EQ. .NE. .GT. .LT. .GE. .LE.
ALGOL 68 = > <
/= >= <=
eq ne gt lt ge le
APL = > <
BÁSICO , ML , Pascal = <> > < >= <=
PAPERAS = '= > < '< '>
Lua == ~= > < >= <=
Como C == != > < >= <=
Erlang == /= > < >= =<
=:= =/=
Conchas tipo Bourne -eq -ne -gt -lt -ge -le
Archivo por lotes EQU NEQ GTR LSS GEQ LEQ
MATLAB == ~= > < >= <=
eq(x,y) ne(x,y) gt(x,y) lt(x,y) ge(x,y) le(x,y)
Fortran 90 , Haskell == /= > < >= <=
Mathematica == != > < >= <=
Equal[x,y] Unequal[x,y] Greater[x,y] Less[x,y] GreaterEqual[x,y] LessEqual[x,y]

Otras convenciones son menos comunes: Common Lisp y Macsyma / Maxima usan operadores similares a los de Basic excepto por la desigualdad, que está /=en Common Lisp y #en Macsyma / Maxima. Mayores Lisps utilizarse equal, greaterpy lessp; y los negó usando notpara los operadores restantes.

Sintaxis

Los operadores relacionales también se utilizan en la literatura técnica en lugar de palabras. Los operadores relacionales generalmente se escriben en notación infija , si son compatibles con el lenguaje de programación, lo que significa que aparecen entre sus operandos (las dos expresiones están relacionadas). Por ejemplo, una expresión en Python imprimirá el mensaje si x es menor que y :

if x < y:
    print("x is less than y in this example")

Otros lenguajes de programación, como Lisp , usan la notación de prefijo , de la siguiente manera:

(>= X Y)

Encadenamiento de operadores

En matemáticas, es una práctica común encadenar operadores relacionales, como en 3 <x <y <20 (es decir, 3 <x y x <y e y <20). La sintaxis es clara ya que estos operadores relacionales en matemáticas son transitivos.

Sin embargo, muchos lenguajes de programación recientes verían una expresión como 3 <x <y como que consta de dos operadores asociativos a la izquierda (o a la derecha), interpretándola como algo parecido (3 < x) < y. Si decimos que x = 4, obtenemos (3 < 4) < y, y la evaluación dará, lo true < yque generalmente no tiene sentido. Sin embargo, se compila en C / C ++ y algunos otros lenguajes, produciendo un resultado sorprendente (como verdadero estaría representado por el número 1 aquí).

Es posible darle a la expresión x < y < zsu significado matemático familiar, y algunos lenguajes de programación como Python y Raku lo hacen. Otros, como C # y Java, no lo hacen, en parte porque diferiría de la forma en que la mayoría de los otros operadores infijos funcionan en lenguajes similares a C. El lenguaje de programación D no hace eso ya que mantiene cierta compatibilidad con C, y "Permitir expresiones en C pero con semánticas sutilmente diferentes (aunque posiblemente en la dirección correcta) agregaría más confusión que conveniencia".

Algunos lenguajes, como Common Lisp , utilizan predicados de múltiples argumentos para esto. En Lisp (<= 1 x 10)es verdadero cuando x está entre 1 y 10.

Confusión con los operadores de asignación

El primer FORTRAN (1956–57) estaba limitado por conjuntos de caracteres muy restringidos donde =era el único operador relacional disponible. No hubo <o >(y ciertamente no o ). Esto obligó a los diseñadores para definir símbolos tales como .GT., .LT., .GE., .EQ.etc, y posteriormente se hizo sentir la tentación de utilizar los restantes =caracteres para copiar, a pesar de la incoherencia evidente con el uso matemática ( X=X+1debería ser imposible).

Algebraica Idioma Internacional (IAL, ALGOL 58 ) y Algol (1958 y 1960) así introducida :=para la asignación, dejando el estándar =disponible para la igualdad, una convención seguidos por CPL , ALGOL W , ALGOL 68 , básica combinada Lenguaje de programación ( BCPL ), Simula , SET Language ( SETL ), Pascal , Smalltalk , Modula-2 , Ada , Standard ML , OCaml , Eiffel , Object Pascal ( Delphi ), Oberon , Dylan , VHSIC Hardware Description Language ( VHDL ) y varios otros idiomas.

B y C

Este uniforme de estándar de facto entre la mayoría de los lenguajes de programación fue finalmente cambiado, de manera indirecta, por un minimalista compilado llamado lenguaje B . Su única aplicación prevista fue como vehículo para un primer puerto de Unix (entonces muy primitivo) , pero también evolucionó hacia el lenguaje C muy influyente .

B comenzó como una variante sintácticamente modificada del lenguaje de programación de sistemas BCPL , una versión simplificada (y sin tipo) de CPL . En lo que se ha descrito como un proceso de "eliminación", los operadores andy orde BCPL fueron reemplazados por &y |(que luego se convertirían en &&y ||, respectivamente). En el mismo proceso, el estilo ALGOL :=de BCPL fue reemplazado por =en B. Se desconoce la razón de todo esto. Como las actualizaciones de variables no tenían una sintaxis especial en B (como leto similar) y estaban permitidas en las expresiones, este significado no estándar del signo igual significaba que la semántica tradicional del signo igual ahora tenía que asociarse con otro símbolo. Ken Thompson usó la ==combinación ad hoc para esto.

A medida que se introdujo más tarde un sistema de tipos pequeños, B se convirtió en C. La popularidad de este lenguaje, junto con su asociación con Unix, llevó a Java, C # y muchos otros lenguajes a seguir su ejemplo, sintácticamente, a pesar de este conflicto innecesario con el significado matemático de el signo igual.

Idiomas

Las asignaciones en C tienen un valor y dado que cualquier valor escalar distinto de cero se interpreta como verdadero en expresiones condicionales , el código if (x = y)es legal, pero tiene un significado muy diferente al de if (x == y). El fragmento de código anterior significa "asignar y a x , y si el nuevo valor de x no es cero, ejecutar la siguiente instrucción". El último fragmento significa " si y solo si x es igual ay , ejecute la siguiente instrucción".

  int x = 1;
  int y = 2;
  if (x = y) {
      /* This code will always execute if y is anything but 0*/
      printf("x is %d and y is %d\n", x, y);
  }

Aunque Java y C # tienen los mismos operadores que C, este error generalmente causa un error de compilación en estos lenguajes, porque la condición if debe ser de tipo booleany no hay una forma implícita de convertir otros tipos ( por ejemplo , números) en booleans. Entonces, a menos que la variable asignada tenga un tipo boolean(o tipo contenedor Boolean), habrá un error de compilación.

En lenguajes similares a ALGOL como Pascal, Delphi y Ada (en el sentido de que permiten definiciones de funciones anidadas ), y en Python , y muchos lenguajes funcionales, entre otros, los operadores de asignación no pueden aparecer en una expresión (incluidas las ifcláusulas), por lo que excluyendo esta clase de error. Algunos compiladores, como GNU Compiler Collection (GCC), proporcionan una advertencia al compilar código que contiene un operador de asignación dentro de una instrucción if, aunque hay algunos usos legítimos de una asignación dentro de una condición if. En tales casos, la asignación debe incluirse explícitamente en un par adicional de paréntesis, para evitar la advertencia.

De manera similar, algunos lenguajes, como BASIC, usan solo el =símbolo tanto para la asignación como para la igualdad, ya que están separados sintácticamente (como con Pascal, Ada, Python, etc., los operadores de asignación no pueden aparecer en las expresiones).

Algunos programadores se acostumbran a escribir comparaciones con una constante en el orden inverso al habitual:

  if (2 == a) {   /* Mistaken use of = versus == would be a compile-time error */
  }

Si =se usa accidentalmente, el código resultante no es válido porque 2 no es una variable. El compilador generará un mensaje de error, en el que se puede sustituir el operador adecuado. Este estilo de codificación se denomina comparación a la izquierda o condiciones de Yoda .

Esta tabla enumera los diferentes mecanismos para probar estos dos tipos de igualdad en varios idiomas:

Idioma Igualdad fisica Igualdad estructural Notas
ALGOL 68 a :=: b o a is b a = b cuando ay bson punteros
C , C ++ a == b *a == *b cuando ay bson punteros
C# object.ReferenceEquals(a, b) a.Equals(b) El ==operador tiene como valor predeterminado ReferenceEquals, pero puede sobrecargarse para realizar en su Equalslugar.
Lisp común (eq a b) (equal a b)
Erlang a =:= b a == b cuando ayb son números
Ir a == b reflect.DeepEqual(*a, *b) cuando ayb son punteros
Java a == b a.equals(b)
JavaScript a === b a == b cuando ayb son dos objetos de cadena que contienen caracteres equivalentes, el operador === seguirá devolviendo verdadero.
OCaml , Smalltalk a == b a = b
Pascal a^ = b^ a = b
Perl $a == $b $$a == $$b cuando $ay $bson referencias a escalares
PHP $a === $b $a == $b cuando $ay $bson objetos
Pitón a is b a == b
Rubí a.equal?(b) a == b
Esquema (eq? a b) (equal? a b)
Rápido a === b a == b cuando ayb tienen tipo de clase
Visual Basic .NET a Is b o object.ReferenceEquals(a, b) a = b o a.Equals(b) Igual que C #
Objective-C ( Cocoa , GNUstep ) a == b [a isEqual:b] cuando ay bson punteros a objetos que son instancias deNSObject

Ruby a === bsuele significar "b es un miembro del conjunto a", aunque los detalles de lo que significa ser miembro varían considerablemente dependiendo de los tipos de datos involucrados. ===se conoce aquí como el operador de "igualdad de casos" o "subsunción de casos".

Ver también

notas y referencias