http://geo.mff.cuni.cz/~lh/OFY056
VÝRAZY
výrazy = operandy prokládané operátory, vyhodnocované podle priority operátorů Výrazy podle priority operátorů (od nejnižší priority) OPERANDY OPERÁTORY výraz = jednoduché výrazy a relační operátory (=, <>, >, >=, <, <=) jednoduchý výraz = + – členy (termy) a aditivní operátory (+, –, or, xor) členy = prvotní výrazy (faktory) a multiplikativní operátory (*, /, div, mod, and, shl, shr) prvotní výrazy = konstanty, identifikátory, zápisy funkce, not faktory, výrazy v závorkách aj. Operátory podle typu operandů a výsledku – aritmetické operátory (+, –, *, /, div, mod) – bitové operátory (not, and, or, xor, shl, shr) – logické operátory (not, and, or, xor) – řetězcové operátory (+) – relační operátory (=, <>, >, >=, <, <=; in) – adresní (@, ^) – množinové (+, *, –)
pro aritmetické operandy (integer, real) s aritmetickým výsledkem pro integer operandy s integer výsledkem pro boolean operandy s boolean výsledkem pro řetězcové operandy (char, string) s řetězcovým výsledkem pro jakékoliv (kompatibilní) operandy s boolean výsledkem pro operand jednoduchou proměnnou (@), resp. ukazatel (^) pro množinové operandy s výsledkem typu množina
Operátory podle počtu operandů – unární: not, +, –, @, ^; jinde i ~, ! zpředu, ! zezadu, ... – binární: +, –, *, /, div, mod, and, or, xor, 6 relačních + in; jinde (Fortran:) **, //, ==, /=, (C:) %, ==, !=, &, ^, |, &&, || – ternární: jinde ?: Příklad: Kde ještě jinde? V Gnuplotu – operátory po vzoru C a Fortranu – print 1+1, 2*2, 3**3, 1/2, 2%3, 0!, 2!, 4!, !0, 0<1, 0!=1, !0==1 Příklad: Aritmetické +, –, * –(–1) => 1 2 unární aritmetické operátory 0+1 => 1 1 binární aritmetický operátor, integer operandy 0.0+1, 0+1e0, 0.0+1.e0 => 1.0 alespoň jeden real operand Pro aritmetické operátory (OP) +, –, * platí: integer OP integer => integer výsledek real OP integer, integer OP real, real OP real => konverze operandu na real => real výsledek Priorita multiplikativních operátorů vyšší než aditivních, při stejné prioritě vyhodnocování zleva doprava 1+2+3+4 => (((1+2)+3)+4 => 10 1+2*3+4 => (1+(2*3))+4 => 11 Platnost aritmetických zákonů pro +, * = 1.797693134862320e+308 největší hodnota pro double počítačové epsilon pro double = 2.220446049250313e–016 – komutativní z.: 0+1.0 je totéž co 1.0+0 High(Integer)+1 je totéž co 1+High(Integer) 0*1.0 je totéž co 1.0*0 1e200*1e300 je totéž co 1e300*1e200 komutativní zákon platí – asociativní z.: (1e300*1e300)*1e–300 => +Inf (pokud se vyčíslí v přesnosti double) 1e300*(1e300*1e–300) => 1e300 (–1.0+1.0)+1e–16 => 1e–16 –1.0+(1.0+1e–16) => 0.0 (pokud se vyčíslí v přesnosti double) tedy v real výrazech kvůli omezenému rozsahu, omezené přesnosti a zaokrouhlování často asociativní zákon neplatí – nulový prvek: 0+i(nteger) => i, i+(–i) => 0 integer nula existuje (–0 je totéž) 0.0+r(eal) => r, r+(–r) => 0.0 real nulový prvek existuje (ale: –0.0 existuje také) – jednotkový prvek: 1.0*r(eal) => r, ale nemusí existovat s tak, že r*s => 1.0 (přesně)
http://geo.mff.cuni.cz/~lh/OFY056 Příklad: Řetězcové + ’0’+’1’ ’0.0’+’1.e0’ ’2’–’1’
=> ’01’ => ’0.01.e0’ => operator not applicable
Příklad: Množinové +, –, * [1,2] + [2,3] [1,2] * [2,3] [1,2,3] – [2]
=> [1,2,3] => [2] => [1,3]
Příklad: Operátor umocnění ** (Fortran) – vyhodnocování zprava doleva 2**3**2 => – umocnění má vyšší prioritu než unární +– –2**2 => (–2)**2 =>
2**(3**2)
=>
512
–4 4
Příklad: Operátory dělení Reálné dělení (v Pascalu /) vrací pro všechny kombinace integer a real operandů vždy real výsledek. Celočíselné dělení (v Pascalu div, v C i Fortranu /) si žádá operandy integer a vrací integer výsledek, podobně celočíselný zbytek po dělení (v Pascalu mod). Pascal, reálné dělení: 1/3, 1.0/3.0 => 0.3333333.... 1/3+1/3+1/3 => 1.0 1.0 div 3.0 => operator not applicable Fortran, C, integer dělení: 1/3+1/3+1/3 => 0 1./3+1/3+1/3 => 0.3333333 1./3+1/3.+1./3. => 1. 1/4*4 => 0 1/4*4. => 0. 1./4*4 => 1. I vyčíslení mocniny se záporným exponentem může vést k celočíselnému dělení: Fortran: 10**(–1) => 1/(10**1) => 0 10.**(–1) => 1/(10.**1) => 0.1 Zbytek po dělení Pascal: 5 mod 3 => 2 operátor mod Fortran: mod(5,3) => 2 standardní funkce mod C: 5%3 => 2 operátor % Příklad: Levý nebo pravý sloupec? Pascal: V:=4/3*pi*r*r*r Fortran: V=4/3*pi*r**3
nebo nebo
V:=r*r*r*4/3*pi V=r**3*4/3*pi
Příklad: Bitové operátory negace not: not 0 => –1, not 1 => –2, not –1 => 0 součin and: 1 and 2, 1 and 3, 1 and 4 součet or: 1 or 2, 1 or 3, 1 or 4 exkluzivní součet xor: 1 xor 2, 1 xor 3, 1 xor 4 posun doleva shl: 0 shl 1, 1 shl 1, 2 shl 1, 3 shl 1, 4 shl 1 posun doprava shr: 0 shr 1, 1 shr 1, 2 shr 1, 3 shr 1, 4 shr 1
http://geo.mff.cuni.cz/~lh/OFY056 Příklad: Logické operátory not (not true) true and false true or true, false or false true xor true, false xor false not true or not true and not false or not false Zkrácené vyhodnocování (short-circuit evaluation) logických výrazů {$B–}: ve výrazech false and X => false true or X => true se X nevyhodnocuje, při úplném vyhodnocování {$B+} se v těchto výrazech X vyhodnocuje. {$B–} (1>0) or (1/0>0) {$B+} (1>0) or (1/0>0)
=> true => ???
{$B–} if (a>0 and ln(a)>=0) then příkaz; {$B+} if (a>0 and ln(a)>=0) then příkaz;
=> vykoná příkaz pro a>=1, jinak nic => vykoná příkaz pro a>=1, nic pro 0>a>1, padne pro a<=0
{$B–} if (true or výraz_s_voláním_funkce) then; => funkce nebude volána {$B+} if (true or výraz_s_voláním_funkce) then; => funkce bude volána tj. volat při {$B–} funkce zleva od jednodušších po složitější Příklad: Relační operátory – aritmetické operandy (lze porovnávat integer s real) 0=1, 1.0<>2.0, 2>3.0, 3e0<=4, 0.0<>–0.0 => false, true, false, true, false – řetězcové operandy (porovnání ve smyslu ASCII kódů) ASCII kódy: mezera 32, ’0’ 48, ’@’ 64, ’A’ 65, ’Z’ 90, ’\’ 92, ’a’ 97, ’z’ 122 ’A’=’A’, ’A’<’B’, ’A’<’a’, ’A’<’A ’, ’99’<’A’ => true, true, true, true, true – množinové operandy je podmnožinou? [0]<=[1,2]+[2,3] => false [1]<=[1,3,2]–[2,3] => true je prvkem? 0 in [1,2,3] => false 1 in [1,2,3] => true relace mají nižší prioritu než logické operátory 1<2 and 3<4 => 1<(2 and 3)<4 => 1<2<4 => true < 4 => incompatible types
http://geo.mff.cuni.cz/~lh/OFY056
VÝRAZY – OPAKOVÁNÍ
Operátory (podle počtu operandů) – unární: not, +, –, @, ^; jinde i ~, ! zpředu, ! zezadu, ... – binární: +, –, *, /, div, mod, and, or, xor, 6 relačních + in; jinde (Fortran:) **, //, ==, /=, (C:) %, ==, !=, &, ^, |, &&, || – ternární: jinde (C:) ?: Příklad: Gnuplot – print 1+1, 2*2, 3**3, 1/2, 2%3, 0!, 2!, 4!, !0, 0<1, 0!=1, !0==1, !0=1 => 2 4 27 0 2 1.0 2.0 24.0 1 1 1 1 chyba – ternární operátor větvení: i=1; print i–1?2+2:3*3; i=2; print i–1?2+2:3*3 Příklad: Syntaktické diagramy a praxe – je správně +1? 1.0? 1.? .1? 1E0? – je správně +1+–1, –1– –1?
synt. diagr.: TTFFT synt. diagr.: FF
Delphi: TTTFT Delphi: TT
=> 9 4 Fortran: TTTTT Fortran: FF
Příklad: Booleovská algebra s operátory not, and a or/xor a b not a a and b a or b a xor b not a or b (=>) false false true false false false true false true –“– false true true true true false false false true true false true true –“– true true false true Platí též pro bitové 0/1 na místě false/true. Ovšem not 0 => –1, neboť bitově not 0000 => bitově 1111 => signed –1, unsigned 2**32–1. Fortran: not(0) => –1, dále iand( ), ior( ), ieor( ), ishft( ), ishftc( ). Gnuplot: !0 => 1, dále &, |, ^. Příklad: Priority Pascal vs. Fortran Pascal: 1<2 and 3<4 => 1<(2 and 3)<4 => 1<2<4 => true < 4 => incompatible types Fortran: 1<2.and.3<4 => (1<2).and.(3<4) => .true..and..true. => .true. V Pascalu multiplikativní and dříve než relace, ve Fortranu relace dříve než logické .and.. Standardní funkce a procedury konverzní funkce: aritmetické funkce: ordinální funkce: funkce pro práci s řetězci: náhodná čísla: dynamické proměnné:
Chr, Ord, Round, Trunc, UpCase Abs, ArcTan, Cos, Exp, Frac, Int, Ln, Pi, Sin, Sqr, Sqrt High, Low, Odd, Pred, Succ; procedury Dec, Inc Concat, Copy, Length, Pos; procedury Delete, Insert, Str, Val Random; procedura Randomize procedury New, Dispose, SetLength, Finalize
Provádějí se typové konverze argumentů: např. function ArcTan(X: Extended): Extended; může být volána s integer argumentem a proběhne konverze jako v přiřazovacím příkazu, volání ArcTan(1.0)*4.0 i ArcTan(1)*4 obojí vrátí pi (ve Fortranu by to byla katastrofa: typové konverze argumentu se neprovádějí!)
http://geo.mff.cuni.cz/~lh/OFY056
ULOŽENÍ CELÝCH ČÍSEL V POČÍTAČI
Obvyklý model „integer“ (tj. podmnožiny celých) čísel zahrnuje: buď nezáporná (unsigned) celá čísla: ∑k=1p fk x bk–1 nebo znaménková (signed) celá čísla: +(∑k=1p fk x bk–1) a – [(b–1) x bp – ∑k=1p fk x bk–1] kde 0 ≤ fk < b pro k = 1, ..., p pro unsigned integer a 0 ≤ fk < b pro k = 1, ..., p – 1, 0 ≤ fp < b – 1 pro signed integer. Pro standardní b = 2 a 0 ≤ fk < 2 jsou tedy unsigned integer 0, 1, ..., 2p–1 a signed integer –2p–1, –2p–1+1, ..., –1, 0, 1, ..., 2p–1–1 . Rozsah integer pro běžná p: p (počet bitů) 8 16 32 unsigned Byte 0..255 Word 0..65535 Longword 0..4 294 967 295 signed Shortint –128..127 Smallint –32768..32767 Longint –2147483648..2147483647 Běžný způsob uložení (p = 4): 0000 0001 0010 0011 ... 0111 1000 1001 1010 ... 1111 fk unsigned 0 1 2 3 ... 7 8 9 10 ... 15 signed 0 1 2 3 ... 7 –8 –7 –6 ... –1 vlastnost tohoto uložení p-bitového signed integer pomocí tzv. dvojkového doplňku: i + (– i) = 2p pro 0 < i < 2p–1 způsob vytvoření dvojkového doplňku: a) bitová negace (tzv. jednotkový doplněk), b) přičtení jedničky; př. 1 = 0001 => a) 1110 => b) 1111 = –1 7 = 0111 => a) 1000 => b) 1001 = –7
http://geo.mff.cuni.cz/~lh/OFY056
ULOŽENÍ REÁLNÝCH ČÍSEL V POČÍTAČI
Obvyklý model „real“ (tj. podmnožiny racionálních) čísel zahrnuje: {LaTeX: $s\times b^{e–bias}\times\sum_{k=1}^pf_k\times b^{–k}$} a) s x be–bias x ∑k=1p fk x b–k znaménko s = ±1 (e ukládáno jako kladný nezáporný integer) exponent e: emin ≤ e – bias ≤ emax (f1 nenulové) mantisa: 0 < f1 < b 0 ≤ fk < b pro k = 2, ..., p b) 0, ∞, chybové výsledky (kvůli uzavřenosti reálné aritmetiky) IEEE Standard 754-1985 – definuje formáty čísel s plovoucí desetinnou čárkou – předepisuje kritéria přesnosti pro základní operace a konverze – definuje chybové stavy a pravidla zaokrouhlování Formáty čísel podle IEEE 754 tj. 1 + 8 + (24 – 1) = 32 bitů single (4 B): b=2, bias=126, 0 < e < 255 = 28–1, p = 24, bity: 31/30...23/22..0 pro znaménko/exponent/mantisu (f1=1 se neukládá) přesnost v desítkové soustavě: 2–24 > 5 x 10–8, tedy cca 7 platných míst tj. 1 + 11 + (53 – 1) = 64 bitů double (8 B): b=2, bias=1022, 0 < e < 2047 = 211–1, p = 53, bity: 63/62...52/51..0 pro znaménko/exponent/mantisu (f1=1 se neukládá) přesnost v desítkové soustavě: 2–53 > 1 x 10–16, tedy cca 15 platných míst single extended (≥6 B): Delphi: Real48, ale na procesorech Intel nutno softwarově emulovat double extended (≥10 B): Delphi: Extended, na procesorech Intel dostupné hardwarově bity: 95..80/79/78..64/63/62..0 pro nevyužité bity/znaménko/exponent/explicitní f1/mantisu Př. největší single (f90: huge): 2128 x ∑k=124 (1/2)k = 3.40282366920938E38 x 9.99999940395355E-01 největší double: 21024 x ∑k=153 (1/2)k = 1.79769313486232E308 x [1.0–∑k=54∞ (1/2)k] nejmenší přesný kladný single (f90: tiny): 2–125 x (1/2)1 = 1.17549435082E–38 nejmenší možný kladný single: 2–125 x (1/2)24 = 1.40129846433E–45 127–126 1 x 1/2 => (0)(011 1111 1)(000 0000 0000 0000 0000 0000) = 3F800000 single +1.0: (–1)^0 x 2 single +2.0: (–1)^0 x 2128–126 x 1/21 => (0)(100 0000 0)(000 0000 0000 0000 0000 0000) = 40000000 single +0.1: (–1)^0 x 2126–126 x (1/24+1/25+1/28+...) = (–1)^0 x 2123–126 x (1/21+1/22+1/25+...) => (0)(011 1101 1)(100 1...) = 3DC(≥8)...., viz např. bitview.exe Pozor! V Pascalu je konstanta 0.1 typu double (nebo rovnou extended), tedy x:=x*0.1 zachová přesnost x, ať je x single nebo double. Ve Fortranu je konstanta 0.1 typu real(4), tedy single, a je-li x typu real(8), pak příkaz x=x*0.1 pokazí přesnost x na efektivních real(4). Nutno psát netriviální konstanty explicitně jako real(8), tedy x=x*0.1_8. Platí pro všechny konstanty, které nelze v real(4) vyjádřit přesně. Rozdělení možných hodnot formátu single – normální čísla: pro 0 < e < 255 => 2 x 254 x 223 = 224 x (28–2) = 232 – 225 – subnormální čísla: pro e = 0 a některé fk≠0, k=2,..,24 => 2 x (223–1) = 224 – 2 => 2 – nuly: pro e = 0 a všechna fk = 0 => 2 – nekonečna (INF): pro e = 255 a všechna fk = 0 => 2 x (223–1) = 224 – 2 – nečísla (NaN): pro e = 255 a některé fk≠0 tedy celkem 232 – 225 normálních čísel (nenulových a v plné přesnosti) 224 – 2 subnormálních čísel (příliš malých, nepřesných: podtečení, underflow) 2 znaménkové nuly (+0.0, –0.0) 2 znaménková nekonečna (+INF, –INF; po přetečení nebo dělení normálního čísla 0) 224 – 2 NaN (Not-a-Number; chybové výsledky po nesprávných operacích) celkem 232 možností Chybové stavy: overflow (přetečení: výsledkem operace příliš velké číslo, buď ±INF nebo ±huge) divide_by_zero (dělení normálního čísla 0, výsledkem ±INF) invalid (nesprávná operace nebo argumentem NaN, výsledkem NaN) underflow (podtečení: výsledkem operace nepřesné subnormální číslo nebo 0) inexact (výsledkem operace normální číslo, ale zaokrouhlené) Vlastnosti – násobení sčítáním exponentů a mantis, dělení odčítáním, jednoduché porovnávání velikosti