Relační operátor - Relational operator

Ve vědě o počítačích , je relační operátor je programovací jazyk konstrukt nebo provozovatel , že zkoušky nebo definuje nějaký druh vztahu mezi dvěma entitami . Patří mezi ně numerická rovnost ( např . 5 = 5 ) a nerovnosti ( např . 4 ≥ 3 ).

V programovacích jazycích, které obsahují v jejich typovém systému odlišný booleovský datový typ , jako je Pascal , Ada nebo Java , se tyto operátory obvykle vyhodnotí jako pravdivé nebo nepravdivé, v závislosti na tom, zda podmíněný vztah mezi těmito dvěma operandy platí nebo ne. V jazycích, jako je C , relační operátoři vracejí celá čísla 0 nebo 1, kde 0 znamená false a jakákoli nenulová hodnota znamená true.

Výraz vytvořené pomocí relační formy obsluhy, co se nazývá relační výraz nebo stavu . Relační operátory lze považovat za speciální případy logických predikátů .

Rovnost

Používání

Rovnost se používá v mnoha konstrukcích a datových typech programovacích jazyků. Používá se k testování, zda prvek již v sadě existuje , nebo k přístupu k hodnotě pomocí klíče. Používá se v příkazech switch k odeslání toku řízení do správné větve a během procesu sjednocení v logickém programování.

Jedním z možných významů rovnosti je, že „pokud se rovná b , pak lze buď a nebo b použít zaměnitelně v jakémkoli kontextu, aniž by si všiml rozdílu.“ Toto tvrzení ale nutně neplatí, zvláště když vezmeme v úvahu proměnlivost spolu s rovností obsahu.

Rovnost umístění vs. rovnost obsahu

Někdy, zejména v objektově orientovaném programování , vyvolává srovnání otázky datových typů a dědičnosti , rovnosti a identity . Často je nutné rozlišovat mezi:

  • dva různé objekty stejného typu, např. dvě ruce
  • dva objekty jsou stejné, ale odlišné, např. dvě bankovky 10 $
  • dva objekty jsou stejné, ale mají rozdílné zastoupení, např. účet v hodnotě 1 $ a mince v hodnotě 1 $
  • dva různé odkazy na stejný objekt, např. dvě přezdívky pro stejnou osobu

V mnoha moderních programovacích jazycích se k objektům a datovým strukturám přistupuje prostřednictvím odkazů . V takových jazycích je potřeba testovat dva různé typy rovnosti:

  • Rovnost umístění (identita): pokud dva odkazy (A a B) odkazují na stejný objekt. Interakce s objektem prostřednictvím A jsou nerozeznatelné od stejných interakcí prostřednictvím B a zejména změny objektu prostřednictvím A se odrážejí prostřednictvím B.
  • Rovnost obsahu: pokud jsou objekty odkazované dvěma odkazy (A a B) v určitém smyslu ekvivalentní:
  • Strukturální rovnost (tj. Jejich obsah je stejný). který může být buď mělký (testování pouze okamžitých částí), nebo hluboký (testování rovnosti částí součástí rekurzivně). Jednoduchého způsobu, jak toho dosáhnout, je reprezentativní rovnost: kontrola, zda mají hodnoty stejnou reprezentaci.
  • Některé další rovnosti šité na míru, zachování vnějšího chování. Například 1/2 a 2/4 jsou považovány za rovnocenné, pokud jsou považovány za racionální číslo. Možným požadavkem by bylo, že „A = B právě a jen tehdy, pokud všechny operace s objekty A a B budou mít stejný výsledek“, kromě reflexivity , symetrie a tranzitivity .

První typ rovnosti obvykle implikuje druhý (s výjimkou věcí, jako je ne číslo ( NaN ), které se jim nerovná), ale obrácení nemusí být nutně pravdivé. Například dva řetězcové objekty mohou být odlišné objekty (v prvním smyslu nerovné), ale obsahují stejnou posloupnost znaků (v druhém smyslu stejné). Další informace o tomto problému najdete v tématu identita .

