Primitive Datentypen in Haskell

Ähnliche Dokumente
2.5 Primitive Datentypen

Primitive Datentypen und Felder (Arrays)

Informationsdarstellung 2.2

Abschnitt 2: Daten und Algorithmen

Intensivübung zu Algorithmen und Datenstrukturen

Einheit Datentypen in der Programmiersprache C Schwerpunkt: Elementare (arithmetische) Datentypen

Kapitel 3. Grunddatentypen, Ausdrücke und Variable

Operatoren und Ausdrücke

Inhaltsangabe 3.1 Zahlensysteme und Darstellung natürlicher Zahlen Darstellung ganzer Zahlen

Kapitel 5: Darstellung von Daten im Rechner

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 12/13. Kapitel 3. Grunddatentypen, Ausdrücke und Variable

Informationsmenge. Maßeinheit: 1 Bit. 1 Byte. Umrechnungen: Informationsmenge zur Beantwortung einer Binärfrage kleinstmögliche Informationseinheit

2.1 Fundamentale Typen

Kapitel 4. Programmierkurs. Datentypen. Arten von Datentypen. Wiederholung Kapitel 4. Birgit Engels, Anna Schulze WS 07/08

Rechnerstrukturen, Teil 1. Vorlesung 4 SWS WS 15/16

Binäre Darstellung ganzer Zahlen

2 Repräsentation von elementaren Daten

Projekt 3 Variablen und Operatoren

Java I Vorlesung Imperatives Programmieren

JAVA-Datentypen und deren Wertebereich

Crashkurs Haskell Mentoring WiSe 2016/17. Anja Wolffgramm Freie Universität Berlin

Java Einführung VARIABLEN und DATENTYPEN Kapitel 2

Praktische Informatik II FSS 2012 Programmierklausur

Einführung in die Informatik I

Zahlensysteme und Kodes. Prof. Metzler

Kapitel 5: Daten und Operationen

3. Datentypen, Ausdrücke und Operatoren

Tutoraufgabe 1 (Zweierkomplement): Lösung: Programmierung WS16/17 Lösung - Übung 2

Einstieg in die Informatik mit Java

Rückblick. Zahlendarstellung zu einer beliebigen Basis b. Umwandlung zwischen Zahlendarstellung (214) 5 = (278) 10 =(?) 8

Programmierung WS12/13 Lösung - Übung 1 M. Brockschmidt, F. Emmes, C. Otto, T. Ströder

Rückblick. Addition in der b-adischen Darstellung wie gewohnt. Informatik 1 / Kapitel 2: Grundlagen

Kapitel 05. Datentypen. Fachgebiet Knowledge Engineering Prof. Dr. Johannes Fürnkranz

Die einfachsten Anweisungen

Basiskonstrukte von Haskell

Dipl.-Ing. Halit Ünver Datenbanken/Künstliche Intelligenz FAW/n. Zahlensysteme

Einstieg in die Informatik mit Java

Beispiele elementarer Datentypen Ganze Zahlen (integer) Unterbereiche Gleitkommazahlen Festkommazahlen

Kapitel 2: Python: Ausdrücke und Typen. Grundlagen der Programmierung 1. Holger Karl. Wintersemester 2016/2017. Inhaltsverzeichnis 1

HaDePrak WS 05/ Versuch

Die Zahl ist: (z 2, z 1, z 0 ) (z ) : 7 = 0 Rest z 2

Kapitel 3: Variablen

4. Zahlendarstellungen

Elementare Konzepte von

Datentypen: integer, char, string, boolean

Fehlererkennende und fehlerkorrigierende Codes

II. Grundlagen der Programmierung

Inhalt. Zahlendarstellungen

Vorsichtige Programmierer verwenden Inkrement- Operatoren nicht in komplizierteren Ausdrücken

Zahlensysteme: Oktal- und Hexadezimalsystem

5.1 Mehr Basistypen. (Wie viele Werte kann man mit n Bit darstellen?)

Repräsentation von Daten Binärcodierung von rationalen Zahlen und Zeichen

Musterlösung zur 2. Aufgabe der 4. Übung

