Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.
| Beide Seiten, vorherige Überarbeitung Vorherige Überarbeitung Nächste Überarbeitung | Vorherige Überarbeitung | ||
| ef_informatik:zahlensysteme [2024-08-27 12:23] – [Zahlensysteme & Datentypen] sca | ef_informatik:zahlensysteme [2026-08-25 13:11] (aktuell) – [Zahlensysteme & Datentypen] sca | ||
|---|---|---|---|
| Zeile 3: | Zeile 3: | ||
| ++++Lernziele| | ++++Lernziele| | ||
| - | Grundsätzlich | + | **1 Integers** |
| + | |||
| + | * Ich kann erklären, was ein **Datentyp** ist, und den Unterschied zwischen **statischer** (C\#, C\+\+) und **dynamischer** (Python) Typisierung an einem Beispiel erläutern -- inklusive je eines Vor- und eines Nachteils. | ||
| + | * Ich kann für $n$ Bit berechnen, **wie viele** Zahlen darstellbar sind sowie die **kleinste** und die **grösste** Zahl -- je für `int` und `unsigned int`. | ||
| + | * Ich kann für eine konkrete Anwendung einen **passenden Datentyp wählen** und meine Wahl mit einer Abschätzung des Wertebereichs begründen. | ||
| + | * Ich kann erklären, was ein **Überlauf (Overflow)** ist, warum dabei aus der grössten positiven die kleinste negative Zahl wird, und warum das so gefährlich ist (Ariane 5). | ||
| + | |||
| + | **2 Programmieren in C\#** | ||
| + | |||
| + | * Ich kann in C\# ein einfaches Programm schreiben: Variablen **deklarieren** und mit Werten belegen, rechnen, ausgeben, sowie **Verzweigungen** und **Schleifen** verwenden. Insbesondere kenne ich die Falle der **Ganzzahldivision** (`7 / 3` ergibt `2`). | ||
| + | |||
| + | **3 Gleitkommazahlen** | ||
| + | |||
| + | * Ich kann eine Dezimalzahl mit Nachkommateil ins **Binärsystem** umwandeln und in **wissenschaftlicher Schreibweise** $1.M_2 \cdot 2^{e}$ darstellen -- und umgekehrt. | ||
| + | * Ich kann den **Aufbau einer Gleitkommazahl** erklären: Vorzeichenbit, Exponent mit **Bias** und **normalisierte Mantisse** mit **impliziter Eins**. | ||
| + | * Ich kann eine Dezimalzahl ins **Mini-Float-Format** (oder ähnliches Format mit vorgegebener Anzahl Bits) umwandeln und ein Bitmuster zurück in eine Dezimalzahl. Ich kann damit die grösste und die kleinste darstellbare Zahl bestimmen. | ||
| + | * Ich kann erklären, warum $0.1$ **nicht exakt** darstellbar ist und warum `0.1 + 0.2 == 0.3` zu `False` führt -- und weiss, wie man Gleitkommazahlen stattdessen vergleicht. | ||
| + | * Ich kann erklären, warum Gleitkommazahlen **ungleichmässig** auf dem Zahlenstrahl liegen, und welche Folgen das hat (Rundungsfehler summieren sich auf, **Absorption**). | ||
| + | * Ich kenne die **Sonderfälle** $\pm 0$, $\pm\infty$ und `NaN` und weiss, dass keiner davon eine Fehlermeldung auslöst. | ||
| - | * Wissen, warum Datentypen wichtig sind in C Sprachen. | ||
| - | * Dynamische und statische Typisierung vergleichen. Vor- und Nachteile? | ||
| - | * Zahlen in wissenschaftlicher Schreibweise darstellen. | ||
| - | * Umwandlung von ganzen Zahlen (ints) dezimal <-> binär | ||
| - | * Binärzahl in Gleitkommadarstellung bringen ... | ||
| - | * ... und zugehörige Fachbegriffe (Mantisse, ...) erklären können. | ||
| - | * Umwandlung von Gleitkommazahlen dezimal <-> binär | ||
| - | * Umwandlung Gleitkommadarstellung in Binärzahl oder Dezimalzahl | ||
| - | * Sonderfälle für binäre Gleitkommazahlen kennen und verstehen. | ||
| - | * Binäre floats addieren können. | ||
| - | * Codes zu den obigen Punkten verfassen können in Python oder C#. | ||
| ++++ | ++++ | ||
| Zeile 21: | Zeile 28: | ||
| ++++Praktische Python Befehle| | ++++Praktische Python Befehle| | ||
| - | # length | + | <code python> |
| + | # Length | ||
| len(" | len(" | ||
| - | # datentypen, Umwandlungen | + | # Data types |
| str(42) | str(42) | ||
| int(" | int(" | ||
| float(13) | float(13) | ||
| type(42) | type(42) | ||
| + | bin(132) | ||
| # Strings | # Strings | ||
| Zeile 44: | Zeile 53: | ||
| s.find(" | s.find(" | ||
| many_zeros_string = " | many_zeros_string = " | ||
| + | |||
| + | ## TIPP: In diesem Thema bietet es sich meist an, mit Strings anstelle Listen zu arbeiten. Sollte man aber das Bedürfnis nach Listen haben, hier die wichtigsten Befehle: | ||
| + | li = [' | ||
| + | len(li) | ||
| + | li.append(' | ||
| + | li.pop(2) | ||
| + | li.remove(' | ||
| + | print(li) | ||
| + | </ | ||
| ++++ | ++++ | ||
| - | ===== - Voraussetzungen ===== | + | ===== Voraussetzungen ===== |
| Aus dem Grundlagenfach weisst du bereits, was Zahlensysteme sind. Insbesondere kennst du das Binärsystem und kannst: | Aus dem Grundlagenfach weisst du bereits, was Zahlensysteme sind. Insbesondere kennst du das Binärsystem und kannst: | ||
| Zeile 58: | Zeile 76: | ||
| Das Dossier **Zahlensysteme** aus dem Grundlagenfach findest du hier: {{ : | Das Dossier **Zahlensysteme** aus dem Grundlagenfach findest du hier: {{ : | ||
| - | ===== - Datentypen | + | ===== Dossier |
| - | + | ||
| - | Beim Programmieren kennen wir viele verschiedene **Datentypen** wie: | + | |
| - | * **Integer** (kurz: int): also ganze Zahlen $\ldots, | + | |
| - | * **Floats:** Gleitkommazahlen, | + | |
| - | * **Strings: | + | |
| - | * und viele weitere | + | |
| - | + | ||
| - | Für einen Computer macht es einen grossen Unterschied, | + | |
| - | + | ||
| - | ==== - Datentypen in Python ==== | + | |
| - | + | ||
| - | In **Python** muss man sich nicht wirklich um Datentypen kümmern, was sowohl eine der grössten Stärken wie auch Schwächen von Python ist. Zum Beispiel kann man in Python eine Variable ganz einfach direkt festlegen: | + | |
| - | <code python> | + | |
| - | i = 42 | + | |
| - | f = 3.14 | + | |
| - | s = "Das EFIF ist super!" | + | |
| - | </ | + | |
| - | Python erkennt dann automatisch, | + | |
| - | <code python> | + | |
| - | print(type(i)) # Output: <type ' | + | |
| - | print(type(f)) # Output: <type ' | + | |
| - | print(type(s)) # Output: <type ' | + | |
| - | </ | + | |
| - | In Python kann man eine Variable auch problemlos in einen anderen Typen umwandeln: | + | |
| - | <code python> | + | |
| - | i = 42 # zuerst int | + | |
| - | i = "Ich bin jetzt ein String, holt mich hier raus!" # jetzt ploetzlich String | + | |
| - | </ | + | |
| - | Aus diesem Grund spricht man in Python von **dynamischer Typisierung**. | + | |
| - | + | ||
| - | ==== - Statische Typisierung ==== | + | |
| - | + | ||
| - | In vielen anderen Programmiersprachen wie C\#, C\+\+ oder Java geniesst man diese Freiheiten nicht. Man spricht dann von **statischer Typisierung** und **typsichere Sprachen**. In solchen müssen Variablen **explizit deklariert**, | + | |
| - | + | ||
| - | Zum Beispiel in C\+\+ (was wir für Arduino brauchen werden): | + | |
| - | <code c++> | + | |
| - | int i; // separate Deklaration ... | + | |
| - | i = 42; // und Wertzuweisung | + | |
| - | + | ||
| - | float f = 3.14; // Deklaration und Wertzuweisung in einer Zeile | + | |
| - | </ | + | |
| - | + | ||
| - | Von nun an wollen wir uns nur noch mit *typsicheren Programmiersprachen* beschäftigen. | + | |
| - | + | ||
| - | ===== - Ganze Zahlen ===== | + | |
| - | + | ||
| - | Deklariert man eine Integer-Variable `int x;`, so wird im Arbeitsspeicher für die Variable x der Speicherplatz reserviert, der einem Integer zusteht. Weise ich der Variable nun einen zu grossen Wert zu, so kann dieser nicht gespeichert werden. In dem Fall muss man auf einen Datentypen ausweichen, dem mehr Speicherplatz zur Verfügung steht. | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | + | ||
| - | ++++Lösung| | + | |
| - | Insgesamt können $2^4 = 16$ verschiedene Zahlen damit dargestellt werden. Der Datentyp `int` beinhaltet sowohl positive als auch negative Zahlen: | + | |
| - | * kleinste Zahl: $-8$ | + | |
| - | * grösste Zahl: $7$ | + | |
| - | + | ||
| - | {{ : | + | |
| - | + | ||
| - | Möchte man nur Zahlen $\geq 0$ haben, so spricht man von einem **unsigned int (uint)**. Bei $4$ Bits ist die grösste Zahl dann also $15$. | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | * Anzahl verschiedene Zahlen | + | |
| - | * die kleinste und grösste Zahl | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | * Anzahl: $2^n$ | + | |
| - | * int: | + | |
| - | * kleinste Zahl: $-2^{n-1}$ | + | |
| - | * grösste Zahl: $2^{n-1}-1$ | + | |
| - | * uint: | + | |
| - | * kleinste Zahl: $0$ | + | |
| - | * grösste Zahl: $2^{n}-1$ | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | Wir werden bald mit **Arduinos**, | + | |
| - | * **int:** 16 Bit (negative und positive Zahlen) | + | |
| - | * **unsigned int:** 16 Bit (nur positive Zahlen: $0, | + | |
| - | * **long:** 32 Bit | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | + | ||
| - | 1. Für welche Zeitdauer geht dies gut? | + | |
| - | 1. Möchtest du längere Zeiten messen, musst du deinen Code anpassen. Was sind deine Optionen? Reichen diese Änderungen? | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | 1. Nur für knapp 33 Sekunden! | + | |
| - | 1. Datentyp ändern in: | + | |
| - | 1. unsigned int: Reicht für $2^{16}-1\, | + | |
| - | 1. long: Reicht für knapp $25$ Tage. D.h. dies kann ein Problem werden für Projekte, die länger laufen sollen (z.B. eine Uhr) | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | ===== - Gleitkommazahlen ===== | + | |
| - | + | ||
| - | Hilfreiches Online-Tool: | + | |
| - | + | ||
| - | Das Rechnen mit ganzen Zahlen am Computer ist relativ problemfrei. So kann man davon ausgehen, dass der Computer einem immer *exakte* Resultate liefert - zumindest so lange man nicht den Bereich verlässt, der vom Datentyp (Z.B. int oder long) abgedeckt wird. Zum Beispiel kann man mit einem 32-Bit-Datentyp für ganze Zahlen (z.B. long auf Arduino Uno) // | + | |
| - | + | ||
| - | Bei Gleitkommazahlen, | + | |
| - | + | ||
| - | Daraus resultiert folgende <color red> | + | |
| - | + | ||
| - | ==== Wissenschaftliche Schreibweise von Dezimalzahlen ==== | + | |
| - | + | ||
| - | Um zu verstehen, wie Gleitkommazahlen in Computern gespeichert werden, lohnt es sich, sich die **wissenschaftliche Schreibweise**, | + | |
| - | $$\pm a \times 10^b$$ | + | |
| - | + | ||
| - | * Die Stelle ganz links beinhaltet das **Vorzeichen** und entscheidet deshalb darüber, ob die Zahl positiv oder negativ ist. | + | |
| - | * Die Zahl $a$ vor der Potenz wird **Mantisse** genannt und erfüllt die Bedingung $1\leq a < 10$. Sie ist also eine Gleitkommazahl, | + | |
| - | * Die Zahl $b$ wird **Exponent** genannt. Grosse Zahlen haben einen positiven, kleine einen negativen Exponenten. Du kannst dir vorstellen, dass der Exponent das Komma *verschiebt*. | + | |
| - | + | ||
| - | Zum Beispiel sieht die wissenschaftliche Schweibweise der Zahl $-72024$ wie folgt aus: | + | |
| - | $$-7.2024 \cdot 10^4$$ | + | |
| - | Gut an der wissenschaftlichen Schreibweise ist, dass sie eine Zahl *eindeutig* beschreibt. Besonders nützlich ist sie für sehr kleine und grosse Zahlen. | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | + | ||
| - | 1. $100023=$\\ \\ | + | |
| - | 1. $0.000000000932=$\\ \\ | + | |
| - | 1. $613453 | + | |
| - | + | ||
| - | Fun fact: Die letzte Zahl entspricht in ihrer Grössenordnung ungefähr der geschätzten Anzahl Atome im sichtbaren Teil des Universums!\\ \\ | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | 1. $100023 = 1.00023 \cdot 10^5$\\ \\ | + | |
| - | 1. $0.000000000932 = 9.32 \cdot 10^{-10}$\\ \\ | + | |
| - | 1. $613453 \cdot 10^{84} = 6.13453 \cdot 10^{89}$ | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | ==== Binäre Gleitkommazahlen ==== | + | |
| - | + | ||
| - | Eine **Gleitkomma-Dezimalzahl** kann man wie folgt darstellen: | + | |
| - | $$\color{blue}{42}.\color{blue}{13}_\color{magenta}{10}= \color{blue}{4} \cdot \color{magenta}{10}^\color{green}{1} + \color{blue}{2} \cdot \color{magenta}{10}^\color{green}{0} + \color{blue}{1} \cdot \color{magenta}{10}^\color{green}{-1} + \color{blue}{3} \cdot \color{magenta}{10}^\color{green}{-2}$$ | + | |
| - | + | ||
| - | Gleichermassen kann eine **Gleitkomma-Binärzahl** dargestellt werden: | + | |
| - | $$\color{blue}{101}.\color{blue}{11}_\color{magenta}{2}= | + | |
| - | \color{blue}{1} \cdot \color{magenta}{2}^\color{green}{2} | + | |
| - | + \color{blue}{0} \cdot \color{magenta}{2}^\color{green}{1} | + | |
| - | + \color{blue}{1} \cdot \color{magenta}{2}^\color{green}{0} | + | |
| - | + \color{blue}{1} \cdot \color{magenta}{2}^\color{green}{-1} | + | |
| - | + \color{blue}{1} \cdot \color{magenta}{2}^\color{green}{-2} | + | |
| - | $$ | + | |
| - | + | ||
| - | Um eine Binärzahl mit Nachkommastellen im Speicher eines Computers zu speichern, bringt man diese zuerst in die wissenschaftliche Schreibweise. Im Speicher werden dann **Vorzeichen, | + | |
| - | Dabei ist ein Bit für das Vorzeichen und jeweils eine *feste Anzahl Bits* für Mantisse und Exponent festgelegt. | + | |
| - | Aus dieser Information kann dann die Zahl rekonstruiert werden. | + | |
| - | + | ||
| - | Die wissenschaftliche Schreibweise für Binärzahlen funktioniert analog zu der für Dezimalzahlen. Beachte, dass in der Mantisse die Ziffer vor dem Punkt *eine Eins* sein muss. Die einzige Ausnahme ist die Zahl $0_2$. Beim Speichern einer Zahl mit Nachkommastellen wird deshalb diese erste $1$ *weggelassen* - so spart man sich ein Bit! Man sagt, dass die Mantisse **normalisiert** wird: | + | |
| - | + | ||
| - | In Exponenten möchte man **negative Zahlen verhindern**. Man addiert zum Exponenten deshalb einen sogenannten **Bias**. Dieser Bias-behaftete Exponent nimmt dann im Normalfall Werte zwischen $1$ und $2^x-2$ an, wobei $x$ die Anzahl Bits für den Exponenten ist. Damit kann man Exponenten zwischen $-(2^{x-1}-2)$ und $+2^{x-1}-1$ darstellen. Die beiden Sonderfälle, | + | |
| - | + | ||
| - | ^**Exponent** ^ **Mantisse** ^ **Beschreibung** ^ | + | |
| - | |$E = 0$ | $M = 0$ | Zahl $0$ | | + | |
| - | |$E = 0$ | $M > 0$ | denormalisierte Zahl (für extrem kleine Zahlen) | | + | |
| - | |$2^x-1 > E > 0$ | $M \geq 0$ | normalisierte Zahl (Normalfall) | | + | |
| - | |$E = 2^x-1$ | $M = 0$ | Unendlich | | + | |
| - | |$E = 2^x-1$ | $M > 0$ | keine Zahl / Not A Number (NAN) | | + | |
| - | + | ||
| - | Diese Zahlendarstellung wird **Gleitkommadarstellung** genannt, da die Position des Kommas je nach Zahl variiert. Diese Darstellung erlaubt, im Gegensatz zu Darstellungen mit einem festen Platz für das Komma, dass man sowohl sehr grosse wie auch sehr kleine Zahlen mit hoher Genauigkeit speichern kann. Die hier beschriebene Darstellung wird durch die Norm **Norm IEEE 754** festgelegt. | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | + | ||
| - | Rechne die Binärzahl $101.01_2$ ins Dezimalsystem um. | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | $$101.01_2 = 1 \cdot 2^{2}+ 0 \cdot 2^{1}+ 1 \cdot 2^{0}+ 0 \cdot 2^{-1}+ 1 \cdot 2^{-2}= 5.25_{10}$$ | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | Ziel ist es, die Zahl $101.01_2$ als **16-Bit Gleitkommazahl** darzustellen. Dabei sind folgende Anzahl Bits reserviert für: | + | |
| - | {{ : | + | |
| - | + | ||
| - | 1. Notiere die Zahl zuerst in der **wissenschaftlichen Schreibweise** für Binärzahlen.\\ \\ | + | |
| - | 1. Bestimme (jeweils als Binärzahl): | + | |
| - | 1. Welche Werte sollen der minimale und maximale Exponent haben können? Bestimme den passenden **Bias**, den man zum Exponenten hinzuaddiert.\\ \\ | + | |
| - | 1. Normalisiere nun die Mantisse und addiere den Bias zum Exponenten. Notiere: Vorzeichen, Exponent mit Bias, Mantisse.\\ \\ | + | |
| - | 1. Notiere nun die **fertige Gleitkommazahl**, | + | |
| - | 1. Wie sehen die Sonderfälle (siehe Tabelle oben) für eine 16-Bit Gleitkommazahl aus?\\ \\ | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | 1. $$101.01\_2 = \color{red}{1.0101}\_2 \cdot 2^{\color{green}{2}\_{10}} = \color{red}{1.0101}\_2 \cdot 2^{\color{green}{10}\_2}$$ \\ \\ | + | |
| - | 1. Vorzeichen: $+$, also $0\_2$\\ Exponent: $10\_2$\\ Mantisse: $1.0101\_2$\\ \\ | + | |
| - | 1. Da $5$ Bit für Exponenten: Mit 5 Bit gibt $2^5 = 32$ Möglichkeiten, | + | |
| - | 1. minimaler Exponent: $-(2^{5-1}-2) = -14$ | + | |
| - | 1. maximaler Exponent: $2^{5-1}-1 = 15$ | + | |
| - | 1. Bias: $B = 15\_{10} = 01111\_2$ | + | |
| - | 1. Vorzeichen: $0\_2$\\ Exponent mit Bias: $10\_2 + 01111\_2 = 10001\_2$\\ Mantisse: $0101000000\_2$ | + | |
| - | 1. $$0\, | + | |
| - | 1. Tabelle, wobei $x=5$ (da $5$ Bits für Exponenten):< | + | |
| - | ^**Exponent** ^ **Mantisse** ^ **Beschreibung** ^ | + | |
| - | |$E = 0$ | $M = 0$ | Zahl $0$ | | + | |
| - | |$E = 0$ | $M > 0$ | denormalisierte Zahl (für extrem kleine Zahlen) | | + | |
| - | |$31 > E > 0$ d.h. $30 \geq E \geq 1$ | $M \geq 0$ | normalisierte Zahl (Normalfall) | | + | |
| - | |$E = 31$ | $M = 0$ | Unendlich | | + | |
| - | |$E = 31$ | $M > 0$ | keine Zahl / Not A Number (NAN) | | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | Wir betrachten wieder 16-Bit Gleitkommazahlen mit 5-Bit Exponent und 10-Bit Mantisse.\\ \\ | + | |
| - | + | ||
| - | 1. Bestimme die grösste und zweitgrösste Zahl, die man damit darstellen kann als Dezimalzahl. Was fällt dir auf?\\ \\ | + | |
| - | 1. Bestimme die kleinste positive und von Null verschiedene Gleitkommazahl, | + | |
| - | 1. Welche Schlüsse ziehst du daraus, wenn es um die Verwendung von ganzen Zahlen und Gleitkommazahlen in der Programmierung geht? | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | 1. grösste Zahl: $$0\, | + | |
| - | | + | |
| - | | + | |
| - | 1. Kleinste positive normalisierte Zahl: $$0\, | + | |
| - | | + | |
| - | 1. Gute Faustregel: Wenn man etwas mit ganzen Zahlen umsetzen kann, sollte man dies tun. Beispiel: Code für Stoppuhr. Die Zeit könnte man in Sekunden in Gleitkommazahlen speichern. Wahrscheinlich ist es aber besser, die Zeit in Millisekunden in ganzen Zahlen zu speichern. Auf Arduinos sollte man, wenn möglich, Gleitkommazahlen (floats) komplett vermeiden, da diese nicht nativ unterstützt werden. | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | $$B = 2^{n-1}-1 = 011\ldots1_2$$ | + | |
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | <color magenta> | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | <code python> | + | |
| - | def binary_string_to_float(bin_str, | + | |
| - | # SIGN | + | |
| - | sign = ' | + | |
| - | if bin_str[0] == ' | + | |
| - | + | ||
| - | # SPECIAL CASE: ZERO | + | |
| - | if ' | + | |
| - | + | ||
| - | # TODO: other special cases (too small, too big, nan) | + | |
| - | + | ||
| - | # if int convert into float | + | |
| - | if not ' | + | |
| - | + | ||
| - | # EXPONENT, MANTISSA | + | |
| - | bin_str = bin_str.lstrip(' | + | |
| - | bias = (2**len_exp - 2)//2 | + | |
| - | mantissa = bin_str | + | |
| - | + | ||
| - | # determine exponent | + | |
| - | i_one = bin_str.find(' | + | |
| - | i_point = bin_str.find(' | + | |
| - | exponent = i_point - i_one | + | |
| - | if exponent > 0: exponent -= 1 | + | |
| - | + | ||
| - | # remove point from mantissa | + | |
| - | if ' | + | |
| - | + | ||
| - | # add bias to exponent | + | |
| - | exp_w_bias = bin(exponent+bias)[2: | + | |
| - | exp_w_bias = ' | + | |
| - | if len(exp_w_bias) > len_exp: | + | |
| - | return [sign,' | + | |
| - | + | ||
| - | # normalize mantissa | + | |
| - | mantissa = mantissa.lstrip(' | + | |
| - | mantissa_normalized = mantissa[1:: | + | |
| - | # ensure mantissa has correct length | + | |
| - | if len(mantissa_normalized) > len_mant: | + | |
| - | mantissa_normalized = mantissa_normalized[0: | + | |
| - | else: | + | |
| - | mantissa_normalized += ' | + | |
| - | + | ||
| - | # TODO: round mantissa correctly | + | |
| - | + | ||
| - | return [sign, | + | |
| - | </ | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | ==== Dezimalzahlen mit Nachkommastellen ==== | + | |
| - | + | ||
| - | Aus dem Grundlagenfach kennen wir den **Restwertalgorithmus**, | + | |
| - | $$0.5_{10} = \left(\frac12\right)_{10} = 0.1_2$$ | + | |
| - | $$0.25_{10} = \left(\frac14\right)_{10} = 0.01_2$$ | + | |
| - | $$0.125_{10} = \left(\frac18\right)_{10} = 0.001_2$$ | + | |
| - | Der Algorithmus zur Umrechnung von dezimalen Nachkommastellen ins Binärsystem geht ganz ähnlich wie oben beschrieben, | + | |
| - | + | ||
| - | **Beispiel: | + | |
| - | $$0.375 \cdot 2 = \color{blue}{0}.75$$ | + | |
| - | $$0.75 \cdot 2 = \color{blue}{1}.5$$ | + | |
| - | $$0.5 \cdot 2 = \color{blue}{1}.\color{red}{0}$$ | + | |
| - | Es gilt also: $$0.375_{10} = 0.\color{blue}{011}_2$$ | + | |
| - | + | ||
| - | Für Zahlen wie $42.375$ gehen wir wie folgt vor: Wir wandeln den Teil vor und den Teil nach dem Komma separat um und fügen sie dann zusammen: | + | |
| - | + | ||
| - | * $42\_{10} = 101010\_2$ | + | |
| - | * $0.375_{10} = 0.011\_2$ | + | |
| - | + | ||
| - | Es gilt also $$42.375_{10} = 101010.011_2$$ | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | + | ||
| - | 1. Dezimalbruch $\cfrac{1}{16}$ als Binärzahl | + | |
| - | 1. Dezimalzahl $0.5625$ als Binärzahl | + | |
| - | 1. Dezimalzahl $90.25$ als Binärzahl | + | |
| - | 1. Dezimalzahl $0.42$ als Binärzahl | + | |
| - | + | ||
| - | ++++Lösung| | + | |
| - | + | ||
| - | 1. $0.0001\_2$ weil $\cfrac{1}{16} = 2^{-4}$ | + | |
| - | 1. $0.1001\_2$ | + | |
| - | 1. $1011010.01\_2$ | + | |
| - | 1. $.0110101110\ldots\_2$ (geht noch weiter, nach 10 NKS abgebrochen) | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | * Vorzeichen negativ, also $0$\\ \\ | + | |
| - | * Vorkommastellen: | + | |
| - | * Nachkommastellen: | + | |
| - | * ganze Binärzahl: $11001.111001\_2$ \\ \\ | + | |
| - | * wissenschaftliche Schreibweise: | + | |
| - | * Exponent: | + | |
| - | * Exponent ohne Bias: $4\_{10} = 00100\_2$ | + | |
| - | * Bias ist: $15\_{10} = 01111\_2$ | + | |
| - | * Exponent mit Bias: $19\_{10} = 10011\_2$ \\ \\ | + | |
| - | * Mantisse: | + | |
| - | * Mantisse nicht normalisiert: | + | |
| - | * Mantisse normalisiert: | + | |
| - | * Zahl als float also: $$1100111001111001_2$$\\ \\ | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | <box 100%> | + | |
| - | <color magenta> | + | |
| - | + | ||
| - | 1. Ganze Dezimalzahlen ins Binärsystem umrechnet. Repetition, implementiere selbst den Restwertalgorithmus und verwende nicht z.B. `bin(...)`.\\ \\ | + | |
| - | 1. Kleine Dezimalzahlen ($0 < a < 1$, haben also Form $0.< | + | |
| - | 1. Beliebige Dezimalzahlen, | + | |
| - | + | ||
| - | ++++Lösung| | + | |
| - | + | ||
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | + | ||
| - | ===== Weitere Aufgaben ===== | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | Umrechnung ohne die festgelegten Spezialfälle: | + | |
| - | + | ||
| - | * Vorzeichen: $0$, also positiv\\ \\ | + | |
| - | * Exponent: | + | |
| - | * Exponent mit Bias: $00000\_2 = 0$ | + | |
| - | * Bias ist: $01111\_2 = 15$ | + | |
| - | * Exponent ohne Bias: $-15$ \\ \\ | + | |
| - | * Mantisse: | + | |
| - | * Mantisse normalisiert: | + | |
| - | * Mantisse nicht normalisiert: | + | |
| - | * Zahl als Binärzahl also: $$+1.0000000000\_2 \cdot 2^{00000\_2}$$\\ \\ | + | |
| - | * das ist zwar klein, aber immer noch viel zu gross... | + | |
| - | + | ||
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | $$1\, | + | |
| - | Bestimme als Binär- und Dezimalzahl. | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | * Vorzeichen: $1$, also negativ\\ \\ | + | |
| - | * Exponent: | + | |
| - | * Exponent mit Bias: $10010\_2 = 18$ | + | |
| - | * Bias ist: $01111\_2 = 15$ | + | |
| - | * Exponent ohne Bias: $3$ \\ \\ | + | |
| - | * Mantisse: | + | |
| - | * Mantisse normalisiert: | + | |
| - | * Mantisse nicht normalisiert: | + | |
| - | * Zahl als Binärzahl also: $$-1101.101\_2$$\\ \\ | + | |
| - | * Zahl als Dezimalzahl: | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | < | + | |
| - | int i = 64237 | + | |
| - | float f = -56736f | + | |
| - | </ | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | Beide haben die gleiche Binärrepräsentation | + | |
| - | $$1111 1010 1110 1101$$ | + | |
| - | + | ||
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | * wissenschaftliche Schreibweise: | + | |
| - | * Exponent: | + | |
| - | * Exponent ohne Bias: $-5\_{10} = 11011\_2$ | + | |
| - | * Bias ist: $15\_{10} = 01111\_2$ | + | |
| - | * Exponent mit Bias: $19\_{10} = 01010\_2$ \\ \\ | + | |
| - | * Mantisse: | + | |
| - | * Mantisse nicht normalisiert: | + | |
| - | * Mantisse normalisiert: | + | |
| - | * Zahl als float also: $$001010001001001001_2$$\\ \\ | + | |
| - | * <color red>oder doch nicht?!? Und jetzt?</ | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | + | ||
| - | $$0011001011001000$$ | + | |
| - | $$0010101001100111$$ | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Tipps| | + | |
| - | + | ||
| - | * Exponenten ermitteln | + | |
| - | * Mantissen ermitteln | + | |
| - | * Exponenten angleichen, Komma der Mantissen entsprechend verschieben. Bias beibehalten | + | |
| - | * Addition durchführen | + | |
| - | * Komma verschieben, | + | |
| - | * Runden | + | |
| - | * Zusammensetzen | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | <nodisp 2> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | * Exponent 1: $2^{12}$ | + | |
| - | * Exponent 2: $2^{10}$ | + | |
| - | * Mantisse 1: $1.1011001\_2$ | + | |
| - | * Mantisse 2a: $1.1001100111\_2$ | + | |
| - | * angeglichene Mantisse 2b: $0.011001100111\_2$ | + | |
| - | * Addition Mantisse 1 und 2b: $10.000110000111\_2$ | + | |
| - | * wissenschaftliche Schreibweise: | + | |
| - | * Runden: $1.000011000< | + | |
| - | * Die erste Ziffer, die weggeschnitten wird, ist eine 1, und danach gibt es weitere 1. Somit aufrunden. | + | |
| - | * aufgerundet: | + | |
| - | * als float: $$0011010000110001$$ | + | |
| - | + | ||
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | ==== Zusatzaufgaben: | + | |
| - | + | ||
| - | + | ||
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | + | ||
| - | 1. Bestimme die grösste und zweitgrösste Zahl, die man in einem C\#-Float (8-Bit Exponent, 23-Bit Mantisse) speichern kann. Verwende Python.\\ \\ | + | |
| - | 1. Wie gross ist die Differenz? Verwende Python.\\ \\ | + | |
| - | 1. Überzeuge dich davon, dass C\# nicht zwischen der grössten Zahl und zwischen einer Zahl, die in diesem Gap liegt, unterscheiden kann, zum Beispiel indem du diese von einander subtrahierst. Python hingegen hat da keine Probleme.\\ | + | |
| - | | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | + | ||
| - | 1. Grösste Zahl: $340282346638528859811704183484516925440 \approx 3.4 \cdot 10^{38}$\\ Zweitgrösste Zahl: $340282326356119256160033759537265639424$\\ \\ | + | |
| - | 1. Differenz: $20282409603651670423947251286016 \approx 2 \cdot 10^{31}$, also eine riesige Differenz\\ \\ | + | |
| - | 1. Man erhält immer $0$, z.B. ergibt folgende Subtraktion $0$: $$340282346638528859811704183484516925440\text{f} - 340282340000000000000000000000000000000\text{f}$$ | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | * C#: https:// | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | Resultat ist $0.1000001$. Also nicht exakt, Grund: Rundungsfehler. $3.3$ und $3.4$ haben als Binärzahl ausgedrückt jeweils unendliche viele sich periodisch wiederholende Nachkommastellen. Diese müssen gerundet werden, was zu diesem Fehler führt. | + | |
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | ==== Zusatzaufgaben: | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | Schätze die Grössenordnung der grössten Zahl, die ein C#-Double (11-Bit Exponent, 52-Bit Mantisse) darstellen kann, ab. Alles was du dazu verwenden darft, ist dein Kopf, also keinen Computer. Taschenrechner, | + | |
| - | + | ||
| - | Berechne dazu die Potenz, die aus dem MSB (most significant bit, also dem Bit, welches ganz links steht) heraus geht, was $2$ hoch `eine grosse Zahl' ist, was eine sehr grosse Dezimalzahl ergibt. Ein handelsüblicher Taschenrechner ist nicht in der Lage, diese Zahl zu berechnen. Der Trick hier ist, dass du dein Wissen über Logarithmen verwendest. Dann schaffst du diese Rechnung ganz ohne Rechner. Insbesondere benötigst du die Formel für den Basiswechsel | + | |
| - | $$\log_a k = \frac{\log_b k}{\log_b a} \,.$$ | + | |
| - | + | ||
| - | <nodisp 1> | + | |
| - | ++++Lösung| | + | |
| - | Muss Grössenordnung von $2^{1023}$ abschätzen. | + | |
| - | + | ||
| - | Grösste Zahl ist $1.798 \cdot 10^{308}$. Mit Abschätzung ohne technische Hilfe sollte man auf etwa $10^{310}$ kommen. | + | |
| - | ++++ | + | |
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | <box 100%> | + | |
| - | **Aufgabe: | + | |
| - | Beweise, dass es im Interval $[0,1]$ überabzählbar unendlich viele reellen Zahlen gibt. | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ||
| - | <nodisp 2> | + | |
| - | ++++Lösungen LP| | + | |
| - | ===== Lösungen LP ===== | + | |
| - | + | ||
| - | <code python> | + | |
| - | def binary_to_decimal(b): | + | |
| - | n = len(b) | + | |
| - | d = 0 # decimal number | + | |
| - | for i in range(n): | + | |
| - | d = d + int(b[i]) * 2**(n-i-1) | + | |
| - | return d | + | |
| - | + | ||
| - | def decimal_to_binary(d, | + | |
| - | b = "" | + | |
| - | while d > 0: | + | |
| - | b = str(d%2) + b | + | |
| - | d //= 2 | + | |
| - | if bits: | + | |
| - | while len(b) < bits: | + | |
| - | b = ' | + | |
| - | return b | + | |
| - | + | ||
| - | def find_mantissa_exponent(b, | + | |
| - | b = b.lstrip(' | + | |
| - | pos_point = b.find(' | + | |
| - | first_one = b.find(' | + | |
| - | + | ||
| - | # exponent: | + | |
| - | exp = pos_point - first_one | + | |
| - | if exp > 0: exp -= 1 | + | |
| - | + | ||
| - | # bias | + | |
| - | bias = 2**(e-1) - 1 | + | |
| - | exp_bias_bin = decimal_to_binary(exp+bias, | + | |
| - | + | ||
| - | # mantissa | + | |
| - | mantissa_bin = b.replace(' | + | |
| - | mantissa_bin = mantissa_bin.lstrip(' | + | |
| - | mantissa_bin = mantissa_bin[1: | + | |
| - | while len(mantissa_bin) < m: | + | |
| - | mantissa_bin = mantissa_bin + ' | + | |
| - | + | ||
| - | return exp_bias_bin, | + | |
| - | + | ||
| - | print(find_mantissa_exponent(" | + | |
| - | print(find_mantissa_exponent(" | + | |
| - | print(find_mantissa_exponent(" | + | |
| - | </ | + | |
| - | + | ||
| - | **Grösste und zweitgrösste Zahl für Float:** | + | |
| - | <code python> | + | |
| - | e = 8 # nr bits exponent | + | |
| - | m = 23 # nr bits mantissa | + | |
| - | + | ||
| - | exp_max = 2**(e-1)-1 | + | |
| - | + | ||
| - | nr_highest = 0 | + | |
| - | nr_2nd = 0 | + | |
| - | + | ||
| - | for i in range(exp_max-m+1, | + | |
| - | nr_2nd += 2**i | + | |
| - | + | ||
| - | nr_highest = nr_2nd + 2**(exp_max-m) | + | |
| - | + | ||
| - | print(nr_highest) | + | |
| - | print(nr_2nd) | + | |
| - | print(nr_highest-nr_2nd) | + | |
| - | </ | + | |
| - | + | ||
| - | ++++ | + | |
| - | </ | + | |
| + | {{ : | ||