Reálná čísla, včetně mnoha jednoduchých zlomků , nelze přesně vyjádřit aritmetikou s plovoucí desetinnou čárkou a může být nutné otestovat rovnost v rámci dané tolerance. Taková tolerance však může snadno narušit požadované vlastnosti, jako je tranzitivita, zatímco reflexivita se také rozbije: IEEE standard s plovoucí desetinnou čárkou vyžaduje, aby NaN ≠ NaN platilo.

Jiné programovací prvky, jako jsou vypočítatelné funkce, nemusí mít žádný smysl pro rovnost nebo rovnost, která je nepočítatelná. Z těchto důvodů definují některé jazyky výslovný pojem „srovnatelný“ ve formě základní třídy, rozhraní, znaku nebo protokolu, který se používá buď explicitně, deklarací ve zdrojovém kódu, nebo implicitně prostřednictvím struktury příslušného typu.

Porovnání hodnot různých typů

V JavaScriptu , PHP , VBScript a několika dalších dynamicky zadávaných jazycích se standardní operátor rovnosti vyhodnotí jako true, pokud jsou dvě hodnoty stejné, i když mají různé typy, takže číslo 4 je srovnatelné například s textovým řetězcem „4“ . Zadaný operátor rovnosti je často k dispozici také v těchto jazycích a vrací true pouze pro hodnoty se stejnými nebo ekvivalentními typy (v PHP 4 === "4"je false, i když 4 == "4"je true). U jazyků, kde může být číslo 0 interpretováno jako nepravdivé , může tento operátor zjednodušit věci, jako je kontrola nuly (jak x == 0by platilo pro x, které je buď 0 nebo „0“ pomocí operátoru rovnosti typu typu).

Objednávání

Větší a menší než porovnání nečíselných dat se provádí podle konvence řazení (například pro textové řetězce, lexikografické pořadí ), které mohou být zabudovány do programovacího jazyka a / nebo konfigurovatelné programátorem.

Pokud je žádoucí spojit číselnou hodnotu s výsledkem srovnání mezi dvěma datovými položkami, řekněme a a b , je obvyklá konvence přiřadit −1 pokud a <b, 0 pokud a = b a 1 pokud a> b. Například funkce C strcmpprovádí třícestné srovnání a vrací -1, 0 nebo 1 podle této konvence a qsort očekává, že srovnávací funkce vrátí hodnoty podle této konvence. U třídicích algoritmů je účinnost srovnávacího kódu rozhodující, protože je jedním z hlavních faktorů přispívajících k výkonu řazení.

Porovnání datových typů definovaných programátorem (datové typy, pro které programovací jazyk nemá vestavěné porozumění) lze provést vlastními psanými nebo knihovními funkcemi (jako je strcmpuvedeno výše), nebo v některých jazycích přetížením porovnání operátor - tj. přiřazení významu definovaného programátorem, který závisí na porovnávaných datových typech. Další alternativou je použití nějaké konvence, jako je členské srovnání.

Logická rovnocennost

Ačkoli je to na první pohled patrné, jako logické logické operátory XOR, AND, OR a NOT, relační operátory mohou být navrženy tak, aby měly logickou ekvivalenci , takže je lze všechny definovat navzájem. Následující čtyři podmíněné příkazy mají všechny logickou ekvivalenci E (buď všechny pravdivé nebo všechny nepravdivé) pro všechny dané hodnoty x a y :

To závisí na dobře uspořádané doméně .

Standardní relační operátoři

Níže jsou uvedeny nejběžnější numerické relační operátory používané v programovacích jazycích.

Společné relační operátory
Konvence rovná nerovná se větší než méně než větší
nebo rovno
menší
nebo rovno
V tisku = > <
FORTRAN .EQ. .NE. .GT. .LT. .GE. .LE.
ALGOL 68 = > <
/= >= <=
eq ne gt lt ge le
APL = > <
BASIC , ML , Pascal = <> > < >= <=
PŘÍUŠNICE = '= > < '< '>
Lua == ~= > < >= <=
C-jako == != > < >= <=
Erlang == /= > < >= =<
=:= =/=
Bourneovy granáty -eq -ne -gt -lt -ge -le
Dávkový soubor 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]