Institut für Programmierung und Reaktive Systeme. Java 2. Markus Reschke

2.Vorlesung Grundlagen der Informatik

Übung Praktische Informatik II

Programmierkurs C++ Variablen und Datentypen

Informatik I (D-MAVT)

Rechnergrundlagen SS Vorlesung

Zahlensysteme. Digitale Rechner speichern Daten im Dualsystem 435 dez = binär

5 Zahlenformate und deren Grenzen

Tag 2 Repetitorium Informatik (Java)

Programmierkurs Python I

Motivation und Überblick

Langzahlarithmetik implementieren Ac 1990 bis 2016

2 ARITHM. UND LOG. AUSDRÜCKE ZAHLEN

Institut für Programmierung und Reaktive Systeme 20. November Programmieren I. 4. Übungsblatt

Das Rechnermodell - Funktion

Noch für heute: primitive Datentypen in JAVA. Primitive Datentypen. Pseudocode. Dezimal-, Binär- und Hexadezimalsystem. der logische Typ boolean

2.1 Java. Er fand jedoch heraus, dass es bereits eine Programmiersprache mit dem Namen Oak gab.

Algorithmen & Programmierung. Felder (2) Zeichenketten

Anleitung zum Ausführen der vier Grundrechenarten mit dem russischen Abakus ( Stschoty )

Rechnergrundlagen SS Vorlesung

8 Typwandlungen. 8.1 Automatische Typkonvertierungen

ALGEBRA Lineare Gleichungen Teil 1. Klasse 8. Datei Nr Friedrich W. Buckel. Dezember 2005 INTERNETBIBLIOTHEK FÜR SCHULMATHEMATIK

Java-Applikationen (Java-Programme)

Programmieren in Haskell Einstieg in Haskell

Grundlagen der Informatik Ergänzungen WS 2007/2008 Prof. Dr. Rainer Lütticke

Algorithmen und Programmieren 1 Funktionale Programmierung - Musterlösung zu Übung 1 -

Prinzip 8 der von-neumann Architektur: (8) Alle Daten werden binär kodiert

Programmieren in Haskell

Abschnitt 11: Korrektheit von imperativen Programmen

Übungsblatt 1. Java Vorkurs (WS 2017)

Zahlen im Computer (Klasse 7 Aufbaukurs Informatik)

float: Fließkommazahl nach IEEE 754 Standard mit 32 bit

Wandeln Sie die folgenden Zahlen in Binärzahlen und Hexadezimalzahlen. Teilen durch die Basis des Zahlensystems. Der jeweilige Rest ergibt die Ziffer.

Programmierkurs Python I

Mathematik 1 -Arbeitsblatt 1-4: Rechnen mit Brüchen. 1F Wintersemester 2012/2013 Unterlagen: LehrerInnenteam GFB RECHNEN MIT BRÜCHEN

6 Ü B E R S E T Z U N G E N U N D C O D I E R U N G E N. 6.1 von wörtern zu zahlen und zurück Dezimaldarstellung von Zahlen Num 10

Einführung in die Programmiertechnik

Es ist für die Lösung der Programmieraufgabe nicht nötig, den mathematischen Hintergrund zu verstehen, es kann aber beim Verständnis helfen.

Schleifeninvarianten. Dezimal zu Binär

Java Kurs für Anfänger Einheit 2 Datentypen und Operationen

Variablen, Konstanten und Datentypen

Inhalt. 2.1 Darstellung von Zahlen. 2.2 Darstellung von Zeichen. 2.3 Boolesche Algebra. 2.4 Aussagenlogik. Informatik 1 / Kapitel 2: Grundlagen

Übungen zu Algorithmen

D A T E N... 1 Daten Micheuz Peter

Basisinformationstechnologie I

2 Darstellung von Zahlen und Zeichen

Transkript:

