3. Datentypen, Ausdrücke und Operatoren ­ Programm muß i.a. Daten zwischenspeichern ­ Speicherplatz muß bereitgestellt werden, der ansprechbar, reserviert ist Ablegen & Wiederfinden ­ in höheren Programmiersprachen Arbeit mit bestimmten Speicherplätzen über Vergabe von Namen = Variable 3.1 Variable im Programm definierter Name für einen (beim Programmlauf) zu reservierenden Speicherplatz im Arbeitsspeicher für Werte eines bestimmten Typs Arbeit mit Variablen (Zuweisungen von Werten, Berechnungen) bedeutet Zugriff auf den zugehörigen Speicherplatz Deklaration in C: Beispiel: Variablentyp Variablenname; int i; Deklaration der integer­Variablen mit Namen i d.h. Bereitstellen von i.a. 4 Byte Speicherplatz (=32 bit) im Arbeitsspeicher i=3; Speicherung des Wertes 3=2^0+2^1(≙ 11 binär) auf dem reservierten Speicherplatz 1 000... ➘ ... ... i ...0011 Arbeitspeicher ­ in vielen höheren Programmiersprachen ist zur Reservierung eines Speicherplatzes, d.h. der Einführung einer neuen Variablen ein Variablentyp mit anzugeben ­ der Variablentyp sagt dem Compiler wieviel Speicherplatz benötigt wird und wie er zu strukturieren ist (zu interpretieren) 3.2 Elementare Datentypen ­ Es gibt drei qualitativ unterschiedliche Basistypen von Daten: ganze Zahlen, reelle Zahlen und alphanumerische Zeichen ­ Die Basistypen werden i.a. in eine Reihe von Untertypen ( die sogenannten elementaren Typen) aufgesplittet. ­ Die Bezeichnungen der Typen ist sprachabhängig, z.B. ganze Zahlen : int , long , short integer, longint, word INTEGER (in C) (in PASCAL) (in FORTRAN) reelle Zahlen : float, double real, extended REAL, DOUBLE (in C) (in PASCAL) (in FORTRAN) Zeichen : char CHARACTER (in C und in PASCAL) (in FORTRAN) (1) Integertypen in C: int short int long int kurz: short kurz: long Speicherbedarf: ­ Speicherplatz für int = Wortlänge des Rechners ­ heutzutage auf dem PC meist 4 Byte = 32 Bit ⇨ max. bzw. min. darstellbare Zahl: 32 Stellen = 32 Möglichkeiten für 0 oder 1 ⇨ 2^32 verschiedene Zahlen darstellbar Sinnvolle Möglichkeiten: (A) das erste Bit gleich 0 bedeutet positive Zahl 1 bedeutet negative Zahl alle anderen Bits repräsentieren den Betrag der ganzen Zahl Diese Darstellungsweise ist auf den ersten Blick sehr sympathisch, hat aber praktische Nachteile, besonders bei der Addition negativeR Zahlen. (B) Deshalb: Kodierung in sog. Zweierkomplementdarstellung Für negative ganze Zahlen bedeutet das: ­ Die Bitfolge der zugehörigen betragsgleichen positiven Zahl wird logisch negiert, d.h. aus jeder 0 wird eine 1 und aus jeder 1 wird eine 0. ­ Anschließend wird zu der so erhaltenen Zahl eine 1 addiert. Beispiel betrachten hier einen max. Umfang von 4 Bit: < C Typ short ⇨bei 32 Bit ist der Bereich: ­231 bis 231­1 231 negative Zahlen, 0 und 231–1 positive Zahlen Maximale Zahl = 231–1 ~ 2 Mio. Unterschiede zwischen long int, int, short int sind compilerabhängig (2) Gleitkomma­Typen Darstellung reeller Zahlen Typen in C: float ... einfache Genauigkeit double ... doppelte Genauigkeit Was bedeutet einfach, was bedeutet doppelt genau? Und was ist eigentlich eine Gleitkommazahl? ­ anderer Name: Maschinenzahl Festkommadarstellung z.B. : 321.45 Gleitkommadarstellung : 3.2145*102 bzw. 0.32145*103 Prinzipielles Problem: Da nur beschränkte Anzahl an Bytes zur Darstellung zur Verfügung steht, ist in der Regel eine genaue Darstellung nicht möglich. Irrationale Zahlen wie 2 oder die Eulersche Zahl e intern nie exakt darstellbar. aber auch viele andere nicht. ­ interne Darstellung im Rechner: x = (­1)v 0.m1 m2 mL 2p Vorzeichen Mantisse Basis + Exponent mi ... sind 0 oder 1, m1 = 1 p ... ist der Exponent (selbst wieder intern binär gespeichert), m p M (d.h. Beschränkt) v ... ist 0 oder 1 d.h. das Komma wird immer an der selben Stelle plaziert. Speicherplatz: Für die Codierung im Computer ist IEEE­Standard üblich ● für Gleitkommazahl in einfacher Genauigkeit: 4Byte = 32 Bit v e7 ... e0 m2 ... ... m24 Vorzeichenbit Exponent Mantisse m1 muß nicht gespeichert werden, da stets = 1 ● für Gleitkommazahl in doppelter Genauigkeit: 8Byte = 64 Bit v e10 ... ... e0 m2 ... ... ... ... ... m53 Vorzeichenbit Exponent Mantisse Typ Max. /pos. Min. Rel. Rechengenauigkeit eps float ~ 1038 / ~ 10­38 ~ 0.610­7 double ~ 10308 / ~ 10­308 ~ 1.110­16 z.B. MAXFLOAT ~ 2M , M = 27 = 128 2M = 2128 ~ 1038 ⇨Mantisse bestimmt die Rechengenauigkeit ⇨Exponent bestimmt den Wertebereich Grenzen der Maschinenzahlen: Unterlauf (underflow): |x| < eps Rundung x=0 Überlauf (overflow) |x| > MAX_Typ compilerabhängige Reaktion ­ Abbruch + Fehlermeldung ­ falsches Ergebnis ­ x=INF oder x=NaN Bei der Darstellung selbst einfachster Dezimalzahlen treten schon Rundungsfehler auf. Zusätzlich ergeben sich beim Rechnen weitere Rundungsfehler: Bei Addition zweier (positiver) Gleitkommazahlen werden folgende Einzelschritte ausgeführt: 1. Erkennen von Mantisse und Exponent beider Zahlen 2. Vergleichen der Exponenten 3. Angleichen der Exponenten 4. Anpassen der Mantisse der Zahl, deren Exponent bei der Exponentenanpassung verändert wurde 5. Addition der Mantissen, ggf. Änderung des gemeinsamen Exponenten (bei Überlauf der Mantisse) 6. Normalisierung des Ergebnisses (gleitendes Komma) Beispiel: Die Eulersche Zahl e = 2.71828182846 ... ist Grenzwert der Zahlenfolge a1 , a2 , a3 , .... an , ... mit an = (1 + 1/ n ) n Es gilt an < an+1 (Monotonie !) und an < e für alle natürlichen Zahlen n. Folglich erhält man (mathematisch betrachtet) mit wachsendem n einen immer besseren Näherungswert für e . (3) Textzeichentyp char reserviert (i.a.) 1 Byte = 8 Bit Speicherplatz für genau ein Zeichen (Erinnerung: z.B. ASCII­Code stellt Zeichen auf 8 Bit dar) ein erster abgeleiteter Variablentyp: Zeichenkette Aufeinanderfolge von Zeichen (z.B. Wörter) dargestellt und gespeichert als Feld des Typs char anderer Name: string Deklaration: char stringname[n]; dabei ist n die maximale Anzahl Zeichen, d.h. die Feldlänge ­ durch die Deklaration wird ein Block von n Byte Speicherplatz im Arbeitspeicher reserviert. ­ Achtung! Der Name stringname enthält dabei die Speicheradresse, an der die Zeichenkette im Arbeitspeicher beginnt (stringname ist ein sog. Zeiger) ­ Zugriff auf die Komponenten, also die einzelnen Zeichen durch stringname[i] wobei der Index i das i­1 . Zeichen der Zeichenkette bezeichnet, da in C die Numerierung bei 0 beginnt! z.B. char str[5]="INFO"; str ➘ I N F O \0 1012 1013 1014 1015 1016 1017 ... str[0] str[1] str[2] str[3] Endezeichen str enthält die Adresse 1015 str[0] = 'I', str[1]='N' , ... ­ gespeichert wird natürlich jedes Zeichen in seiner Binärdarstellung! ­ es muß stets ein Byte Platz für das Endezeichen eingerechnet werden, sonst kann es zu Problemen führen Erreichen des Endezeichens kann z.B. in einer Schleifenanweisung durch i=0; while (str[i]!=0) { tue etwas i=i+1; } abgefragt werden. ­ Achtung! Zuweisung eines ganzen Wortes nur in der Deklaration erlaubt danach nur noch Zugriff auf Einzelkomponenten möglich (4) leerer Typ void sinnvoll z.B. Für Funktionen ohne Ergebniswert (sog. Prozeduren oder Subroutinen) aus diesen Grundtypen lassen sich dann beliebig komplexere Typen selbstdefinieren (dazu mehr in der 4. Vorlesung) 3.3 Ausdrücke und Operatoren Ein Ausdruck ist eine Aneinanderreihung von Zahlen, Strings und Operatoren, die sich zu einem Wert auflösen lassen, sprich: eine mehr oder weniger komplexe Rechenvorschrift ⇨Ausdrücke können über Operatoren miteinander verknüpft werden ⇨Ausdrücke können Variablen zugewiesen werden Operatoren: es gibt grundsätzlich unäre, binäre und terniäre Operatoren z.B.: (1) unäre Operatoren: (in C) Inkrementoperator ++ausdruck ausdruck++ Dekrementoperator ­­ausdruck ausdruck­­ (2) binäre Operatoren: arithmetische Grundoperationen + , ­ , * , / (in allen Programmiersprachen) (3) terniäre Operatoren: eher selten in C z.B. Ausdruck1 ? Ausdruck2 : Ausdruck3 ist Ausdruck 1 wahr so berechne Audruck2 sonst berechne Ausdruck3 Zuweisung: (binärer Operator) Variablenname = Ausdruck ­ eine Zuweisung ist selbst wieder ein Ausdruck ­ die Zuweisung hat den Wert, der der Variablen zugewiesen wird Vergleiche und logische Operatoren Vergleiche Symbolik fürVergleiche in Programmiersprachen ähnlich der aus der Mathematik bekannten: < , > ≤ ... <= ≥ ... >= = ... == doppeltes Gleichheitszeichen, da '=' der Zuweisung entspricht allgemein ist die Syntax: Ausdruck Vergleichsoperator Ausdruck ­ liefert wieder einen Ausdruck ­ dieser Ausdruck hat einen int­Wert, und zwar 0 , falls der Vergleich nicht zutrifft 1, falls der Vergleich zutrifft Logische Operatoren Aussagenlogisches UND Symbolik: && .and. & ODER || .or. | VERNEINUNG ! .not. ~ (in C) (in FORTRAN) (in MATLAB) Ausdruck logischer Operator Ausdruck ­ liefert wieder einen Ausdruck ­ dieser Ausdruck hat einen int­Wert, und zwar 0 , falls der Gesamtausdruck wahr 1, falls der Gesamtausdruck falsch ist Anweisungen ­ sind in der jeweiligen Programmiersprache erlaubte Ausdrücke, die zeilenweise in den Programmen geschrieben werden (oder durch entsprechende Zeichen voneinander abgegrenzt, z.B. ein Komma in FORTRAN oder in MATLAB) ­ möglicherweise prinzipiell durch ein Zeichen abgeschlossen werden in C: Ausdruck ; Priorität von Operatoren (von höchster zu niedrigster Priorität) Symbol Name/Bedeutung Assoziativität ----------------------------------------------------------------++ Erhöhung nach Auswertung von links nach rechts -Erniedrigung nach Auswertung ( ) Funktionsaufruf [ ] Arrayelement -> Zeiger auf Strukturfeld . Felder einer Struktur oder Union ----------------------------------------------------------------++ Erhöhung vor Auswertung von rechts nach links -Erniedrigung vor Auswertung ! logisches NOT unäres Minus + unäres Plus & Adresse von * Dereferenzierung sizeof Größe in Bytes (type) Typumwandlung (cast) ----------------------------------------------------------------* / Multiplikation Division von links nach rechts % Divisionsrest (modulo) ----------------------------------------------------------------+ Addition von links nach rechts Subtraktion ----------------------------------------------------------------< kleiner als von links nach rechts <= kleiner oder gleich > größer als >= größer oder gleich ----------------------------------------------------------------== gleich von links nach rechts != ungleich ----------------------------------------------------------------&& logisches AND von links nach rechts ----------------------------------------------------------------|| logisches OR von links nach rechts ----------------------------------------------------------------? : Bedingung von rechts nach links ----------------------------------------------------------------= Zuweisung von rechts nach links *= zusammengesetzte Zuweisung /= %= += -= <<= >>= &= ^= |= ----------------------------------------------------------------, Komma-Operator von links nach rechts ----------------------------------------------------------------- Typumwandlung nötig, falls in einer Operation Operanden verschiedenen Typs beteiligt sind ● implizite Typumwandlung: durch den Compiler z.B. int i=1, k=3; float x; x = i*k; int*int liefert int, in der Zuweisung Umwandlung intfloat ● explizite Typumwandlung: durch einen cast­Operator z.B. float y = 6.78; i = 3 + (int) y;