Ostatní konvence jsou méně časté: Common Lisp a Macsyma / Maxima používají operátory podobné Basic s výjimkou nerovnosti, která je /=v Common Lisp a #v Macsyma / Maxima. Starší Lisps používá equal, greaterpa lessp; a negoval je notpro zbývající operátory.

Syntax

Relační operátory se také používají v technické literatuře místo slov. Relační operátory jsou obvykle psány v infixové notaci , pokud jsou podporovány programovacím jazykem, což znamená, že se objevují mezi svými operandy (dva výrazy jsou příbuzné). Například výraz v Pythonu vytiskne zprávu, pokud je x menší než y :

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

Ostatní programovací jazyky, například Lisp , používají prefixový zápis následovně:

(>= X Y)

Řetězení operátora

V matematice je běžnou praxí řetězit relační operátory, například v 3 <x <y <20 (to znamená 3 <x a x <y a y <20). Syntaxe je jasná, protože tyto relační operátory v matematice jsou tranzitivní.

Mnoho nedávných programovacích jazyků by však vidělo výraz jako 3 <x <y sestávající ze dvou levých (nebo pravých) asociativních operátorů, které by jej interpretovaly jako něco podobného (3 < x) < y. Řekneme-li, že x = 4, dostaneme (3 < 4) < ya vyhodnocení dá, true < ycož obecně nedává smysl. Zkompilovává se však v C / C ++ a některých dalších jazycích, což přináší překvapivý výsledek (protože true by zde představovalo číslo 1).

Je možné dát výrazu x < y < zjeho známý matematický význam a některé programovací jazyky jako Python a Raku to dělají. Jiní, například C # a Java, to ne, částečně proto, že by se lišila od způsobu, jakým většina ostatních operátorů infix pracuje v jazycích podobných C. D programovací jazyk nedělá, protože udržuje určitou kompatibilitu s C, a „Povolení C výrazy, ale s jemně různé sémantiky (byť pravděpodobně správným směrem) by přidat více zmatku než pohodlí“.

Některé jazyky, například Common Lisp , používají k tomu více predikátů argumentů. V Lispu (<= 1 x 10)platí, když x je mezi 1 a 10.

Zmatek s operátory přiřazení

Brzy FORTRAN (1956–1957) byl omezen silně omezenými znakovými sadami, kde =byl k dispozici jediný relační operátor. Nebyly žádné <nebo >(a určitě žádné nebo ). To přinutilo návrháři definovat symboly, například .GT., .LT., .GE., .EQ.atd. A následně dělal to lákavé použít zbývající =znak pro kopírování, a to navzdory zjevné nesoudržnosti s matematickým použití ( X=X+1musí být nemožné).

Takto zavedené mezinárodní algebraické jazyky (IAL, ALGOL 58 ) a ALGOL (1958 a 1960) :=ponechávají standard =dostupný pro rovnost, konvence následovaná 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 ) a několik dalších jazyků.

B a C.

Tato jednotná de facto standardem u většiny programovacích jazyků byl nakonec změněn, nepřímo minimalistický sestavují jazyk s názvem B . Jeho jediným zamýšleným použitím bylo jako prostředek pro první port (tehdy velmi primitivního) Unixu , ale také se vyvinulo do velmi vlivného jazyka C.

B začínal jako syntakticky změněná varianta systémového programovacího jazyka BCPL , zjednodušená (a bez typická) verze CPL . V tom, co bylo popsáno jako proces „strip-dolů“, jsou andi orprovozovatelé BCPL byly nahrazeny &a |(který by později se stal &&i ||, resp.). Ve stejném procesu byl ALGOL styl :=BCPL nahrazen =v B. Důvod, proč to všechno bylo neznámé. Protože aktualizace proměnných neměly v B žádnou speciální syntaxi (například letnebo podobnou) a byly povoleny ve výrazech, tento nestandardní význam znaménka rovnosti znamenalo, že tradiční sémantika znaménka rovnosti nyní musela být spojena s jiným symbolem. Ken Thompson k tomu použil ==kombinaci ad hoc .

Když byl později zaveden malý typ systému, B se stal C. Popularita tohoto jazyka spolu s jeho spojením s Unixem vedla k tomu, že Java, C # a mnoho dalších jazyků následovaly, syntakticky, navzdory tomuto zbytečnému konfliktu s matematickým významem znaménko rovná se.