Primitive Datentypen in Haskell Der Datentyp Bool Der Datentyp Bool dient zur Beschreibung von Wahrheitswerten und zum Rechnen mit solchen Werten. Bool hat nur zwei mögliche Werte True und False. Als Operationen sind die Negation not sowie Konjunktion && und Disjunktion vordefiniert, wobei letztere als echte zweistellige Operationen in Infix-Notation anzuwenden sind oder alternativ als Funktionen ( ), (&&) :: Bool -> Bool -> Bool verwendet werden können. Wie in der Aussagenlogik bindet die Konjunktion stärker als die Disjunktion, d.h. im Ausdruck (x && y) z kann man auf die Klammern verzichten aber der Ausdruck (x y) && z würde ohne Klammern eine andere Bedeutung erhalten. Der Datentyp Bool tritt bei der Auswertung von Bedingungen auf, vor allem als Rückgabetyp von Vergleichsoperationen wie z.b. i <= n oder k == n auf. Der Datentyp Int Der Datentyp Int ist der Standardtyp zur Darstellung von (positiven und negativen) ganzen Zahlen. Darstellbar sind alle Zahlen aus dem Bereich [ 2 31, 2 31 1]. Für Anwendungen, bei denen dieser Bereich überschritten werden könnte, sollte man den Datentyp Integer verwenden. Da einige Effekte, die bei der Verwendung von Int auftreten, nur durch genauere Kenntnisse der internen Darstellung von ganzen Zahlen zu verstehen sind, stellen wir dieses Thema an den Anfang unserer Betrachtungen. Darstellung negativer Zahlen Wie wir bereits wissen, kann man mit n Bits jede natürliche Zahl aus dem Bereich von 0 bis 2 n 1 darstellen. Zur Darstellung negativer Zahlen wird ein zusätzliches Bit verwendet, das man üblicherweise wie ein Minuszeichen an den Anfang der Darstellung stellt. Bei insgesamt n-bits bleiben also noch n 1 Bits für die Darstellung positiver Zahlen womit der Bereich von 0 bis 2 n 1 1 abgedeckt werden kann. Für die Darstellung einer negativen Zahl z kann man die folgenden Ideen verwenden: Naiver Ansatz: Mit einer 1 im Vorzeichenbit wird ein Minus codiert, die verbleibenden Bits dienen zur Codierung des Betrags von z. 1 Komplement: Man codiert zuerst die positive Zahl z = z mit einer Null im Vorzeichenbit und bildet dann das Komplement dieser Darstellung, d.h. alle Bits b werden durch ihr Gegenteil (Komplement) b ersetzt, insbesondere wird das Vorzeichenbit zur 1. 2 Komplement: Das Vorzeichenbit steht für 2 n 1 und alle anderen Bits haben die übliche Bedeutung wie bei der Darstellung einer positiven Zahl, d.h. eine Folge

von n Bits b n 1 b n 2... b 1 b 0 ist die Darstellung der Zahl z = b n 1 2 n 1 + b n 2 2 n 2 +... + b 1 2 + b 0 Obwohl die dritte Variante zunächst als ein unnötig komplizierter Ansatz erscheint, wird sie sehr häufig verwendet, insbesondere liefert sie die Darstellung für den Haskell- Datentyp Int. Genauer gesagt werden in Haskell Zahlen des Typs Int mit 32 Bits dargestellt und daraus ergibt sich [ 2 31, 2 31 1] als darstellbarer Bereich. Bei der Suche nach Gründen, die gegen die ersten zwei Varianten sprechen, fällt zuerst auf, dass die Zahl 0 keine eindeutige Darstellung hat. Das 2 Komplement hat aber einen weiteren Vorteil, der erst bei genauerer Betrachtung der Addition zu Tage tritt. Berechnung der 2 Komplement Darstellung von negativen Zahlen Wir beschäftigen uns zuerst mit der Frage, wie man aus der Darstellung einer positiven Zahl z die Darstellung von z im 2 Komplement bestimmen kann. Man verfährt dazu nach der folgenden Regel, die auch gleichzeitig eine Erklärung dafür gibt, warum diese Darstellung als Komplement bezeichnet wird: Bilde zuerst das 1 Komplement von z und addiere dazu eine 1. Zuerst kann man sich leicht davon überzeugen, dass 0 nach dieser Regel die gleiche Darstellung wie die 0 hat, denn das Komplement der Darstellung von 0 ist 11... 11 und durch Addition von 1 ergibt sich eigentlich 100... 00, aber die führende 1 ist nur ein Übertrag auf eine nicht vorhandene Stelle, d.h. sie fällt aus der Darstellung heraus und übrig bleibt 00... 00. Die Dartellung von 1 ergibt sich aus 11... 110 plus 1, also 11... 111, und man kann leicht nachrechen, dass das mit der Definition des 2 Komplements übereinstimmt. Zur Überprüfung des allgemeinen Falles z 1 ignorieren wir zunächst das Vorzeichenbit b 31 sehen wir uns die Bitfolge b 30 b 29... b 1 b 0 aus der Darstellung von z an. Sei u die durch b 30 b 29... b 1 b 0 dargestellte, positive Zahl. Da die Addition dieser beiden Bitfolgen die Folge 11... 111 ergibt, gilt offensichtlich z + u = 2 31 1 und damit u + 1 = 2 31 z. Addiert man also nach obiger Regel zum 1 Komplement von z noch eine 1, wird mit den hinteren Stellen die positive Zahl u + 1 repräsentiert und das Vorzeichnenbit b 31 ist 1. Der Wert dieser Darstellung im 2-Komplement ist somit 2 31 + (u + 1) = 2 31 + (2 31 z) = z. Addition von Zahlen in 2 Komplement Darstellung Der Vorteil des 2 Komplements liegt darin, dass man die übliche Additionsmethode auch zur Addition eines positiven und eines negativen Summanden verwenden kann, während man bei den anderen Darsetllungen Fallunterscheidungen für die auszuführenden Operationen machen muss. Beim 2 Komplement reicht eine Fallunterscheidung in der Beweisfürung aus.

Fall 1: Angenommen a b 0 sind ganze Zahlen und es ist die Summe von a und b im 2 Komplement zu bestimmen. Dann ist in der Darstellung a 31 a 30... a 1 a 0 von a das Bit a 31 = 0 und die restlichen Bits stellen die positive Zahl a dar. In der Darstellung c 31 c 30... c 1 c 0 von b ist das Bit c 31 = 1 und die restlichen Bits stellen die positive Zahl c = 2 31 b dar. Bei der Addition der hinteren 31 Bits entsteht wegen a + c = a + (2 31 b) = 2 31 + (a b) 2 31 die Darstellung von a b und eine 1 im Überlaufbit, das zu a 31 + c 31 addiert wird und damit eine 0 im Vorzeichenbit erzeugt. Der Überlauf aus der Addition der Vorzeichenbits wird ignoriert und das Ergebnis ist wie beabsichtigt die Zahl a b. Fall 2: Angenommen b > a 0 sind ganze Zahlen und es ist die Summe von a und b im 2 Komplement zu bestimmen. Dann ist in der Darstellung a 31 a 30... a 1 a 0 von a das Bit a 31 = 0 und die restlichen Bits stellen die positive Zahl a dar. In der Darstellung c 31 c 30... c 1 c 0 von b ist das Bit c 31 = 1 und die restlichen Bits stellen die positive Zahl 2 31 b dar. Bei der Addition der hinteren 31 Bits entsteht wegen a + c = a + (2 31 b) = 2 31 + (a b) < 2 31 die Darstellung von 2 31 + (a b) und eine 0 im Überlaufbit, das zu a 31 + c 31 addiert wird und damit eine 1 im Vorzeichenbit erzeugt. Der Wert des Ergebnisses ist wie beabsichtigt die Zahl 2 31 + (2 31 + (a b)) = a b. Durch weitere Fallunterscheidungen kann man sich auch davon überzeugen, das Additionen von zwei positiven bzw. von zwei negativen Zahlen korrekt ausgeführt werden, solange das Ergebnis im darstellbaren Bereich liegt. Achtung: Liegt das Ergebnis einer Additionen von zwei positiven Zahlen nicht mehr im darstellbaren Bereich, so entsteht eine 1 im Vorzeichenbit und damit ein negatives Ergebnis. Ähnlich führt die Addition von zwei negativen Zahlen bei Überschreitung des darstellbaren Bereichs zu einem positiven Ergebnis. Wenn man diese unerwünschten Effekte vermeiden will, muss man zum Datentyp Integer wechseln, bezahlt das aber durch Laufzeitverluste. Die Funktionen div und mod Für die ganzzahlige Division sind die Funktionen div, mod :: Int -> Int -> Int vordefiniert. Im Gegensatz zur Programmiersprache Java stimmt die Haskell-Implementierung dieser Funktionen mit der mathematischen Definition überein, d.h. sie realisieren die Ausaage des folgenden Satzes. Satz: Für beliebige Zahlen n, d Z mit d > 0 existieren eindeutig bestimmte Zahlen q, r Z, so dass folgende Bedingungen erfüllt sind n = q d + r und r {0, 1,..., d 1} Man nennt q den ganzzahligen Quotienten und r den Rest aus n und d. Der Aufruf div n d berechnet q und der Aufruf mod n d berechnet r. In mathematischen Texten