Jazyky

Přiřazení v C mají hodnotu a protože jakákoli nenulová skalární hodnota je v podmíněných výrazech interpretována jako true , je kód legální, ale má velmi odlišný význam od . Dřívější znamená fragment kódu „přiřadit y do x , a pokud je nová hodnota x není nula, spusťte následující příkaz“. Druhý fragment znamená „právě tehdy, když x se rovná y , provede následující příkaz“. if (x = y)if (x == y)

  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);
  }

Ačkoli Java a C # mají stejné operátory jako C, tato chyba obvykle způsobí chybu kompilace v těchto jazycích, protože podmínka if musí být typu booleana neexistuje žádný implicitní způsob převodu z jiných typů ( např . Čísel) na booleans. Takže pokud proměnná, která je přiřazena, nemá typ boolean(nebo typ obálky Boolean), dojde k chybě kompilace.

V jazycích podobných ALGOL, jako jsou Pascal, Delphi a Ada (v tom smyslu, že umožňují definice vnořených funkcí ), a v Pythonu a mnoha funkčních jazycích se operátory přiřazení mimo jiné nemohou objevit ve výrazu (včetně ifklauzulí), tedy vylučující tuto třídu chyb. Některé kompilátory, jako je GNU Compiler Collection (GCC), poskytují varování při kompilaci kódu obsahujícího operátor přiřazení uvnitř příkazu if, i když existují určitá legitimní použití přiřazení uvnitř podmínky if. V takových případech musí být přiřazení explicitně zabaleno do dvojice závorek, aby se zabránilo varování.

Podobně některé jazyky, například BASIC, používají =pro přiřazení a rovnost pouze symbol , protože jsou syntakticky oddělené (stejně jako u Pascal, Ada, Python atd. Se operátory přiřazení nemohou objevit ve výrazech).

Někteří programátoři mají ve zvyku psát srovnání s konstantou v opačném pořadí, než je obvyklé:

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

Pokud =je použit omylem, výsledný kód je neplatný, protože 2 není proměnná. Kompilátor vygeneruje chybovou zprávu, kterou lze nahradit správným operátorem. Tento styl kódování se nazývá levostranné srovnání neboli Yoda podmínky .

Tato tabulka uvádí různé mechanismy pro testování těchto dvou typů rovnosti v různých jazycích:

Jazyk Fyzická rovnost Strukturální rovnost Poznámky
ALGOL 68 a :=: b nebo a is b a = b kdy aa bjsou ukazatele
C , C ++ a == b *a == *b kdy aa bjsou ukazatele
C# object.ReferenceEquals(a, b) a.Equals(b) Tyto ==výchozí operátorovi ReferenceEquals, ale může být přetížen vykonávat Equalsmísto.
Společný Lisp (eq a b) (equal a b)
Erlang a =:= b a == b když a a b jsou čísla
Jít a == b reflect.DeepEqual(*a, *b) když a a b jsou ukazatele
Jáva a == b a.equals(b)
JavaScript a === b a == b když a a b jsou dva řetězcové objekty obsahující ekvivalentní znaky, operátor === stále vrátí true.
OCaml , Smalltalk a == b a = b
Pascal a^ = b^ a = b
Perl $a == $b $$a == $$b kdy $aa $bjsou odkazy na skaláry
PHP $a === $b $a == $b kdy $aa $bjsou objekty
Krajta a is b a == b
Rubín a.equal?(b) a == b
Systém (eq? a b) (equal? a b)
Rychlý a === b a == b když a a b mají typ třídy
Visual Basic .NET a Is b nebo object.ReferenceEquals(a, b) a = b nebo a.Equals(b) Stejné jako C #
Objective-C ( kakao , GNUstep ) a == b [a isEqual:b] kdy aa bjsou ukazatele na objekty, které jsou instancemiNSObject

Ruby obvykle a === bznamená „b je členem množiny a“, ačkoli podrobnosti toho, co znamená být členem, se značně liší v závislosti na použitých datových typech. ===je zde známý jako operátor „rovnost případů“ nebo „subsumpce případu“.

Viz také

Poznámky a odkazy