verwendet man n für q und n mod d für r. d Welchen Wert mod für negative Werte von n liefern sollte, kann man sich am Beispiel n = 17 und d = 5 überlegen. Man beginnt mit dem positiven Fall n = 17, also 17 = 3 5+2 und multipliziert beide Seiten mit 1. In der Gleichung 17 = ( 3) 5+( 2) ist der Rest aber nicht aus der zuläsigen Menge {0, 1, 2, 3, 4}. Man korrigiert das durch Addition und Subtraktion einer 5, wobei die subtrahierte 5 dem Produkt zugeschlagen wird:. 17 = ( 3) 5 + ( 2) + 5 5 = ( 4) 5 + 3 folglich ist q = 4 und r = 3 Der Datentyp Float Der Datentyp Float ist der Standardtyp zur Darstellung von rellen Zahlen. Natürlich kann man mit einer beschränktem Anzahl von Bits nicht alle reellen Zahlen darstellen, man kann nur eine beschränkte Genauigkeit erreichen und auch nicht beliebig große Zahlen darstellen. Häufig gibt man die die Zahlen in der einfachen Notation mit einem Dezimalpunkt an, wie z.b.: 0.432-332.675 0.00967 Liegt der Dezimalpunkt aber sehr weit rechts (bei sehr großen Zahlen) oder stehen am Anfang sehr viele Nullen (bei Zahlen mit sehr kleinem Betrag), bietet sich auch die sogennante wissenschaftliche Notation an: 45.675e5 = 45.675 10 5 = 4 567 500-1.564e6 = 1.564 10 6 = 1 564 000 23.67e-6 = 23.67 10 6 = 0.000 023 67 Die wichtigsten Standardfunktionen wie Quadratwurzel sqrt, Exponential- und Logarithmusfunktion exp, log, Winkelfunktionen sin, cos,tan und die Betragsfunktion abs sind als Funktionen von Float nach Float implementiert. Dazu kommen die Funktionen floor, ceiling :: Float -> Int, die für einen gegeben Float-Wert r die größte bzw. kleinste ganze Zahl ausgeben die r bzw. r ist. Da die Operationen +, und sowohl für den Int- als auch für den Float-Typ definiert sind, muss der Interpreter durch Typanalyse feststellen, welcher Operationstyp zur Ausführung kommt. Deshalb ist es auch nicht möglich, einen Int- und einen Float- Wert zu addieren. Um dieses Problem zu umgehen, kann man vorher die Funktion fromintegral zur Typangleichung verwenden. Es ist zu beachten, dass die Eingabe einer ganzen Zahl ohne Dezimalpunkt wie z.b. 2543 bei Bedarf auch als Float-Wert interpretiert wird.

Beispiel: 3.5 + 4 7.5 3.5 + floor 4.5 ERROR - Unresolved overloading 3.5 + fromintegral (floor 4.5) 7.5 Der Datentyp Char Mit dem Datentyp Char werden Zeichen beschrieben, die man auf der Tastatur finden kann oder die in einer normalen Textzeile angezeigt werden können. Haskell verwendet zur internen Darstellung von Zeichen den Unicode, einen 16-Bit-Code. Wir werden uns in der Regel aber mit einem sehr kleinen Teil dieses Codes begnügen, den ASCII- Zeichen. American Standard Code for Information Interchange (ASCII) Dieser Code ist schon relativ alt und wurde in den frühen Zeiten der Datenfernübertragung entwickelt. Es ist ein 7-Bit-Code bei dem ein achtes Bit als Prüfbit (Paritätsbit) verwendet wurde. Da die 128 darstellbaren Zeichen nicht ausreichten, um auch Umlaute oder andere Sonderzeichen aus dem skandinavischen Sprachraum aufzunehmen, wurde später das achte Bit zur Erweiterung auf 256 Zeichen verwendet, unter anderem entstand so der Code Latin1. Da aber auch diese Erweiterungen nicht einmal für alle europäischen Sprachen und schon gar nicht für chinesische und japanische Schriftzeichen ausreichten, wurde mit dem sogenannte Unicode eine wesentlich größere Erweiterung entwickelt. Unicode Der Unicode wurde ursprünglich als 16-Bit-Code konzipiert mit dem man 65536 Zeichen darstellen kann, aber bald zeigte sich, dass diese Zahl nicht für alle Schriftzeichen der Welt verbreiteten Sprachen ausreicht. Deshalb entschloss man sich, diesen Bereich um 16 weitere Bereiche der gleichen Göße aufzustocken. Da der ASCII-Standard schon weltweit verbreitet war, wurden die ersten 128 Zeichen des Unicodes für die ASCII-Zeichen reserviert. Für die Arbeit mit dem Datentyp Char in Haskell spielt die Dualität zwischen Zeichen und Zahl eine entscheidende Rolle: Jedes 16- Bit-Tupel kann sowohl als Zeichen als auch als Binärzahl interpretiert werden. Hier sind die wichtigsten Fakten, die man zu diesem Thema wissen sollte. Um die im Folgenden besprochenen Funktionen verwenden zu können, muss (für alle neueren Hugs-Versionen) das Modul Char.hs geladen werden. Das geschieht durch die Anweisung import Char in der.hs Datei, die diese Funktionen verwendet oder bei einfachen Testbeispielen auf der Hugs Kommandozeile durch :l Char. 1. Zur Übersetzung von Zeichen in Zahlen und von Zahlen in Zeichen gibt es die Fuktionen ord :: Char -> Int

chr :: Int -> Char 2. Dadurch wird auch eine Ordnung auf Char definiert, die mit der lexikalischen Ordnung unseres Alphabet übereinstimmt, insbesondere bilden die Großbuchstaben einen zusammenhängenden Abschnitt von 65 bis 90, ebenso wie die Kleinbuchstaben von 97 bis 122 und die Ziffern von 48 bis 57. 3. Um Zeichen, also Elemente von Char, von Namen für Variable oder Funktionen zu unterscheiden, werden sie in Hochkommata eingefasst, wie z.b. a, X oder 3. Man kann Zeichen aber auch mit einem backslash und ihrer Nummer angeben, wie z.b. \51 für 3. 4. Man kann diese Umrechnungen auch nutzen, um einige der in Char.hs vordefinierten Funktionen oder Abwandlungen davon selbst zu implementieren. Als Beispiel betrachten wir die Funktion toupper :: Char -> Char mit der Kleinbuchstaben in die entsprechenden Großbuchstaben umgewandelt werden: offset :: Int -- Verschiebeabstand der Bloecke, ist ein Int-Wert offset = ord A - ord a -- Wert kann jetzt verwendet werden toupper ch = chr (ord ch + offset) 5. In Char.hs sind auch schon die Ordnungsrelationen <, <=, >, >= vordefiniert, man muss also nicht den Umweg über die Funktion ord gehen, um Zeichen vergleichen zu können. Zum Beispiel kann man eine Funktion iscapital :: Char -> Bool für den Test, ob ein Zeichen ein Großbuchstabe ist, wie folgt definieren: iscapital ch = ( A <= ch) && (ch <= Z ) Das ist doch etwas kürzer und einfacher als: iscapital ch = (ord A <= ord ch) && (ord ch <= ord Z )