removed nb dir from git tracking

This commit is contained in:
Meik Hellmund 2024-05-14 13:20:00 +02:00
parent aa4af0c42a
commit 31981a7612
21 changed files with 0 additions and 12998 deletions

View File

@ -1,981 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "7c21d452",
"metadata": {},
"source": [
"# Zeichen, Strings und Unicode\n",
"\n",
"## Zeichencodierungen (Frühgeschichte)\n",
"\n",
"Es gab - abhängig von Hersteller, Land, Programmiersprache, Betriebsssystem,... - eine große Vielzahl von Codierungen. \n",
"\n",
"Bis heute relevant sind:\n",
"\n",
"\n",
"### ASCII \n",
"Der _American Standard Code for Information Interchange_ wurde 1963 in den USA als Standard veröffentlicht. \n",
"\n",
"- Er definiert $2^7=128$ Zeichen, und zwar: \n",
" - 33 Steuerzeichen, wie `newline`, `escape`, `end of transmission/file`, `delete`\n",
" - 95 graphisch darstellbare Zeichen:\n",
" - 52 lateinische Buchstaben `a-z, A-Z`\n",
" - 10 Ziffern `0-9`\n",
" - 7 Satzzeichen `.,:;?!\"`\n",
" - 1 Leerzeichen ` `\n",
" - 6 Klammern `[{()}]`\n",
" - 7 mathematische Operationen `+-*/<>=`\n",
" - 12 Sonderzeichen ``` #$%&'\\^_|~`@ ``` \n",
"\n",
"- ASCII ist heute noch der \"kleinste gemeinsame Nenner\" im Codierungs-Chaos.\n",
"- Die ersten 128 Unicode-Zeichen sind identisch mit ASCII.\n",
"\n",
"### ISO 8859-Zeichensätze\n",
"\n",
"- ASCII nutzt nur 7 Bits. \n",
"- In einem Byte kann man durch Setzen des 8. Bits weitere 128 Zeichen unterbringen. \n",
"- 1987/88 wurden im ISO 8859-Standard verschiedene 1-Byte-Codierungen festgelegt, die alle ASCII-kompatibel sind, darunter:\n",
"\n",
":::{.narrow}\n",
" |Codierung | Region | Sprachen|\n",
" |:-----------|:----------|:-------|\n",
" |ISO 8859-1 (Latin-1) | Westeuropa | Deutsch, Französisch,...,Isländisch\n",
" |ISO 8859-2 (Latin-2) | Osteuropa | slawische Sprachen mit lateinischer Schrift\n",
" |ISO 8859-3 (Latin-3) | Südeuropa | Türkisch, Maltesisch,...\n",
" |ISO 8859-4 (Latin-4) | Nordeuropa | Estnisch, Lettisch, Litauisch, Grönländisch, Sami\n",
" |ISO 8859-5 (Latin/Cyrillic) | Osteuropa | slawische Sprachen mit kyrillischer Schrift\n",
" |ISO 8859-6 (Latin/Arabic) | |\n",
" |ISO 8859-7 (Latin/Greek) | |\n",
" |...| | \n",
" |ISO 8859-15 (Latin-9)| | 1999: Revision von Latin-1: jetzt mit Euro-Zeichen! \n",
" \n",
":::\n",
" \n",
"## Unicode \n",
"\n",
"Das Ziel des Unicode-Consortiums ist eine einheitliche Codierung für alle Schriften der Welt.\n",
"\n",
"- Unicode Version 1 erschien 1991\n",
"- Unicode Version 15 erschien 2021 mit 149 186 Zeichen (das sind 4489 mehr als Unicode 14), darunter: \n",
" - 161 Schriften \n",
" - mathematische und technische Symbole\n",
" - Emojis und andere Symbole, Steuer- und Formatierungszeichen\n",
"- davon entfallen über 90 000 Zeichen auf die CJK-Schriften (Chinesisch/Japanisch/Koreanisch) \n",
" \n",
" \n",
"### Technische Details\n",
"\n",
"- Jedem Zeichen wird ein `codepoint` zugeordnet. Das ist einfach eine fortlaufende Nummer.\n",
"- Diese Nummer wird hexadezimal notiert\n",
" - entweder 4-stellig als `U+XXXX` (0-te Ebene) \n",
" - oder 5...6-stellig als `U+XXXXXX` (weitere Ebenen)\n",
"- Jede Ebene geht von `U+XY0000` bis `U+XYFFFF`, kann also $2^{16}=65\\;534$ Zeichen enthalten. \n",
"- Vorgesehen sind bisher 17 Ebenen `XY=00` bis `XY=10`, also der Wertebereich von `U+0000` bis `U+10FFFF`.\n",
"- Damit sind maximal 21 Bits pro Zeichen nötig.\n",
"- Die Gesamtzahl der damit möglichen Codepoints ist etwas kleiner als 0x10FFFF, da aus technischen Gründen gewisse Bereiche nicht verwendet werden. Sie beträgt etwa 1.1 Millionen, es ist also noch viel Platz. \n",
"- Bisher wurden nur Codepoints aus den Ebenen \n",
" - Ebene 0 = BMP _Basic Multilingual Plane_ `U+0000 - U+FFFF`,\n",
" - Ebene 1 = SMP _Supplementary Multilingual Plane_ `U+010000 - U+01FFFF`,\n",
" - Ebene 2 = SIP _Supplementary Ideographic Plane_ `U+020000 - U+02FFFF`, \n",
" - Ebene 3 = TIP _Tertiary Ideographic Plane_ `U+030000 - U+03FFFF` und\n",
" - Ebene 14 = SSP _Supplementary Special-purpose Plane_ `U+0E0000 - U+0EFFFF` vergeben.\n",
"- `U+0000` bis `U+007F` ist identisch mit ASCII\n",
"- `U+0000` bis `U+00FF` ist identisch mit ISO 8859-1 (Latin-1)\n",
"\n",
"### Eigenschaften von Unicode-Zeichen\n",
"\n",
"Im Standard wird jedes Zeichen beschrieben duch\n",
"\n",
" - seinen Codepoint (Nummer) \n",
" - einen Namen (welcher nur aus ASCII-Großbuchstaben, Ziffern und Minuszeichen besteht) und \n",
" - verschiedene Attributen wie\n",
" - Laufrichtung der Schrift \n",
" - Kategorie: Großbuchstabe, Kleinbuchstabe, modifizierender Buchstabe, Ziffer, Satzzeichen, Symbol, Seperator,....\n",
"\n",
"Im Unicode-Standard sieht das dann so aus (zur Vereinfachung nur Codepoint und Name):\n",
"```\n",
"...\n",
"U+0041 LATIN CAPITAL LETTER A\n",
"U+0042 LATIN CAPITAL LETTER B\n",
"U+0043 LATIN CAPITAL LETTER C\n",
"U+0044 LATIN CAPITAL LETTER D\n",
"...\n",
"U+00E9 LATIN SMALL LETTER E WITH ACUTE\n",
"U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX\n",
"...\n",
"U+0641 ARABIC LETTER FEH\n",
"U+0642 ARABIC LETTER QAF\n",
"...\n",
"U+21B4 RIGHTWARDS ARROW WITH CORNER DOWNWARDS\n",
"...\n",
"```\n",
"\n",
"Wie sieht 'RIGHTWARDS ARROW WITH CORNER DOWNWARDS' aus?\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "48697b80",
"metadata": {},
"outputs": [],
"source": [
"'\\U21b4'"
]
},
{
"cell_type": "markdown",
"id": "568c932d",
"metadata": {},
"source": [
"### Eine Auswahl an Schriften \n",
"\n",
"::: {.content-visible when-format=\"html\"}\n",
"\n",
":::{.callout-note}\n",
"Falls im Folgenden einzelne Zeichen oder Schriften in Ihrem Browser nicht darstellbar sind, müssen Sie geeignete \n",
"Fonts auf Ihrem Rechner installieren. \n",
"\n",
"Alternativ können Sie die PDF-Version dieser Seite verwenden. Dort sind alle Fonts eingebunden.\n",
":::\n",
"\n",
":::\n",
"\n",
"Eine kleine Hilfsfunktion:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "44eecb07",
"metadata": {},
"outputs": [],
"source": [
"\"\"\"\n",
"printuc(c, n):\n",
"print n characters from unicode table, starting with character c \n",
"\"\"\"\n",
"function printuc(c, n)\n",
" for i in 0:n-1\n",
" print(c + i)\n",
" end\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "9857ec8a",
"metadata": {},
"source": [
"__Kyrillisch__\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d1827fb6",
"metadata": {},
"outputs": [],
"source": [
"printuc('\\U0400', 100)"
]
},
{
"cell_type": "markdown",
"id": "1975b4c8",
"metadata": {},
"source": [
"__Tamilisch__\n",
"\n",
":::{.cellmerge}\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0ac169a1",
"metadata": {},
"outputs": [],
"source": [
"#| echo: true\n",
"#| output: false\n",
"printuc('\\U0be7',20)"
]
},
{
"cell_type": "markdown",
"id": "cf47c3ec",
"metadata": {},
"source": [
"\\begingroup\\setmonofont{Noto Sans Tamil}\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4c539418",
"metadata": {},
"outputs": [],
"source": [
"#| echo: false\n",
"#| output: true\n",
"printuc('\\U0be7',20)"
]
},
{
"cell_type": "markdown",
"id": "57b1dd19",
"metadata": {},
"source": [
"\\endgroup\n",
"\n",
":::\n",
"\n",
"__Schach__\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6d474a65",
"metadata": {},
"outputs": [],
"source": [
"printuc('\\U2654', 12)"
]
},
{
"cell_type": "markdown",
"id": "9c31ea8a",
"metadata": {},
"source": [
"__Mathematische Operatoren__\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "58aaf4c5",
"metadata": {},
"outputs": [],
"source": [
"printuc('\\U2200', 255)"
]
},
{
"cell_type": "markdown",
"id": "9b6c63b0",
"metadata": {},
"source": [
"__Runen__\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "88859f95",
"metadata": {},
"outputs": [],
"source": [
"printuc('\\U16a0', 40)"
]
},
{
"cell_type": "markdown",
"id": "08203fd6",
"metadata": {},
"source": [
":::{.cellmerge}\n",
"\n",
"__Scheibe (Diskus) von Phaistos__\n",
"\n",
"- Diese Schrift ist nicht entziffert. \n",
"- Es ist unklar, welche Sprache dargestellt wird.\n",
"- Es gibt nur ein einziges Dokument in dieser Schrift: die Tonscheibe von Phaistos aus der Bronzezeit \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "640c2422",
"metadata": {},
"outputs": [],
"source": [
"#| echo: true\n",
"#| output: false\n",
"printuc('\\U101D0', 46 )"
]
},
{
"cell_type": "markdown",
"id": "ee56718c",
"metadata": {},
"source": [
"\\begingroup\\setmonofont{Phaistos.otf}\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0a728045",
"metadata": {},
"outputs": [],
"source": [
"#| echo: false\n",
"#| output: true\n",
"printuc('\\U101D0', 46 )"
]
},
{
"cell_type": "markdown",
"id": "cfcb78f6",
"metadata": {},
"source": [
"\\endgroup\n",
"\n",
":::\n",
"\n",
"### Unicode transformation formats: UTF-8, UTF-16, UTF-32\n",
"\n",
"_Unicode transformation formats_ legen fest, wie eine Folge von Codepoints als eine Folge von Bytes dargestellt wird. \n",
"\n",
"Da die Codepoints unterschiedlich lang sind, kann man sie nicht einfach hintereinander schreiben. Wo hört einer auf und fängt der nächste an? \n",
"\n",
"- __UTF-32__: Das einfachste, aber auch speicheraufwändigste, ist, sie alle auf gleiche Länge zu bringen. Jeder Codepoint wird in 4 Bytes = 32 Bit kodiert. \n",
"- Bei __UTF-16__ wird ein Codepoint entweder mit 2 Bytes oder mit 4 Bytes dargestellt. \n",
"- Bei __UTF-8__ wird ein Codepoint mit 1,2,3 oder 4 Bytes dargestellt. \n",
"- __UTF-8__ ist das Format mit der höchsten Verbreitung. Es wird auch von Julia verwendet. \n",
"\n",
"\n",
"### UTF-8\n",
"\n",
"- Für jeden Codepoint werden 1, 2, 3 oder 4 volle Bytes verwendet. \n",
"\n",
"- Bei einer Codierung mit variabler Länge muss man erkennen können, welche Bytefolgen zusammengehören:\n",
" - Ein Byte der Form 0xxxxxxx steht für einen ASCII-Codepoint der Länge 1.\n",
" - Ein Byte der Form 110xxxxx startet einen 2-Byte-Code.\n",
" - Ein Byte der Form 1110xxxx startet einen 3-Byte-Code.\n",
" - Ein Byte der Form 11110xxx startet einen 4-Byte-Code.\n",
" - Alle weiteren Bytes eines 2-,3- oder 4-Byte-Codes haben die Form 10xxxxxx. \n",
"\n",
"- Damit ist der Platz, der für den Codepoint zur Verfügung steht (Anzahl der x):\n",
" - Ein-Byte-Code: 7 Bits\n",
" - Zwei-Byte-Code: 5 + 6 = 11 Bits\n",
" - Drei-Byte-Code: 4 + 6 + 6 = 16 Bits\n",
" - Vier-Byte-Code: 3 + 6 + 6 + 6 = 21 Bits\n",
"\n",
"- Damit ist jeder ASCII-Text automatisch auch ein korrekt codierter UTF-8-Text.\n",
"\n",
"- Sollten die bisher für Unicode festgelegten 17 Ebenen = 21 Bit = 1.1 Mill. mögliche Zeichen mal erweitert werden, dann wird UTF-8 auf 5- und 6-Byte-Codes erweitert. \n",
" \n",
"\n",
"## Zeichen und Zeichenketten in Julia\n",
"\n",
"### Zeichen: `Char` \n",
"\n",
"Der Datentyp `Char` kodiert ein einzelnes Unicode-Zeichen. \n",
"\n",
"- Julia verwendet dafür einfache Anführungszeichen: `'a'`. \n",
"- Ein `Char` belegt 4 Bytes Speicher und \n",
"- repräsentiert einen Unicode-Codepoint.\n",
"- `Char`s können von/zu `UInt`s umgewandelt werden und \n",
"- der Integer-Wert ist gleich dem Unicode-codepoint.\n",
"\n",
"\n",
"### Zeichenketten: `String`\n",
"\n",
"- Für Strings verwendet Julia doppelte Anführungszeichen: `\"a\"`.\n",
"- Sie sind UTF-8-codiert, d.h., ein Zeichen kann zwischen 1 und 4 Bytes lang sein.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "707c245e",
"metadata": {},
"outputs": [],
"source": [
"@show typeof('a') sizeof('a') typeof(\"a\") sizeof(\"a\");"
]
},
{
"cell_type": "markdown",
"id": "ce463383",
"metadata": {},
"source": [
"- `Char`s können von/zu `UInt`s umgewandelt werden.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6488fdf6",
"metadata": {},
"outputs": [],
"source": [
"UInt('a')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2637de2b",
"metadata": {},
"outputs": [],
"source": [
"b = Char(0x2656)"
]
},
{
"cell_type": "markdown",
"id": "985adab7",
"metadata": {},
"source": [
"__Bei einem Nicht-ASCII-String unterscheiden sich Anzahl der Bytes und Anzahl der Zeichen:__\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "53c741c8",
"metadata": {},
"outputs": [],
"source": [
"asciistr = \"Hello World!\"\n",
"@show length(asciistr) ncodeunits(asciistr);"
]
},
{
"cell_type": "markdown",
"id": "bf536c2d",
"metadata": {},
"source": [
"(Das Leerzeichen zählt natürlich auch.)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "37e36e85",
"metadata": {},
"outputs": [],
"source": [
"str = \"😄 Hellö 🎶\"\n",
"@show length(str) ncodeunits(str);"
]
},
{
"cell_type": "markdown",
"id": "b9caf74d",
"metadata": {},
"source": [
"__Iteration über einen String iteriert über die Zeichen:__\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0e8e04e3",
"metadata": {},
"outputs": [],
"source": [
"for i in str\n",
" println(i, \" \", typeof(i))\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "ce0cfd1b",
"metadata": {},
"source": [
"### Verkettung von Strings\n",
"\n",
"\"Strings mit Verkettung bilden ein nichtkommutatives Monoid.\"\n",
"\n",
"Deshalb wird in Julia die Verkettung multiplikativ geschrieben.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6f35d90f",
"metadata": {},
"outputs": [],
"source": [
" str * asciistr * str"
]
},
{
"cell_type": "markdown",
"id": "898a6ea1",
"metadata": {},
"source": [
"Damit sind auch Potenzen mit natürlichem Exponenten definiert.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cb9d7217",
"metadata": {},
"outputs": [],
"source": [
"str^3, str^0"
]
},
{
"cell_type": "markdown",
"id": "cc89a9ca",
"metadata": {},
"source": [
"### Stringinterpolation\n",
"\n",
"Das Dollarzeichen hat in Strings eine Sonderfunktion, die wir schon oft in \n",
"`print()`-Anweisungen genutzt haben. MAn kann damit eine Variable oder einen Ausdruck interpolieren:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "16b8af0a",
"metadata": {},
"outputs": [],
"source": [
"a = 33.4\n",
"b = \"x\"\n",
"\n",
"s = \"Das Ergebnis für $b ist gleich $a und die verdoppelte Wurzel daraus ist $(2sqrt(a))\\n\""
]
},
{
"cell_type": "markdown",
"id": "1ddcc1ad",
"metadata": {},
"source": [
"### Backslash escape sequences \n",
"\n",
"Der _backslash_ `\\` hat in Stringkonstanten ebenfalls eine Sonderfunktion. \n",
"Julia benutzt die von C und anderen Sprachen bekannten _backslash_-Codierungen für Sonderzeichen und für Dollarzeichen und Backslash selbst:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "64a50bab",
"metadata": {},
"outputs": [],
"source": [
"s = \"So bekommt man \\'Anführungszeichen\\\" und ein \\$-Zeichen und einen\\nZeilenumbruch und ein \\\\ usw... \"\n",
"print(s)"
]
},
{
"cell_type": "markdown",
"id": "f8a758f6",
"metadata": {},
"source": [
"### Triple-Quotes\n",
"\n",
"Man kann Strings auch mit Triple-Quotes begrenzen. \n",
"In dieser Form bleiben Zeilenumbrüche und Anführungszeichen erhalten:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a042c5ed",
"metadata": {},
"outputs": [],
"source": [
"s = \"\"\"\n",
" Das soll\n",
"ein \"längerer\" \n",
" 'Text' sein.\n",
"\"\"\"\n",
"\n",
"print(s)"
]
},
{
"cell_type": "markdown",
"id": "7ff4c2dd",
"metadata": {},
"source": [
"### Raw strings\n",
"\n",
"In einem `raw string` sind alle backslash-Codierungen außer `\\\"` abgeschaltet:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "929529cf",
"metadata": {},
"outputs": [],
"source": [
"s = raw\"Ein $ und ein \\ und zwei \\\\ und ein 'bla'...\"\n",
"print(s)"
]
},
{
"cell_type": "markdown",
"id": "0040e4d6",
"metadata": {},
"source": [
"## Weitere Funktionen für Zeichen und Strings (Auswahl)\n",
"\n",
"### Tests für Zeichen\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "195a2a3e",
"metadata": {},
"outputs": [],
"source": [
"@show isdigit('0') isletter('Ψ') isascii('\\U2655') islowercase('α') \n",
"@show isnumeric('½') iscntrl('\\n') ispunct(';');"
]
},
{
"cell_type": "markdown",
"id": "2e50dae6",
"metadata": {},
"source": [
"### Anwendung auf Strings\n",
"\n",
"Diese Tests lassen sich z.B. mit `all()`, `any()` oder `count()` auf Strings anwenden:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c778a4ad",
"metadata": {},
"outputs": [],
"source": [
"all(ispunct, \";.:\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6a162d83",
"metadata": {},
"outputs": [],
"source": [
"any(isdigit, \"Es ist 3 Uhr! 🕒\" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c2d57533",
"metadata": {},
"outputs": [],
"source": [
"count(islowercase, \"Hello, du!!\")"
]
},
{
"cell_type": "markdown",
"id": "f6562800",
"metadata": {},
"source": [
"### Weitere String-Funktionen\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "495799ef",
"metadata": {},
"outputs": [],
"source": [
"@show startswith(\"Lampenschirm\", \"Lamp\") occursin(\"pensch\", \"Lampenschirm\") \n",
"@show endswith(\"Lampenschirm\", \"irm\"); "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13e4d303",
"metadata": {},
"outputs": [],
"source": [
"@show uppercase(\"Eis\") lowercase(\"Eis\") titlecase(\"eiSen\");"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "36451c74",
"metadata": {},
"outputs": [],
"source": [
"# remove newline from end of string\n",
"\n",
"@show chomp(\"Eis\\n\") chomp(\"Eis\");"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a665d380",
"metadata": {},
"outputs": [],
"source": [
"split(\"π ist irrational.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "64967f02",
"metadata": {},
"outputs": [],
"source": [
"replace(\"π ist irrational.\", \"ist\" => \"ist angeblich\")"
]
},
{
"cell_type": "markdown",
"id": "663832cf",
"metadata": {},
"source": [
"## Indizierung von Strings\n",
"\n",
"Strings sind nicht mutierbar aber indizierbar. Dabei gibt es ein paar Besonderheiten.\n",
"\n",
"- Der Index nummeriert die Bytes des Strings. \n",
"- Bei einem nicht-ASCII-String sind nicht alle Indizes gültig, denn\n",
"- ein gültiger Index adressiert immer ein Unicode-Zeichen.\n",
"\n",
"Unser Beispielstring:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "23d51f20",
"metadata": {},
"outputs": [],
"source": [
"str"
]
},
{
"cell_type": "markdown",
"id": "639c88fa",
"metadata": {},
"source": [
"Das erste Zeichen\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "68ba5cb6",
"metadata": {},
"outputs": [],
"source": [
"str[1]"
]
},
{
"cell_type": "markdown",
"id": "44617a04",
"metadata": {},
"source": [
"Dieses Zeichen ist in UTF8-Kodierung 4 Bytes lang. Damit sind 2,3 und 4 ungültige Indizes. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c4575cca",
"metadata": {},
"outputs": [],
"source": [
"str[2]"
]
},
{
"cell_type": "markdown",
"id": "e558202c",
"metadata": {},
"source": [
"Erst das 5. Byte ist ein neues Zeichen:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3813bbdf",
"metadata": {},
"outputs": [],
"source": [
"str[5]"
]
},
{
"cell_type": "markdown",
"id": "48f4cca9",
"metadata": {},
"source": [
"Auch bei der Adressierung von Substrings müssen Anfang und Ende jeweils gültige Indizes sein, d.h., der Endindex muss ebenfalls das erste Byte eines Zeichens indizieren und dieses Zeichen ist das letzte des Teilstrings. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "546d4ed2",
"metadata": {},
"outputs": [],
"source": [
"str[1:7]"
]
},
{
"cell_type": "markdown",
"id": "1007a717",
"metadata": {},
"source": [
"Die Funktion `eachindex()` liefert einen Iterator über die gültigen Indizes:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d01e440e",
"metadata": {},
"outputs": [],
"source": [
"for i in eachindex(str)\n",
" c = str[i]\n",
" println(\"$i: $c\")\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "2f35e6bf",
"metadata": {},
"source": [
"Wie üblich macht collect() aus einem Iterator einen Vektor.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b1644ea5",
"metadata": {},
"outputs": [],
"source": [
"collect(eachindex(str))"
]
},
{
"cell_type": "markdown",
"id": "dc77d9e5",
"metadata": {},
"source": [
"Die Funktion `nextind()` liefert den nächsten gültigen Index.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5c9f35e7",
"metadata": {},
"outputs": [],
"source": [
"@show nextind(str, 1) nextind(str, 2); "
]
},
{
"cell_type": "markdown",
"id": "6d1e346b",
"metadata": {},
"source": [
"Warum verwendet Julia einen Byte-Index und keinen Zeichenindex? Der Hauptgrund dürfte die Effizienz der Indizierung sein.\n",
"\n",
"- In einem langen String, z.B. einem Buchtext, ist die Stelle `s[123455]` mit einem Byte-Index schnell zu finden. \n",
"- Ein Zeichen-Index müsste in der UTF-8-Codierung den ganzen String durchlaufen, um das n-te Zeichen zu finden, da die Zeichen 1,2,3 oder 4 Bytes lang sein können.\n",
"\n",
"\n",
"Einige Funktionen liefern Indizes oder Ranges als Resultat. Sie liefern immer gültige Indizes:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e1ec4807",
"metadata": {},
"outputs": [],
"source": [
"findfirst('l', str)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2f8520fd",
"metadata": {},
"outputs": [],
"source": [
"findfirst(\"Hel\", str)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0f07cff3",
"metadata": {},
"outputs": [],
"source": [
"str2 = \"αβγδϵ\"^3"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "19e5bcc4",
"metadata": {},
"outputs": [],
"source": [
"n = findfirst('γ', str2)"
]
},
{
"cell_type": "markdown",
"id": "f614e688",
"metadata": {},
"source": [
"So kann man ab dem nächsten nach `n=5` gültigen Index weitersuchen:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3f3b90b4",
"metadata": {},
"outputs": [],
"source": [
"findnext('γ', str2, nextind(str2, n))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.10.2",
"language": "julia",
"name": "julia-1.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,335 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "32301000",
"metadata": {},
"source": [
"# Arbeit mit Julia: REPL, Pakete, Introspection\n",
"\n",
"\n",
"\n",
"## Dokumentation\n",
"\n",
"Die offizielle Julia-Dokumentation [https://docs.julialang.org/](https://docs.julialang.org/) enthält zahlreiche Übersichten, darunter:\n",
"\n",
" - [https://docs.julialang.org/en/v1/base/punctuation/](https://docs.julialang.org/en/v1/base/punctuation/) Verzeichnis der Symbole\n",
" - [https://docs.julialang.org/en/v1/manual/unicode-input/](https://docs.julialang.org/en/v1/manual/unicode-input/) Verzeichnis spezieller Unicode-Symbole und deren Eingabe in Julia via Tab-Vervollständigung\n",
" - [https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions) Liste mathematischer Funktionen \n",
"\n",
"\n",
"\n",
"\n",
"## Julia REPL (Read - Eval - Print - Loop)\n",
"\n",
"Nach dem Start von Julia in einem Terminal kann man neben Julia-Code auch verschiedene Kommandos eingeben \n",
"\n",
":::{.narrow}\n",
"| Kommando | Wirkung |\n",
"| :----------------------------| :------------------------ |\n",
"| `exit()` oder `Ctrl-d` | exit Julia |\n",
"| `Ctrl-c` | interrupt |\n",
"| `Ctrl-l` | clear screen |\n",
"| Kommando mit `;` beenden | Ausgabe unterdrückt |\n",
"| `include(\"filename.jl\")` | Datei mit Julia-Code einlesen und ausführen |\n",
"\n",
"\n",
"\n",
"Der REPL hat verschiedene Modi: \n",
"\n",
"| Modus | Prompt | Modus starten | Modus verlassen |\n",
"| :- | :- | :- | :- |\n",
"| default| `julia>` | | `Ctrl-d`|\n",
"| Package manager | `pkg>` | `]` | `backspace` |\n",
"| Help | `help?>` | `?`| `backspace `|\n",
"|Shell | `shell>` | `;` | `backspace`|\n",
"\n",
":::\n",
"\n",
"\n",
"## Jupyter-Notebooks (IJulia)\n",
"\n",
"\n",
"In einem Jupyter-Notebook sind die Modi sind als Einzeiler in einer eigenen Input-Zelle nutzbar: \n",
"\n",
"(i) ein Kommando des Paket-Managers:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "efacde4f",
"metadata": {},
"outputs": [],
"source": [
"#| eval: false\n",
"] status "
]
},
{
"cell_type": "markdown",
"id": "85fec425",
"metadata": {},
"source": [
"(ii) eine Help-Abfrage:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "80535b76",
"metadata": {},
"outputs": [],
"source": [
"#| eval: false\n",
"?sin"
]
},
{
"cell_type": "markdown",
"id": "581aae68",
"metadata": {},
"source": [
"(iii) Ein Shell-Kommando:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c2438155",
"metadata": {},
"outputs": [],
"source": [
"#| eval: false\n",
";ls "
]
},
{
"cell_type": "markdown",
"id": "bd2c64b7",
"metadata": {},
"source": [
"## Der Paketmanager\n",
"\n",
"Wichtiger Teil des _Julia Ecosystems_ sind die zahlreichen Pakete, die Julia erweitern.\n",
"\n",
"- Einige Pakete sind Teil jeder Julia-Installation und müssen nur mit einer `using Paketname`-Anweisung aktiviert werden. \n",
" - Sie bilden die sogenannte _Standard Library_ und dazu gehören \n",
" - `LinearAlgebra`, `Statistics`, `SparseArrays`, `Printf`, `Pkg` und andere.\n",
"- Über 9000 Pakete sind offiziell registriert, siehe [https://julialang.org/packages/](https://julialang.org/packages/). \n",
" - Diese können mit wenigen Tastendrücken heruntergeladen und installiert werden.\n",
" - Dazu dient der _package manager_ `Pkg`.\n",
" - Man kann ihn auf zwei Arten verwenden: \n",
" - als normale Julia-Anweisungen, die auch in einer `.jl`-Programmdatei stehen können:\n",
" ```\n",
" using Pkg\n",
" Pkg.add(\"PaketXY\")\n",
" ```\n",
" - im speziellen pkg-Modus des Julia-REPLs:\n",
" ```\n",
" ] add PaketXY\n",
" ```\n",
" - Anschließend kann das Paket mit `using PaketXY` verwendet werden.\n",
"- Man kann auch Pakete aus anderen Quellen und selbstgeschriebene Pakete installieren.\n",
"\n",
" \n",
"### Einige Funktionen des Paketmanagers\n",
"\n",
"| Funktion | `pkg` - Mode | Erklärung |\n",
"|:------------------------|:--------------------------| :-------------------------------------------------------|\n",
"| `Pkg.add(\"MyPack\")` | `pkg> add MyPack` | add `MyPack.jl` to current environment |\n",
"| `Pkg.rm(\"MyPack\")` | `pkg> remove MyPack` | remove `MyPack.jl` from current environment |\n",
"| `Pkg.update()` | `pkg> update` | update packages in current environment |\n",
"| `Pkg.activate(\"mydir\")` | `pkg> activate mydir` | activate directory as current environment |\n",
"| `Pkg.status()` | `pkg> status` | list packages |\n",
"| `Pkg.instantiate()` | `pg> instantiate` | install all packages according to `Project.toml` |\n",
"\n",
"\n",
"### Installierte Pakete und Environments \n",
"\n",
"- Julia und der Paketmanager verwalten \n",
" 1. eine Liste der mit dem Kommando `Pkg.add()` bzw. `]add` explizit installierten Pakete mit genauer Versionsbezeichnung in einer Datei `Project.toml` und \n",
" 2. eine Liste aller dabei auch als implizite Abhängigkeiten installierten Pakete in der Datei `Manifest.toml`. \n",
"- Das Verzeichnis, in dem diese Dateien stehen, ist das `environment` und wird mit `Pkg.status()` bzw. `]status` angezeigt. \n",
"- Im Normalfall sieht das so aus: \n",
"\n",
"```\n",
"(@v1.8) pkg> status\n",
" Status `~/.julia/environments/v1.8/Project.toml`\n",
" [1dea7af3] OrdinaryDiffEq v6.7.1\n",
" [91a5bcdd] Plots v1.27.1\n",
" [438e738f] PyCall v1.93.1\n",
"```\n",
"\n",
"- Man kann für verschiedene Projekte eigene `environments` benutzen. Dazu kann man entweder Julia mit \n",
"```shell\n",
"julia --project=path/to/myproject\n",
"```\n",
"starten oder in Julia das environment mit `Pkg.activate(\"path/to/myproject\")` aktivieren. Dann werden `Project.toml, Manifest.toml` dort angelegt und verwaltet. (Die Installation der Paketdateien erfolgt weiterhin irgendwo unter `$HOME/.julia`) \n",
"\n",
"\n",
"### Zum Installieren von Paketen auf unserem Jupyter-Server `misun103`:\n",
"\n",
"- Es gibt ein zentrales Repository, in dem alle in diesem Kurs erwähnten Pakete bereits installiert sind. \n",
"- Dort haben Sie keine Schreibrechte.\n",
"- Sie können aber zusätzliche Pakete in Ihrem `HOME` installieren. Dazu ist als erster Befehl nötig, das aktuelle Verzeichnis zu aktivieren: \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "87138f78",
"metadata": {},
"outputs": [],
"source": [
"#| eval: false\n",
"] activate ."
]
},
{
"cell_type": "markdown",
"id": "da9c6bb6",
"metadata": {},
"source": [
"(Man beachte den Punkt!)\n",
"\n",
"\n",
"Danach können Sie mit `add` im Pkg-Modus auch Pakete installieren:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7a9e6ab0",
"metadata": {},
"outputs": [],
"source": [
"#| eval: false\n",
"] add PaketXY"
]
},
{
"cell_type": "markdown",
"id": "d5fc8aef",
"metadata": {},
"source": [
"Achtung! Das kann dauern! Viele Pakete haben komplexe Abhängigkeiten und lösen die Installation von weiteren Paketen aus. Viele Pakete werden beim Installieren vorkompiliert. Im REPL sieht man den Installationsfortschritt, im Jupyter-Notebook leider nicht.\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"## Der Julia JIT _(just in time)_ Compiler: Introspection\n",
"\n",
"Julia baut auf die Werkzeuge des _LLVM Compiler Infrastructure Projects_ auf.\n",
"\n",
":::{.narrow}\n",
"Stages of Compilation \n",
"\n",
"| stage & result | introspection command |\n",
"| :--- | :--- |\n",
"|Parse $\\Longrightarrow$ Abstract Syntax Tree (AST) | `Meta.parse()` |\n",
"| Lowering: transform AST $\\Longrightarrow$ Static Single Assignment (SSA) form | `@code_lowered`|\n",
"| Type Inference | `@code_warntype`, `@code_typed` |\n",
"| Generate LLVM intermediate representation | `@code_llvm`|\n",
"| Generate native machine code | `@code_native` |\n",
"\n",
":::\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bc5fdcec",
"metadata": {},
"outputs": [],
"source": [
"function f(x,y)\n",
" z = x^2 + log(y)\n",
" return 2z\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bb56b5a6",
"metadata": {},
"outputs": [],
"source": [
"p = Meta.parse( \"function f(x,y); z=x^2+log(y); return 2x; end \")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9a8825dd",
"metadata": {},
"outputs": [],
"source": [
"using TreeView\n",
"\n",
"walk_tree(p)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aa2d2ada",
"metadata": {},
"outputs": [],
"source": [
"@code_lowered f(2,4)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e6303b02",
"metadata": {},
"outputs": [],
"source": [
"@code_warntype f(2,4)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "05f5a0cd",
"metadata": {},
"outputs": [],
"source": [
"@code_typed f(2,4)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "523e86a5",
"metadata": {},
"outputs": [],
"source": [
"@code_llvm f(2,4)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "953d5e83",
"metadata": {},
"outputs": [],
"source": [
"@code_native f(2,4)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.10.2",
"language": "julia",
"name": "julia-1.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,755 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "81cc02aa",
"metadata": {},
"source": [
"# Container\n",
"\n",
"\n",
"Julia bietet eine große Auswahl von Containertypen mit weitgehend ähnlichem Interface an. \n",
"Wir stellen hier `Tuple`, `Range` und `Dict` vor, im nächsten Kapitel dann `Array`, `Vector` und `Matrix`. \n",
"\n",
"Diese Container sind: \n",
"\n",
"- **iterierbar:** Man kann über die Elemente des Containers iterieren: \n",
"```julia \n",
"for x ∈ container ... end\n",
"```\n",
"- **indizierbar:** Man kann auf Elemente über ihren Index zugreifen: \n",
"```julia\n",
"x = container[i]\n",
"``` \n",
"und einige sind auch \n",
"\n",
"- **mutierbar**: Man kann Elemente hinzufügen, entfernen und ändern.\n",
"\n",
"Weiterhin gibt es eine Reihe gemeinsamer Funktionen, z.B.\n",
"\n",
"- `length(container)` --- Anzahl der Elemente\n",
"- `eltype(container)` --- Typ der Elemente\n",
"- `isempty(container)` --- Test, ob Container leer ist\n",
"- `empty!(container)` --- leert Container (nur wenn mutierbar)\n",
"\n",
"\n",
"## Tupeln\n",
"\n",
"Ein Tupel ist ein nicht mutierbarer Container von Elementen. Es ist also nicht möglich, neue Elemente dazuzufügen oder den Wert eines Elements zu ändern. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ec893f0b",
"metadata": {},
"outputs": [],
"source": [
"t = (33, 4.5, \"Hello\")\n",
"\n",
"@show t[2] # indizierbar\n",
"\n",
"for i ∈ t println(i) end # iterierbar"
]
},
{
"cell_type": "markdown",
"id": "21549769",
"metadata": {},
"source": [
"Ein Tupel ist ein **inhomogener** Typ. Jedes Element hat seinen eigenen Typ und das zeigt sich auch im Typ des Tupels:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5add8abb",
"metadata": {},
"outputs": [],
"source": [
"typeof(t)"
]
},
{
"cell_type": "markdown",
"id": "e8bc972e",
"metadata": {},
"source": [
"Man verwendet Tupel gerne als Rückgabewerte von Funktionen, um mehr als ein Objekt zurückzulieferen.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "85b3f1fd",
"metadata": {},
"outputs": [],
"source": [
"# Ganzzahldivision und Rest: \n",
"# Quotient und Rest werden den Variablen q und r zugewiesen\n",
"\n",
"q, r = divrem(71, 6)\n",
"@show q r;"
]
},
{
"cell_type": "markdown",
"id": "d144679d",
"metadata": {},
"source": [
"Wie man hier sieht, kann man in bestimmten Konstrukten die Klammern auch weglassen.\n",
"Dieses *implict tuple packing/unpacking* verwendet man auch gerne in Mehrfachzuweisungen:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2ef18811",
"metadata": {},
"outputs": [],
"source": [
"x, y, z = 12, 17, 203"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "759e8783",
"metadata": {},
"outputs": [],
"source": [
"y"
]
},
{
"cell_type": "markdown",
"id": "2bed8606",
"metadata": {},
"source": [
"Manche Funktionen bestehen auf Tupeln als Argument oder geben immer Tupeln zurück. Dann braucht man manchmal ein Tupel aus einem Element. \n",
"\n",
"Das notiert man so:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e985c23d",
"metadata": {},
"outputs": [],
"source": [
"x = (13,) # ein 1-Element-Tupel"
]
},
{
"cell_type": "markdown",
"id": "174aed3a",
"metadata": {},
"source": [
"Das Komma - und nicht die Klammern -- macht das Tupel. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8359e689",
"metadata": {},
"outputs": [],
"source": [
"x= (13) # kein Tupel"
]
},
{
"cell_type": "markdown",
"id": "a5fb2b62",
"metadata": {},
"source": [
"## Ranges\n",
"\n",
"Wir haben *range*-Objekte schon in numerischen `for`-Schleifen verwendet.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ba823baf",
"metadata": {},
"outputs": [],
"source": [
"r = 1:1000\n",
"typeof(r)"
]
},
{
"cell_type": "markdown",
"id": "6dd2ebf4",
"metadata": {},
"source": [
"Es gibt verschiedene *range*-Typen. Wie man sieht, sind es über den Zahlentyp parametrisierte Typen und `UnitRange` ist z.B. ein *range* mit der Schrittweite 1. Ihre Konstruktoren heißen in der Regel `range()`. \n",
"\n",
"Der Doppelpunkt ist eine spezielle Syntax. \n",
"\n",
"- `a:b` wird vom Parser umgesetzt zu `range(a, b)` \n",
"- `a:b:c` wird umgesetzt zu `range(a, c, step=b)`\n",
"\n",
"\n",
"*Ranges* sind offensichtlich iterierbar, nicht mutierbar aber indizierbar.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5ee0a9ef",
"metadata": {},
"outputs": [],
"source": [
"(3:100)[20] # das zwanzigste Element"
]
},
{
"cell_type": "markdown",
"id": "f4524b63",
"metadata": {},
"source": [
"Wir erinnern an die Semantik der `for`-Schleife: `for i in 1:1000` heißt **nicht**:\n",
"\n",
"- 'Die Schleifenvariable `i` wird bei jedem Durchlauf um eins erhöht' **sondern** \n",
"- 'Der Schleifenvariable werden nacheinander die Werte 1,2,3,...,1000 aus dem Container zugewiesen'. \n",
"\n",
"Allerdings wäre es sehr ineffektiv, diesen Container tatsächlich explizit anzulegen. \n",
"\n",
"- _Ranges_ sind \"lazy\" Vektoren, die nie wirklich irgendwo als konkrete Liste abgespeichert werden. Das macht sie als Iteratoren in `for`-Schleifen so nützlich: speichersparend und schnell.\n",
"- Sie sind 'Rezepte' oder Generatoren, die auf die Abfrage 'Gib mir dein nächstes Element!' antworten.\n",
"- Tatsächlich ist der Muttertyp `AbstractRange` ein Subtyp von `AbstractVector`.\n",
"\n",
"Das Macro `@allocated` gibt aus, wieviel Bytes an Speicher bei der Auswertung eines Ausdrucks alloziert wurden.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7049d454",
"metadata": {},
"outputs": [],
"source": [
"@allocated [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dbc66a57",
"metadata": {},
"outputs": [],
"source": [
"@allocated 1:20"
]
},
{
"cell_type": "markdown",
"id": "3d98f5f4",
"metadata": {},
"source": [
"Zum Umwandeln in einen 'richtigen' Vektor dient die Funktion `collect()`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fe033c47",
"metadata": {},
"outputs": [],
"source": [
"collect(20:-3:1)"
]
},
{
"cell_type": "markdown",
"id": "a94e5258",
"metadata": {},
"source": [
"Recht nützlich, z.B. beim Vorbereiten von Daten zum Plotten, ist der *range*-Typ `LinRange`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e4b40085",
"metadata": {},
"outputs": [],
"source": [
"LinRange(2, 50, 300)"
]
},
{
"cell_type": "markdown",
"id": "bde8b38f",
"metadata": {},
"source": [
"`LinRange(start, stop, n)` erzeugt eine äquidistante Liste von `n` Werten von denen der erste und der letzte die vorgegebenen Grenzen sind. \n",
"Mit `collect()` kann man bei Bedarf auch daraus den entsprechenden Vektor gewinnen.\n",
"\n",
"\n",
"## Dictionaries \n",
"\n",
"- _Dictionaries_ (deutsch: \"assoziative Liste\" oder \"Zuordnungstabelle\" oder ...) sind spezielle Container. \n",
"- Einträge in einem Vektor `v` sind durch einen Index 1,2,3.... addressierbar: `v[i]`\n",
"- Einträge in einem _dictionary_ sind durch allgemeinere _keys_ addressierbar. \n",
"- Ein _dictionary_ ist eine Ansammlung von _key-value_-Paaren.\n",
"- Damit haben _dictionaries_ in Julia den parametrisierten Typ `Dict{S,T}`, wobei `S` der Typ der _keys_ und `T` der Typ der _values_ ist\n",
"\n",
"\n",
"Man kann sie explizit anlegen:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "25c7aefc",
"metadata": {},
"outputs": [],
"source": [
"# Einwohner 2020 in Millionen, Quelle: wikipedia\n",
"\n",
"EW = Dict(\"Berlin\" => 3.66, \"Hamburg\" => 1.85, \n",
" \"München\" => 1.49, \"Köln\" => 1.08)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9620f365",
"metadata": {},
"outputs": [],
"source": [
"typeof(EW)"
]
},
{
"cell_type": "markdown",
"id": "d3b4d2af",
"metadata": {},
"source": [
"und mit den _keys_ indizieren:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "62938a1b",
"metadata": {},
"outputs": [],
"source": [
"EW[\"Berlin\"]"
]
},
{
"cell_type": "markdown",
"id": "73ddf61d",
"metadata": {},
"source": [
"Das Abfragen eines nicht existierenden _keys_ ist natürlich ein Fehler.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6e16eb41",
"metadata": {},
"outputs": [],
"source": [
"EW[\"Leipzig\"]"
]
},
{
"cell_type": "markdown",
"id": "49a6d001",
"metadata": {},
"source": [
"Man kann ja auch vorher mal anfragen...\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e43aec5d",
"metadata": {},
"outputs": [],
"source": [
"haskey(EW, \"Leipzig\")"
]
},
{
"cell_type": "markdown",
"id": "a1cefaa1",
"metadata": {},
"source": [
"... oder die Funktion `get(dict, key, default)` benutzen, die bei nicht existierendem Key keinen Fehler wirft sondern das 3. Argument zurückgibt. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e31c792c",
"metadata": {},
"outputs": [],
"source": [
"@show get(EW, \"Leipzig\", -1) get(EW, \"Berlin\", -1);"
]
},
{
"cell_type": "markdown",
"id": "f625eaaa",
"metadata": {},
"source": [
"Man kann sich auch alle `keys` und `values` als spezielle Container geben lassen.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21460e3a",
"metadata": {},
"outputs": [],
"source": [
"keys(EW)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a87d9788",
"metadata": {},
"outputs": [],
"source": [
"values(EW)"
]
},
{
"cell_type": "markdown",
"id": "97b96369",
"metadata": {},
"source": [
"Man kann über die `keys` iterieren...\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "41e9189f",
"metadata": {},
"outputs": [],
"source": [
"for i in keys(EW)\n",
" n = EW[i]\n",
" println(\"Die Stadt $i hat $n Millionen Einwohner.\")\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "b2fe653a",
"metadata": {},
"source": [
"odere gleich über `key-value`-Paare.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0b445207",
"metadata": {},
"outputs": [],
"source": [
"for (stadt, ew) ∈ EW\n",
" println(\"$stadt : $ew Mill.\")\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "6fcd4019",
"metadata": {},
"source": [
"### Erweitern und Modifizieren\n",
"\n",
"Man kann in ein `Dict` zusätzliche `key-value`-Paare eintragen...\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "94c4f076",
"metadata": {},
"outputs": [],
"source": [
"EW[\"Leipzig\"] = 0.52\n",
"EW[\"Dresden\"] = 0.52 \n",
"EW"
]
},
{
"cell_type": "markdown",
"id": "ed90d684",
"metadata": {},
"source": [
"und einen `value` ändern.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c57e8dd2",
"metadata": {},
"outputs": [],
"source": [
"# Oh, das war bei Leipzig die Zahl von 2010, nicht 2020\n",
"\n",
"EW[\"Leipzig\"] = 0.597\n",
"EW"
]
},
{
"cell_type": "markdown",
"id": "3d0eadd7",
"metadata": {},
"source": [
"Ein Paar kann über seinen `key` auch gelöscht werden.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0dfd9f2d",
"metadata": {},
"outputs": [],
"source": [
"delete!(EW, \"Dresden\")"
]
},
{
"cell_type": "markdown",
"id": "3db2aa1f",
"metadata": {},
"source": [
"Zahlreiche Funktionen können mit `Dicts` wie mit anderen Containern arbeiten.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1204aaab",
"metadata": {},
"outputs": [],
"source": [
"maximum(values(EW))"
]
},
{
"cell_type": "markdown",
"id": "6a4946b4",
"metadata": {},
"source": [
"### Anlegen eines leeren Dictionaries\n",
"\n",
"Ohne Typspezifikation ...\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1f82ac79",
"metadata": {},
"outputs": [],
"source": [
"d1 = Dict()"
]
},
{
"cell_type": "markdown",
"id": "27c98eaf",
"metadata": {},
"source": [
"und mit Typspezifikation:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1b8f201e",
"metadata": {},
"outputs": [],
"source": [
"d2 = Dict{String, Int}()"
]
},
{
"cell_type": "markdown",
"id": "7fe71a3b",
"metadata": {},
"source": [
"### Umwandlung in Vektoren: `collect()`\n",
"\n",
"- `keys(dict)` und `values(dict)` sind spezielle Datentypen. \n",
"- Die Funktion `collect()` macht daraus eine Liste vom Typ `Vector`. \n",
"- `collect(dict)` liefert eine Liste vom Typ `Vector{Pair{S,T}}` \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2dc85bdd",
"metadata": {},
"outputs": [],
"source": [
"collect(EW)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "100dbbf1",
"metadata": {},
"outputs": [],
"source": [
"collect(keys(EW)), collect(values(EW))"
]
},
{
"cell_type": "markdown",
"id": "f9703f73",
"metadata": {},
"source": [
"### Geordnetes Iterieren über ein Dictionary\n",
"\n",
"Wir sortieren die Keys. Als Strings werden sie alphabetisch sortiert. Mit dem `rev`-Parameter wird rückwärts sortiert.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3c02f0ca",
"metadata": {},
"outputs": [],
"source": [
"for k in sort(collect(keys(EW)), rev = true)\n",
" n = EW[k]\n",
" println(\"$k hat $n Millionen Einw. \")\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "c20f0654",
"metadata": {},
"source": [
"Wir sortieren `collect(dict)`. Das ist ein Vektor von Paaren. Mit `by` definieren wir, wonach zu sortieren ist: nach dem 2. Element des Paares. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "89ee04e9",
"metadata": {},
"outputs": [],
"source": [
"for (k,v) in sort(collect(EW), by = pair -> last(pair), rev=false)\n",
" println(\"$k hat $v Mill. EW\")\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "94ba9752",
"metadata": {},
"source": [
"### Eine Anwendung von Dictionaries: Zählen von Häufigkeiten\n",
"\n",
"Wir machen 'experimentelle Stochastik' mit 2 Würfeln: \n",
"\n",
"Gegeben sei `l`, eine Liste mit den Ergebnissen von 100 000 Pasch-Würfen, also 100 000 Zahlen zwischen 2 und 12.\n",
"\n",
"Wie häufig sind die Zahlen 2 bis 12?\n",
"\n",
"\n",
"Wir (lassen) würfeln:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a7ff829d",
"metadata": {},
"outputs": [],
"source": [
"l = rand(1:6, 100_000) .+ rand(1:6, 100_000)"
]
},
{
"cell_type": "markdown",
"id": "48a58503",
"metadata": {},
"source": [
"Wir zählen mit Hilfe eines Dictionaries die Häufigkeiten der Ereignisse. Dazu nehmen wir das Ereignis als `key` und seine Häufigkeit als `value`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dd2bcd79",
"metadata": {},
"outputs": [],
"source": [
"# In diesem Fall könnte man das auch mit einem einfachen Vektor\n",
"# lösen. Eine bessere Illustration wäre z.B. Worthäufigkeit in\n",
"# einem Text. Dann ist i keine ganze Zahl sondern ein Wort=String\n",
"\n",
"d = Dict{Int,Int}() # das Dict zum 'reinzählen'\n",
"\n",
"for i in l # für jedes i wird d[i] erhöht. \n",
" d[i] = get(d, i, 0) + 1 \n",
"end\n",
"d"
]
},
{
"cell_type": "markdown",
"id": "62fe53b9",
"metadata": {},
"source": [
"Das Ergebnis:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "154252d3",
"metadata": {},
"outputs": [],
"source": [
"using Plots\n",
"\n",
"plot(collect(keys(d)), collect(values(d)), seriestype=:scatter)"
]
},
{
"cell_type": "markdown",
"id": "dd482553",
"metadata": {},
"source": [
"##### Das Erklär-Bild dazu:\n",
"\n",
"[https://math.stackexchange.com/questions/1204396/why-is-the-sum-of-the-rolls-of-two-dices-a-binomial-distribution-what-is-define](https://math.stackexchange.com/questions/1204396/why-is-the-sum-of-the-rolls-of-two-dices-a-binomial-distribution-what-is-define)\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.10.2",
"language": "julia",
"name": "julia-1.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,341 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "f21dc71b",
"metadata": {},
"source": [
"# Erste Miniprogramme\n",
"\n",
"\n",
"## Was sollte man zum Programmieren können?\n",
"\n",
"\n",
"- **Denken in Algorithmen:** \n",
" Welche Schritte sind zur Lösung des Problems nötig? Welche Daten müssen gespeichert, welche Datenstrukturen angelegt werden? Welche Fälle können auftreten und müssen erkannt und behandelt werden? \n",
"- **Umsetzung des Algorithmus in ein Programm:** \n",
" Welche Datenstrukturen, Konstrukte, Funktionen... stellt die Programmiersprache bereit? \n",
"- **Formale Syntax:** \n",
" Menschen verstehen 'broken English'; Computer verstehen kein 'broken C++' oder 'broken Julia'. Die Syntax muss beherrscht werden.\n",
"- **„Ökosystem“ der Sprache:** \n",
" Wie führe ich meinen Code aus? Wie funktionieren die Entwicklungsumgebungen? Welche Optionen versteht der Compiler? Wie installiere ich Zusatzbibliotheken? Wie lese ich Fehlermeldungen? Wo kann ich mich informieren? \n",
"- **die Kunst des Debugging:** \n",
" Programmieranfänger sind oft glücklich, wenn sie alle Syntaxfehler eliminiert haben und das Programm endlich 'durchläuft'. Bei komplexeren Programmen fängt die Arbeit jetzt erst an, denn nun muss getestet und die Fehler im Algorithmus gefunden und behoben werden. \n",
"- **Gefühl für die Effizienz und Komplexität von Algorithmen**\n",
"- **Besonderheiten der Computerarithmetik**, insbesondere der Gleitkommazahlen\n",
"\n",
"Das erschließt sich nicht alles auf einmal. Haben Sie Geduld mit sich und 'spielen' Sie mit der Sprache. \n",
"\n",
"Das Folgende soll eine kleine Anregung dazu sein.\n",
"\n",
"## Project Euler\n",
"\n",
"Eine hübsche Quelle für Programmieraufgaben mit mathematischem Charakter und sehr unterschiedlichen Schwierigkeitsgraden ist [Project Euler](https://projecteuler.net/). \n",
"Die Aufgaben sind so gestaltet, dass keinerlei Eingaben notwendig und das gesuchte Ergebnis eine einzige Zahl ist. So kann man sich voll auf das Programmieren des Algorithmus konzentrieren. \n",
"\n",
"---------\n",
"\n",
"### Beispiel 1\n",
"\n",
"::::::{.content-hidden unless-format=\"xxx\"}\n",
"\n",
"https://github.com/luckytoilet/projecteuler-solutions/blob/master/Solutions.md\n",
"https://math.stackexchange.com/questions/3370978/iterating-sum-of-squares-of-decimal-digits-of-an-integer-how-big-can-it-grow\n",
"aufg. 92\n",
"\n",
":::\n",
"\n",
"::: {.callout-note icon=false .titlenormal}\n",
"## Project Euler Problem No 1\n",
"\n",
"If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.\n",
"\n",
"Find the sum of all the multiples of 3 or 5 below 1000.\n",
"\n",
":::\n",
"\n",
"1. Algorithmus: \n",
" - Teste alle natürlichen Zahlen <1000 auf Teilbarkeit durch 3 oder durch 5 und\n",
" - summiere die teilbaren Zahlen auf.\n",
"\n",
"2. Umsetzung:\n",
"\n",
" Wie liefert Julia den Rest der Ganzzahldivision? Solche Funktionen heißen typischerweise `rem()` (für *remainder*) oder `mod()`. [Nachlesen in der Doku](https://docs.julialang.org/en/v1/base/math/#Base.rem) oder ausprobieren von `?rem` und `?mod` in der Julia-REPL zeigt, dass es beides gibt. Der Unterschied liegt in der Behandlung negativer ganzer Zahlen. Für natürliche Zahlen `n,m` liefern `mod(n,m)` und `rem(n,m)` dasselbe und letzteres hat auch noch die Infix-Form `n % m`. \n",
" \n",
" Wie testet man eine Reihe von Werten durch und summiert auf? Da gibt es ein Standardmuster: `for`-Schleife und Akkumulatorvariable: \n",
"\n",
":::{.callout-caution icon=\"false\" collapse=\"true\" .titlenormal}\n",
"\n",
"## Eine Lösungsvariante:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "44d0f59e",
"metadata": {},
"outputs": [],
"source": [
"s = 0 # Akkumulatorvariable initialisieren\n",
"for i in 1:999 # Schleife \n",
" if i % 3 == 0 || i % 5 == 0 # Test\n",
" s += i # Zu Akkumulator addieren \n",
" end # Ende Test\n",
"end # Ende Schleife\n",
"println(\" Die Antwort ist: $s\") # Ausgabe des Ergebnisses "
]
},
{
"cell_type": "markdown",
"id": "4d9f5b4f",
"metadata": {},
"source": [
":::\n",
"\n",
"Natürlich geht das auch etwas kürzer:\n",
"\n",
":::{.callout-caution icon=\"false\" collapse=\"true\" .titlenormal}\n",
"\n",
"## Noch eine Lösungsvariante:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9d36a90d",
"metadata": {},
"outputs": [],
"source": [
"sum([i for i in 1:999 if i%3==0||i%5==0])"
]
},
{
"cell_type": "markdown",
"id": "71a52de7",
"metadata": {},
"source": [
":::\n",
"\n",
"\n",
"-----------\n",
"\n",
"### Beispiel 2\n",
"\n",
"\n",
"::: {.callout-note icon=false .titlenormal}\n",
"## Project Euler Problem No 92\n",
"A number chain is created by continuously adding the square of the digits in a number to form a new number until it has been seen before.\n",
"\n",
"For example,\n",
"\n",
"| 44 → 32 → 13 → 10 → **1** → **1**\n",
"| 85 → **89** → 145 → 42 → 20 → 4 → 16 → 37 → 58 → **89**\n",
"\n",
"Therefore any chain that arrives at 1 or 89 will become stuck in an endless loop. What is most amazing is that EVERY starting number will eventually arrive at 1 or 89.\n",
"\n",
"How many starting numbers below ten million will arrive at 89?\n",
":::\n",
"\n",
"Programme kann man [*top-down* und *bottom-up*](https://de.wikipedia.org/wiki/Top-Down-_und_Bottom-Up-Design) entwickeln.\n",
"*Top-down* würde hier wohl bedeuten: „Wir fangen mit einer Schleife `for i = 1:9999999` an.“ Der andere Weg führt über einzeln testbare Komponenten und ist oft zielführender. (Und ab einer gewissen Projektgröße nähert man sich sowieso von 'top' und 'bottom' gleichzeitig dem Ziel.)\n",
"\n",
"##### Funktion Nr. 1\n",
"Es soll untersucht werden, wie sich die Zahlen unter dem wiederholten Berechnen der 'Quadratquersumme' (Summe der Quadrate der Ziffern) verhalten. Also sollte man eine Funktion schreiben und testen, die diese 'Quadratquersumme' berechnet. \n",
"\n",
"\n",
":::{.callout-caution icon=\"false\" collapse=\"true\" .titlenormal}\n",
"\n",
"## `q2sum(n)` berechnet die Summe der Quadrate der Ziffern von n im Dezimalsystem:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15983324",
"metadata": {},
"outputs": [],
"source": [
"#| output: false\n",
"function q2sum(n)\n",
" s = 0 # Akkumulator für die Summe\n",
" while n > 9 # solange noch mehrstellig...\n",
" q, r = divrem(n, 10) # berechne Ganzzahlquotient und Rest bei Division durch 10\n",
" s += r^2 # addiere quadrierte Ziffer zum Akkumulator\n",
" n = q # mache weiter mit der durch 10 geteilten Zahl\n",
" end\n",
" s += n^2 # addiere das Quadrat der letzten Ziffer\n",
" return s\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "7cafe59e",
"metadata": {},
"source": [
":::\n",
"... und das testen wir jetzt natürlich:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "82139e32",
"metadata": {},
"outputs": [],
"source": [
"for i in [1, 7, 33, 111, 321, 1000, 73201]\n",
" j = q2sum(i)\n",
" println(\"Quadratquersumme von $i = $j\")\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "1467ade0",
"metadata": {},
"source": [
"Im Sinne der Aufgabe wenden wir die Funktion wiederholt an:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2a91c9da",
"metadata": {},
"outputs": [],
"source": [
"n = 129956799\n",
"for i in 1:14\n",
" n = q2sum(n)\n",
" println(n)\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "1399219b",
"metadata": {},
"source": [
"... und haben hier einen der '89er Zyklen' getroffen.\n",
"\n",
"\n",
"#### Funktion Nr. 2\n",
"\n",
"Wir müssen testen, ob die wiederholte Anwendung der Funktion `q2sum()` schließlich zu **1** führt oder in diesem **89er**-Zyklus endet.\n",
"\n",
":::{.callout-caution icon=\"false\" collapse=\"true\" .titlenormal}\n",
"\n",
"## `q2test(n)` ermittelt, ob wiederholte Quadratquersummenbildung in den 89er-Zyklus führt:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8b76324d",
"metadata": {},
"outputs": [],
"source": [
"#| output: false\n",
"function q2test(n)\n",
" while n !=1 && n != 89 # solange wir nicht bei 1 oder 89 angekommen sind....\n",
" n = q2sum(n) # wiederholen \n",
" end\n",
" if n==1 return false end # keine 89er-Zahl\n",
" return true # 89er-Zahl gefunden\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "06d73770",
"metadata": {},
"source": [
":::\n",
"\n",
"... und damit können wir die Aufgabe lösen:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7a0051f2",
"metadata": {},
"outputs": [],
"source": [
"c = 0 # mal wieder ein Akkumulator\n",
"for i = 1 : 10_000_000 - 1 # so kann man in Julia Tausenderblöcke zur besseren Lesbarkeit abtrennen\n",
" if q2test(i) # q2test() gibt einen Boolean zurück, kein weiterer Test nötig \n",
" c += 1 # 'if x == true' ist redundant, 'if x' reicht völlig \n",
" end \n",
"end\n",
"println(\"$c numbers below ten million arrive at 89.\")"
]
},
{
"cell_type": "markdown",
"id": "000b5826",
"metadata": {},
"source": [
"Zahlen, bei denen die iterierte Quadratquersummenbildung bei 1 endet, heißen übrigens [fröhliche Zahlen](https://de.wikipedia.org/wiki/Fr%C3%B6hliche_Zahl) und wir haben gerade die Anzahl der traurigen Zahlen kleiner als 10.000.000 berechnet.\n",
"\n",
"Hier nochmal das vollständige Programm:\n",
"\n",
":::{.callout-caution icon=\"false\" collapse=\"true\" .titlenormal}\n",
"## unsere Lösung von Project Euler No 92:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "db3ef4ef",
"metadata": {},
"outputs": [],
"source": [
"function q2sum(n)\n",
" s = 0 \n",
" while n > 9 \n",
" q, r = divrem(n, 10)\n",
" s += r^2 \n",
" n = q \n",
" end\n",
" s += n^2 \n",
" return s\n",
"end\n",
"\n",
"function q2test(n)\n",
" while n !=1 && n != 89 \n",
" n = q2sum(n) \n",
" end\n",
" if n==1 return false end \n",
" return true \n",
"end\n",
"\n",
"c = 0\n",
"for i = 1 : 10_000_000 - 1 \n",
" if q2test(i)\n",
" c += 1\n",
" end \n",
"end\n",
"println(\"$c numbers below ten million arrive at 89.\")"
]
},
{
"cell_type": "markdown",
"id": "8d2084be",
"metadata": {},
"source": [
":::"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.10.2",
"language": "julia",
"name": "julia-1.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,233 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "0b96655f",
"metadata": {},
"source": [
"# Ein Beispiel zur Stabilität von Gleitkommaarithmetik\n",
"\n",
"## Berechnung von $\\pi$ nach Archimedes\n",
"\n",
"\n",
"\n",
"Eine untere Schranke für $2\\pi$, den Umfang des Einheitskreises, erhält man durch die\n",
"Summe der Seitenlängen eines dem Einheitskreis eingeschriebenen regelmäßigen $n$-Ecks.\n",
" Die Abbildung links zeigt, wie man beginnend mit einem Viereck der Seitenlänge $s_4=\\sqrt{2}$ die Eckenzahl iterativ verdoppelt.\n",
"\n",
"| Abb. 1 | Abb.2 |\n",
"| :-: | :-: |\n",
"| ![](../images/pi1.png) | ![](../images/pi2.png) |\n",
"\n",
"Die zweite Abbildung zeigt die Geometrie der Eckenverdoppelung.\n",
"\n",
"Mit\n",
"$|\\overline{AC}|= s_{n},\\quad |\\overline{AB}|= |\\overline{BC}|= s_{2n},\\quad |\\overline{MN}| =a, \\quad |\\overline{NB}| =1-a,$ liefert Pythagoras für die Dreiecke $MNA$ und\n",
" $NBA$ jeweils\n",
"$$\n",
" a^2 + \\left(\\frac{s_{n}}{2}\\right)^2 = 1\\qquad\\text{bzw.} \\qquad\n",
" (1-a)^2 + \\left(\\frac{s_{n}}{2}\\right)^2 = s_{2n}^2\n",
"$$\n",
"Elimination von $a$ liefert die Rekursion\n",
"$$\n",
" s_{2n} = \\sqrt{2-\\sqrt{4-s_n^2}} \\qquad\\text{mit Startwert}\\qquad\n",
" s_4=\\sqrt{2}\n",
"$$\n",
"für die Länge $s_n$ **einer** Seite des eingeschriebenen regelmäßigen\n",
"$n$-Ecks.\n",
"\n",
"\n",
"Die Folge $(n\\cdot s_n)$\n",
"konvergiert monoton von unten gegen den\n",
"Grenzwert $2\\pi$:\n",
"$$\n",
" n\\, s_n \\rightarrow 2\\pi % \\qquad\\text{und} \\qquad {n c_n}\\downarrow 2\\pi\n",
"$$\n",
"Der relative Fehler der Approximation von 2π durch ein $n$-Eck ist:\n",
"$$\n",
" \\epsilon_n = \\left| \\frac{n\\, s_n-2 \\pi}{2\\pi} \\right|\n",
"$$\n",
"\n",
"\n",
"## Zwei Iterationsvorschriften^[nach: Christoph Überhuber, „Computer-Numerik“ Bd. 1, Springer 1995, Kap. 2.3]\n",
"Die Gleichung\n",
"$$\n",
" s_{2n} = \\sqrt{2-\\sqrt{4-s_n^2}}\\qquad \\qquad \\textrm{(Iteration A)}\n",
"$$\n",
"ist mathematisch äquivalent zu\n",
"$$\n",
" s_{2n} = \\frac{s_n}{\\sqrt{2+\\sqrt{4-s_n^2}}} \\qquad \\qquad \\textrm{(Iteration B)}\n",
"$$\n",
"\n",
"(Bitte nachrechnen!) \n",
"\n",
"\n",
"\n",
"Allerdings ist Iteration A schlecht konditioniert und numerisch instabil, wie der folgende Code zeigt. Ausgegeben wird die jeweils berechnete Näherung für π.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fa3be89a",
"metadata": {},
"outputs": [],
"source": [
"using Printf\n",
"\n",
"iterationA(s) = sqrt(2 - sqrt(4 - s^2))\n",
"iterationB(s) = s / sqrt(2 + sqrt(4 - s^2))\n",
"\n",
"s_B = s_A = sqrt(2) # Startwert \n",
"\n",
"ϵ(x) = abs(x - 2π)/2π # rel. Fehler \n",
"\n",
"ϵ_A = Float64[] # Vektoren für den Plot\n",
"ϵ_B = Float64[]\n",
"is = Float64[]\n",
"\n",
"@printf \"\"\" approx. Wert von π\n",
" n-Eck Iteration A Iteration B\n",
"\"\"\"\n",
"\n",
"for i in 3:35\n",
" push!(is, i)\n",
" s_A = iterationA(s_A) \n",
" s_B = iterationB(s_B) \n",
" doublePi_A = 2^i * s_A\n",
" doublePi_B = 2^i * s_B\n",
" push!(ϵ_A, ϵ(doublePi_A))\n",
" push!(ϵ_B, ϵ(doublePi_B))\n",
" @printf \"%14i %20.15f %20.15f\\n\" 2^i doublePi_A/2 doublePi_B/2 \n",
"end"
]
},
{
"cell_type": "markdown",
"id": "7ce50a85",
"metadata": {},
"source": [
"Während Iteration B sich stabilisiert bei einem innerhalb der Maschinengenauigkeit korrekten Wert für π, wird Iteration A schnell instabil. Ein Plot der relativen Fehler $\\epsilon_i$ bestätigt das:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5004b70e",
"metadata": {},
"outputs": [],
"source": [
"using CairoMakie\n",
"\n",
"F = Figure(resolution=(800,500))\n",
"ax = Axis(F[1, 1], xlabel = \"Iterationsschritte\", ylabel = \"rel. Fehler\",\n",
" yscale = log10, xticks=2:2:35, yticks=LogTicks(-20:0))\n",
"\n",
"scatterlines!(ax, is, ϵ_A, label = \"Iteration A\" )\n",
"scatterlines!(ax, is, ϵ_B, marker=:xcross, label = \"Iteration B\" )\n",
"\n",
"axislegend(position=:rc)\n",
"F"
]
},
{
"cell_type": "markdown",
"id": "7a93c5e3",
"metadata": {},
"source": [
"## Stabilität und Auslöschung\n",
"\n",
"Bei $i=26$ erreicht Iteration B einen relativen Fehler in der Größe des Maschinenepsilons:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "527eee0e",
"metadata": {},
"outputs": [],
"source": [
"ϵ_B[22:28]"
]
},
{
"cell_type": "markdown",
"id": "6f2f4475",
"metadata": {},
"source": [
"Weitere Iterationen verbessern das Ergebnis nicht mehr. Sie stabilisieren sich bei einem relativen Fehler von etwa 2.5 Maschinenepsilon:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3b2a8b77",
"metadata": {},
"outputs": [],
"source": [
"ϵ_B[end]/eps(Float64)"
]
},
{
"cell_type": "markdown",
"id": "6ff2d4b8",
"metadata": {},
"source": [
"Die Form Iteration A ist instabil. Bereits bei $i=16$ beginnt der relative Fehler wieder zu wachsen.\n",
"\n",
"Ursache ist eine typische Auslöschung. Die Seitenlängen $s_n$ werden sehr schnell klein. Damit ist\n",
"$a_n=\\sqrt{4-s_n^2}$ nur noch wenig kleiner als 2 und bei der Berechnung von $s_{2n}=\\sqrt{2-a_n}$ tritt ein typischer Auslöschungseffekt auf.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ca6c5ca2",
"metadata": {},
"outputs": [],
"source": [
"setprecision(80) # precision für BigFloat\n",
"\n",
"s = sqrt(BigFloat(2))\n",
"\n",
"@printf \" a = √(4-s^2) als BigFloat und als Float64\\n\\n\"\n",
"\n",
"for i = 3:44\n",
" s = iterationA(s)\n",
" x = sqrt(4-s^2)\n",
" if i > 20\n",
" @printf \"%i %30.26f %20.16f \\n\" i x Float64(x)\n",
" end \n",
"end\n"
]
},
{
"cell_type": "markdown",
"id": "5e4994b3",
"metadata": {},
"source": [
"Man sieht die Abnahme der Zahl der signifikanten Ziffern. Man sieht auch, dass eine Verwendung von `BigFloat` mit einer Mantissenlänge von hier 80 Bit das Einsetzen des Auslöschungseffekts nur etwas hinaussschieben kann. \n",
"\n",
"**Gegen instabile Algorithmen helfen in der Regel nur bessere, stabile Algorithmen und nicht genauere Maschinenzahlen!**\n",
"\n",
":::{.content-hidden unless-format=\"xxx\"}\n",
"\n",
"Offensichtlich tritt bei der Berechnung von $2-a_n$ bereits relativ früh\n",
"eine Abnahme der Anzahl der signifikanten Ziffern (Auslöschung) auf, \n",
"bevor schließlich bei der Berechnung von $a_n=\\sqrt{4-s_n^2}$ \n",
"selbst schon Auslöschung zu einem unbrauchbaren Ergebnis führt.\n",
"\n",
":::"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.8.5",
"language": "julia",
"name": "julia-1.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,313 +0,0 @@
{
"cells": [
{
"cell_type": "raw",
"id": "9e1ef849",
"metadata": {},
"source": [
"---\n",
"format:\n",
" html:\n",
" include-in-header:\n",
" text: |\n",
" <script type=\"application/javascript\">\n",
" window.PlotlyConfig = {MathJaxConfig: 'local'}\n",
" </script>\n",
"---"
]
},
{
"cell_type": "markdown",
"id": "beff12c8",
"metadata": {},
"source": [
"# Ein Beispiel zur Stabilität von Gleitkommaarithmetik\n",
"\n",
"## Berechnung von $\\pi$ nach Archimedes\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a7810264",
"metadata": {},
"outputs": [],
"source": [
"#| error: false\n",
"#| echo: false\n",
"#| output: false\n",
"using PlotlyJS, Random\n",
"using HypertextLiteral\n",
"using JSON, UUIDs\n",
"using Base64\n",
"\n",
"\n",
"## see https://github.com/JuliaPlots/PlotlyJS.jl/blob/master/src/PlotlyJS.jl\n",
"## https://discourse.julialang.org/t/encode-a-plot-to-base64/27765/3\n",
"function IJulia.display_dict(p::PlotlyJS.SyncPlot)\n",
" Dict(\n",
" # \"application/vnd.plotly.v1+json\" => JSON.lower(p),\n",
" # \"text/plain\" => sprint(show, \"text/plain\", p),\n",
" \"text/html\" => let\n",
" buf = IOBuffer()\n",
" show(buf, MIME(\"text/html\"), p)\n",
" #close(buf)\n",
" #String(resize!(buf.data, buf.size))\n",
" String(take!(buf))\n",
" end,\n",
" \"image/png\" => let\n",
" buf = IOBuffer()\n",
" buf64 = Base64EncodePipe(buf)\n",
" show(buf64, MIME(\"image/png\"), p)\n",
" close(buf64)\n",
" #String(resize!(buf.data, buf.size))\n",
" String(take!(buf))\n",
" end,\n",
"\n",
" )\n",
" end\n",
"\n",
" function Base.show(io::IO, mimetype::MIME\"text/html\", p::PlotlyJS.SyncPlot)\n",
" uuid = string(UUIDs.uuid4())\n",
" show(io,mimetype,@htl(\"\"\"\n",
" <div style=\"height: auto\" id=\\\"$(uuid)\\\"></div>\n",
" <script>\n",
" require(['../js/plotly-latest.min.js'], function(plotly) { \n",
" plotly.newPlot($(uuid),\n",
" $(HypertextLiteral.JavaScript(json(p.plot.data))),\n",
" $(HypertextLiteral.JavaScript(json(p.plot.layout))),{responsive: true});\n",
" });\n",
" </script>\n",
"\"\"\"))\n",
"end "
]
},
{
"cell_type": "markdown",
"id": "8d4bd1ab",
"metadata": {},
"source": [
"Eine untere Schranke für $2\\pi$, den Umfang des Einheitskreises, erhält man durch die\n",
"Summe der Seitenlängen eines dem Einheitskreis eingeschriebenen regelmäßigen $n$-Ecks.\n",
" Die Abbildung links zeigt, wie man beginnend mit einem Viereck der Seitenlänge $s_4=\\sqrt{2}$ die Eckenzahl iterativ verdoppelt.\n",
"\n",
":::{.narrow}\n",
"\n",
"| Abb. 1 | Abb.2 |\n",
"| :-: | :-: |\n",
"| ![](../images/pi1.png) | ![](../images/pi2.png) |\n",
": {tbl-colwidths=\"[57,43]\"}\n",
"\n",
":::\n",
"\n",
"\n",
"Die zweite Abbildung zeigt die Geometrie der Eckenverdoppelung.\n",
"\n",
"Mit\n",
"$|\\overline{AC}|= s_{n},\\quad |\\overline{AB}|= |\\overline{BC}|= s_{2n},\\quad |\\overline{MN}| =a, \\quad |\\overline{NB}| =1-a,$ liefert Pythagoras für die Dreiecke $MNA$ und\n",
" $NBA$ jeweils\n",
"$$\n",
" a^2 + \\left(\\frac{s_{n}}{2}\\right)^2 = 1\\qquad\\text{bzw.} \\qquad\n",
" (1-a)^2 + \\left(\\frac{s_{n}}{2}\\right)^2 = s_{2n}^2\n",
"$$\n",
"Elimination von $a$ liefert die Rekursion\n",
"$$\n",
" s_{2n} = \\sqrt{2-\\sqrt{4-s_n^2}} \\qquad\\text{mit Startwert}\\qquad\n",
" s_4=\\sqrt{2}\n",
"$$\n",
"für die Länge $s_n$ **einer** Seite des eingeschriebenen regelmäßigen\n",
"$n$-Ecks.\n",
"\n",
"\n",
"Die Folge $(n\\cdot s_n)$\n",
"konvergiert monoton von unten gegen den\n",
"Grenzwert $2\\pi$:\n",
"$$\n",
" n\\, s_n \\rightarrow 2\\pi % \\qquad\\text{und} \\qquad {n c_n}\\downarrow 2\\pi\n",
"$$\n",
"Der relative Fehler der Approximation von 2π durch ein $n$-Eck ist:\n",
"$$\n",
" \\epsilon_n = \\left| \\frac{n\\, s_n-2 \\pi}{2\\pi} \\right|\n",
"$$\n",
"\n",
"\n",
"## Zwei Iterationsvorschriften^[nach: Christoph Überhuber, „Computer-Numerik“ Bd. 1, Springer 1995, Kap. 2.3]\n",
"Die Gleichung\n",
"$$\n",
" s_{2n} = \\sqrt{2-\\sqrt{4-s_n^2}}\\qquad \\qquad \\textrm{(Iteration A)}\n",
"$$\n",
"ist mathematisch äquivalent zu\n",
"$$\n",
" s_{2n} = \\frac{s_n}{\\sqrt{2+\\sqrt{4-s_n^2}}} \\qquad \\qquad \\textrm{(Iteration B)}\n",
"$$\n",
"\n",
"(Bitte nachrechnen!) \n",
"\n",
"\n",
"\n",
"Allerdings ist Iteration A schlecht konditioniert und numerisch instabil, wie der folgende Code zeigt. Ausgegeben wird die jeweils berechnete Näherung für π.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3f238690",
"metadata": {},
"outputs": [],
"source": [
"using Printf\n",
"\n",
"iterationA(s) = sqrt(2 - sqrt(4 - s^2))\n",
"iterationB(s) = s / sqrt(2 + sqrt(4 - s^2))\n",
"\n",
"s_B = s_A = sqrt(2) # Startwert \n",
"\n",
"ϵ(x) = abs(x - 2π)/2π # rel. Fehler \n",
"\n",
"ϵ_A = Float64[] # Vektoren für den Plot\n",
"ϵ_B = Float64[]\n",
"is = Float64[]\n",
"\n",
"@printf \"\"\" approx. Wert von π\n",
" n-Eck Iteration A Iteration B\n",
"\"\"\"\n",
"\n",
"for i in 3:35\n",
" push!(is, i)\n",
" s_A = iterationA(s_A) \n",
" s_B = iterationB(s_B) \n",
" doublePi_A = 2^i * s_A\n",
" doublePi_B = 2^i * s_B\n",
" push!(ϵ_A, ϵ(doublePi_A))\n",
" push!(ϵ_B, ϵ(doublePi_B))\n",
" @printf \"%14i %20.15f %20.15f\\n\" 2^i doublePi_A/2 doublePi_B/2 \n",
"end"
]
},
{
"cell_type": "markdown",
"id": "0c0178f5",
"metadata": {},
"source": [
"Während Iteration B sich stabilisiert bei einem innerhalb der Maschinengenauigkeit korrekten Wert für π, wird Iteration A schnell instabil. Ein Plot der relativen Fehler $\\epsilon_i$ bestätigt das:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f415aab0",
"metadata": {},
"outputs": [],
"source": [
"using PlotlyJS\n",
"\n",
"layout = Layout(xaxis_title=\"Iterationsschritte\", yaxis_title=\"rel. Fehler\",\n",
" yaxis_type=\"log\", yaxis_exponentformat=\"power\", \n",
" xaxis_tick0=2, xaxis_dtick=2)\n",
"\n",
"plot([scatter(x=is, y=ϵ_A, mode=\"markers+lines\", name=\"Iteration A\", yscale=:log10), \n",
" scatter(x=is, y=ϵ_B, mode=\"markers+lines\", name=\"Iteration B\", yscale=:log10)],\n",
" layout) \n"
]
},
{
"cell_type": "markdown",
"id": "02116ab2",
"metadata": {},
"source": [
"## Stabilität und Auslöschung\n",
"\n",
"Bei $i=26$ erreicht Iteration B einen relativen Fehler in der Größe des Maschinenepsilons:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3d50cba2",
"metadata": {},
"outputs": [],
"source": [
"ϵ_B[22:28]"
]
},
{
"cell_type": "markdown",
"id": "5ba088ba",
"metadata": {},
"source": [
"Weitere Iterationen verbessern das Ergebnis nicht mehr. Sie stabilisieren sich bei einem relativen Fehler von etwa 2.5 Maschinenepsilon:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2bcae61d",
"metadata": {},
"outputs": [],
"source": [
"ϵ_B[end]/eps(Float64)"
]
},
{
"cell_type": "markdown",
"id": "0bfd8235",
"metadata": {},
"source": [
"Die Form Iteration A ist instabil. Bereits bei $i=16$ beginnt der relative Fehler wieder zu wachsen.\n",
"\n",
"Ursache ist eine typische Auslöschung. Die Seitenlängen $s_n$ werden sehr schnell klein. Damit ist\n",
"$a_n=\\sqrt{4-s_n^2}$ nur noch wenig kleiner als 2 und bei der Berechnung von $s_{2n}=\\sqrt{2-a_n}$ tritt ein typischer Auslöschungseffekt auf.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "365d4c27",
"metadata": {},
"outputs": [],
"source": [
"setprecision(80) # precision für BigFloat\n",
"\n",
"s = sqrt(BigFloat(2))\n",
"\n",
"@printf \" a = √(4-s^2) als BigFloat und als Float64\\n\\n\"\n",
"\n",
"for i = 3:44\n",
" s = iterationA(s)\n",
" x = sqrt(4-s^2)\n",
" if i > 20\n",
" @printf \"%i %30.26f %20.16f \\n\" i x Float64(x)\n",
" end \n",
"end\n"
]
},
{
"cell_type": "markdown",
"id": "04736a02",
"metadata": {},
"source": [
"Man sieht die Abnahme der Zahl der signifikanten Ziffern. Man sieht auch, dass eine Verwendung von `BigFloat` mit einer Mantissenlänge von hier 80 Bit das Einsetzen des Auslöschungseffekts nur etwas hinaussschieben kann. \n",
"\n",
"**Gegen instabile Algorithmen helfen in der Regel nur bessere, stabile Algorithmen und nicht genauere Maschinenzahlen!**\n",
"\n",
":::{.content-hidden unless-format=\"xxx\"}\n",
"\n",
"Offensichtlich tritt bei der Berechnung von $2-a_n$ bereits relativ früh\n",
"eine Abnahme der Anzahl der signifikanten Ziffern (Auslöschung) auf, \n",
"bevor schließlich bei der Berechnung von $a_n=\\sqrt{4-s_n^2}$ \n",
"selbst schon Auslöschung zu einem unbrauchbaren Ergebnis führt.\n",
"\n",
":::"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.10.2",
"language": "julia",
"name": "julia-1.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,83 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "cdcef88f",
"metadata": {},
"source": [
"# Verzweigungen\n",
"\n",
"::: {.column-margin}\n",
":::\n",
"\n",
"### If\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13854f8c",
"metadata": {},
"outputs": [],
"source": [
"x = 3\n",
"y = 66\n",
"\n",
"if x<y \n",
" println(\"yes\")\n",
"else\n",
" x = 10\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "6b04de1f",
"metadata": {},
"source": [
"Suchen wir mal danach:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6a207036",
"metadata": {},
"outputs": [],
"source": [
"methods(sqrt)"
]
},
{
"cell_type": "markdown",
"id": "568d4980",
"metadata": {},
"source": [
"das ist das Ende.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fbe323de",
"metadata": {},
"outputs": [],
"source": [
"using REPL, Markdown\n",
"help = Core.eval(Main, REPL.helpmode(\"mod\"))\n",
"helpstr=Markdown.plaininline(help)\n",
"#print(helpstr)\n",
"print(\"...\\n\", join(split(helpstr,'\\n')[22:30],'\\n'), \"\\n...\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.8.5",
"language": "julia",
"name": "julia-1.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,167 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "1cb64ccb",
"metadata": {},
"source": [
"# Entwicklungsumgebungen\n",
"\n",
"Für diesen Kurs werden wir die webbasierte Entwicklungsumgebung [Jupyterhub](https://de.wikipedia.org/wiki/Project_Jupyter) verwenden. Sie steht allen Teilnehmerïnnen für die Dauer des Kurses zur Verfügung. \n",
"\n",
"Für langfristiges Arbeiten empfiehlt sich eine eigene Installation. \n",
"\n",
"\n",
"## Installation auf eigenem Rechner (Linux/MacOS/MS Windows)\n",
"\n",
"1. Julia mit dem Installations- und Update-Manager **juliaup** installieren: <https://github.com/JuliaLang/juliaup/>\n",
"2. als Editor/IDE **Visual Studio Code** installieren: <https://code.visualstudio.com/>\n",
"3. im VS Code Editor die **Julia language extension** installieren: <https://www.julia-vscode.org/docs/stable/gettingstarted/>\n",
"\n",
"Einstieg:\n",
"\n",
"- In VS Code eine neue Datei mit der Endung `.jl` anlegen\n",
"- Julia-Code schreiben\n",
"- {{< kbd Shift-Enter >}} oder {{< kbd Ctrl-Enter >}} am Ende einer Anweisung oder eines Blocks startet ein Julia-REPL, Code wird ins REPL kopiert und ausgeführt \n",
"- [Tastenbelegungen für VS Code](https://code.visualstudio.com/docs/getstarted/keybindings#_keyboard-shortcuts-reference)\n",
"und [Julia in VS Code](https://www.julia-vscode.org/docs/stable/userguide/keybindings/)\n",
"\n",
"\n",
"\n",
"## Arbeiten auf dem [Jupyterhub-Webserver](https://misun103.mathematik.uni-leipzig.de/)\n",
"\n",
"### Jupyterhub & Jupyter\n",
"\n",
"- [Jupyterhub](https://de.wikipedia.org/wiki/Project_Jupyter) ist ein Multi-User-Server für Jupyter.\n",
"- Jupyter ist eine web-basierte interaktive Programmierumgebung, die\n",
"- ursprünglich in und für Python geschrieben, inzwischen eine\n",
" Vielzahl von Programmiersprachen nutzen kann.\n",
"- In Jupyter bearbeitet man sogenannte *notebooks*. Das sind strukturiere Textdateien (JSON), erkennbar an der Dateiendung \n",
" `*.ipynb`.\n",
"\n",
"Unser Jupyterhub-Server: <https://misun103.mathematik.uni-leipzig.de/>\n",
"\n",
"Nach dem Einloggen in Jupyterhub erscheint ein Dateimanager:\n",
"\n",
"![Jupyterhub Dateimanager](../images/notebook001.png)\n",
"\n",
"Mit diesem kann man:\n",
"\n",
"- vorhandene *notebooks* öffnen,\n",
"- neue *notebooks* anlegen,\n",
"- Dateien, z.B. *notebooks*, vom lokalen Rechner hochladen,\n",
"- die Sitzung mit `Logout` beenden (bitte nicht vergessen!). \n",
"\n",
"### Jupyter notebooks\n",
"\n",
"![Jupyter Notebook](../images/notebook003.png)\n",
"\n",
"\n",
"*Notebooks* bestehen aus Zellen. Zellen können \n",
"\n",
"- Code oder \n",
"- Text/Dokumentation (Markdown) \n",
"\n",
"enthalten. In Textzellen können mit die Auszeichnungssprache [Markdown](https://de.wikipedia.org/wiki/Markdown) zur Formatierung und LaTeX für mathematische Gleichungen verwendet werden. \n",
"\n",
"Es sei empfohlen, die Punkte `User Interface Tour` und `Keyboard Shortcuts` im `Help`-Menü anzuschauen. Die Zelle, die man gerade bearbeitet, kann im `command mode` oder `edit mode` sein. \n",
"\n",
"\n",
"\n",
"```{html}\n",
"<table>\n",
" <caption>Einige Kommandos</caption>\n",
" <thead>\n",
" <tr>\n",
" <th></th><th>command mode</th><th>edit mode</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr> \n",
" <td>Mode aktivieren</td><td>ESC</td>\n",
" </tr>\n",
" </tbody> \n",
"</table>\n",
"```\n",
"\n",
"\n",
"\n",
"| | *command mode* | *edit mode* |\n",
"|:-------|:---------------:|:-----------:|\n",
"| Mode aktivieren | `ESC` | Doppelklick oder `Enter` in Zelle |\n",
"| neue Zelle | `b` | `Alt-Enter` |\n",
"| Zelle löschen | `dd` | |\n",
"| Notebook speichern | `s` | `Ctrl-s` |\n",
"\n",
"\n",
"\n",
"- Notebook speichern:\n",
"\n",
" - `Ctrl-s` in Edit Mode\n",
" - `s` in Command mode\n",
" - `Menu -> File -> Save & Checkpoint`\n",
" - `Menu -> File -> Rename`: Umbenennen (falls es noch\n",
" \\\"Untitled1\\\" heißt) `<br>`{=html}`<br>`{=html}\n",
"\n",
"- Notebook schließen:\n",
"\n",
" - `Menu -> File -> Close & Halt` `<br>`{=html}`<br>`{=html}\n",
"\n",
"- Ausführen von Julia:\n",
"\n",
" - `Ctrl-Enter`: Run cell\n",
" - `Shift-Enter`: Run cell, move to next cell\n",
" - `Alt-Enter`: run cell, insert new cell below\n",
"\n",
"\n",
"\n",
"bla backslash\n",
"\n",
"![](../images/notebook002.png)\n",
"\n",
"bla backslash\n",
"\n",
"\n",
"------------------------------------------------------------------------\n",
"\n",
"Wenn eine Zelle \\\"arbeitet\\\", wird ihre Zellen-Nummer zu einem `*` und\n",
"die `kernel busy`-Anzeige (Voller schwarzer Punkt oben rechts neben der\n",
"Julia-Version) erscheint. Falls das zu lange dauert (ein *infinite loop*\n",
"ist schnell programmiert), dann\n",
"\n",
"- `Menu -> Kernel -> Interrupt` anklicken; falls das wirkungslos ist,\n",
"- `Menu -> Kernel -> Restart` anklicken.\n",
"\n",
"Danach müssen alle Zellen, die weiterhin benötigte Definitionen,\n",
"`using`-Anweisungen etc enthalten, wieder ausgeführt werden!\n",
"\n",
"------------------------------------------------------------------------\n",
"\n",
"**Am Ende der Arbeit bitte immer:**\n",
"\n",
"- `Menu -> File -> Save & Checkpoint`\n",
"- `Menu -> File -> Close & Halt`\n",
"- `Logout`\n",
":::\n",
"\n",
"::: {#73820119 .cell .markdown}\n",
"#### Markdown-Zellen\n",
"\n",
"neben den üblichen Markdown-Elementen können auch diese auch\n",
"`HTML`-Anweisungen und Mathematische Formeln in LaTeX-Form enthalten.\n",
"LaTeX-Formeln werden in `$...$` oder `$$...$$` (Display-Form)\n",
"eingeschlossen.\n",
":::\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.8.5",
"language": "julia",
"name": "julia-1.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,146 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "1847e5bc",
"metadata": {},
"source": [
"# Some Julia Code\n",
"\n",
"\n",
"1. ?forvarianrte\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fd1a489b",
"metadata": {},
"outputs": [],
"source": [
"?for"
]
},
{
"cell_type": "markdown",
"id": "62aee612",
"metadata": {},
"source": [
"## Einfache rechnerei\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "23afd224",
"metadata": {},
"outputs": [],
"source": [
"2^33+33"
]
},
{
"cell_type": "markdown",
"id": "d1f050b2",
"metadata": {},
"source": [
"## colored console graphs produced by `Benchmarktools.jl`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a9b6a7c8",
"metadata": {},
"outputs": [],
"source": [
"using BenchmarkTools\n",
"\n",
"@benchmark sum(rand(1000))"
]
},
{
"cell_type": "markdown",
"id": "948d948e",
"metadata": {},
"source": [
"## structure of floating point numbers\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fbe94ce0",
"metadata": {},
"outputs": [],
"source": [
"function printbitsf64(x::Float64)\n",
" s = bitstring(x)\n",
" printstyled(s[1], color = :blue, reverse=true)\n",
" printstyled(s[2:12], color = :green, reverse=true)\n",
" printstyled(s[13:end], color=:red, bold=true, reverse=true)\n",
" print(\"\\n\")\n",
"end\n",
"\n",
"printbitsf64(27.56640625)"
]
},
{
"cell_type": "markdown",
"id": "611f43fa",
"metadata": {},
"source": [
"### illustrate machine epsilon...\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "294f9e7e",
"metadata": {},
"outputs": [],
"source": [
"Eps=0.5\n",
"while 1 != 1 + Eps\n",
" Eps /= 2\n",
" printbitsf64(1+Eps)\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "34e578b1",
"metadata": {},
"source": [
"### ... some ugly colors\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9771dbc3",
"metadata": {},
"outputs": [],
"source": [
"function printbits2f64(x::Float64)\n",
" s = bitstring(x)\n",
" printstyled(s[1], color = 142, reverse=true)\n",
" printstyled(s[2:12], color = 190, reverse=false, underline=true)\n",
" printstyled(s[13:end], color= 27, bold=true, reverse=true)\n",
" print(\"\\n\")\n",
"end\n",
"\n",
"printbits2f64(27.56640625)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.8.5",
"language": "julia",
"name": "julia-1.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,628 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "65cc0031",
"metadata": {},
"source": [
"# First Contact\n",
"\n",
"Dieses Kapitel soll beim 'Loslegen' helfen. Es läßt viele Details weg und die Codebeispiele sind oft eher suboptimal. \n",
"\n",
"\n",
"## Julia als Taschenrechner\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f9151e6d",
"metadata": {},
"outputs": [],
"source": [
"#| eval: true\n",
"#| echo: false\n",
"#| output: false\n",
"\n",
"using REPL, Markdown\n",
"\n",
"function mhelp(s,n,m)\n",
" helptxt = Core.eval(Main, REPL.helpmode(s))\n",
" helpstr=Markdown.plaininline(helptxt)\n",
" print(\"...\\n\", join(split(helpstr,'\\n')[n:m],'\\n'), \"\\n...\")\n",
"end;\n",
"\n",
"function Tab(s)\n",
" l = filter(x->startswith(x,s), REPL.doc_completions(s))\n",
" println.(l[2:end])\n",
" return # return nothing, since broadcast println produces empty vector\n",
"end\n",
"\n",
"▷ = |>\n",
"\n",
"# IJulia.set_verbose(true)"
]
},
{
"cell_type": "markdown",
"id": "3c611742",
"metadata": {},
"source": [
"Berechne $\\qquad 12^{1/3} + \\frac{3\\sqrt{2}}{\\sin(0.5)-\\cos(\\frac{\\pi}{4})\\log(3)}+ e^5$\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fd02456e",
"metadata": {},
"outputs": [],
"source": [
"12^(1/3) + 3sqrt(2) / (sin(.5) - cos(pi/4)*log(3)) + exp(5)"
]
},
{
"cell_type": "markdown",
"id": "9ce12c0f",
"metadata": {},
"source": [
"Man beachte:\n",
"\n",
"- Potenzen schreibt man `a^b`.\n",
"- Die Konstante `pi` ist vordefiniert.\n",
"- `log()` ist der natürliche Logarithmus.\n",
"- Das Multiplikationszeichen `a*b` kann nach einer Zahl weggelassen werden, wenn eine Variable, Funktion oder Klammer folgt.\n",
"\n",
"\n",
"## Die wichtigsten Tasten: `Tab` und `?` {#sec-tab}\n",
"\n",
"Man drücke beim Programmieren immer wieder die Tabulatortaste, sobald 2...3 Buchstaben eines Wortes getippt sind. Es werden dann mögliche Ergänzungen angezeigt bzw. ergänzt, wenn die Ergänzung eindeutig ist. Das spart Zeit und bildet ungemein:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e2ca6f27",
"metadata": {},
"outputs": [],
"source": [
"lo = \"lo\" #| hide_line\n",
"lo ▷ Tab"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9fdfabe6",
"metadata": {},
"outputs": [],
"source": [
"pri = \"pri\" #| hide_line\n",
"pri ▷ Tab"
]
},
{
"cell_type": "markdown",
"id": "d8ecd73b",
"metadata": {},
"source": [
"Die eingebaute Julia-Hilfe `?name` zu allen Funktionen und Konstrukten ist sehr umfassend. Hier ein eher kurzes Beispiel: \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9ba34e9d",
"metadata": {},
"outputs": [],
"source": [
"?for"
]
},
{
"cell_type": "markdown",
"id": "c798d174",
"metadata": {},
"source": [
":::{.content-hidden unless-format=\"xxx\"}\n",
"\n",
"::: {.cell }\n",
"``` {.julia .cell-code}\n",
"?for\n",
"```\n",
"\n",
"::: {.cell-output .cell-output-stdout}\n",
"```\n",
"search: for foreach foldr floor mapfoldr factorial EOFError OverflowError\n",
"\n",
"for loops repeatedly evaluate a block of statements while iterating over a sequence of values.\n",
"\n",
"Examples\n",
"\n",
"julia> for i in [1, 4, 0]\n",
" println(i)\n",
" end\n",
"1\n",
"4\n",
"0\n",
"\n",
"```\n",
":::\n",
":::\n",
":::\n",
"\n",
"\n",
"## Variablen und Zuweisungen\n",
"\n",
"Variablen entstehen durch Zuweisung *(assignment)* mit dem Zuweisungsoperator `=` . Danach können sie in weiteren Anweisungen verwendet werden.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2f60e4e5",
"metadata": {},
"outputs": [],
"source": [
"x = 1 + sqrt(5) \n",
"y = x / 2"
]
},
{
"cell_type": "markdown",
"id": "20819c0a",
"metadata": {},
"source": [
"Im interaktiven Betrieb zeigt Julia das Ergebnis der letzten Operation an.\n",
"\n",
":::{.callout-note .titlenormal}\n",
"Zuweisungen sind keine mathematischen Gleichungen. Die Semantik des Zuweisungsoperators (Gleichheitszeichens) ist: \n",
"\n",
"- berechne die rechte Seite und\n",
"- weise das Ergebnis der linken Seite zu.\n",
"\n",
"Ausdrücke wie `x + y = sin(2)` sind daher unzulässig. Links darf nur ein Variablenname stehen.\n",
":::\n",
"\n",
"\n",
"## Datentypen\n",
"\n",
"Julia ist eine [stark typisierte](https://de.wikipedia.org/wiki/Starke_Typisierung) Sprache. Alle Objekte haben einen Typ. \n",
"So gibt es unter anderem die Basistypen \n",
"\n",
"- Ganze Zahlen *(integers)*,\n",
"- Gleitkommazahlen *(floating point numbers)*,\n",
"- Zeichenketten *(strings)* und \n",
"- Wahrheitswerte *(booleans)*.\n",
"\n",
"Den Typ einer Variablen kann man mit der Funktion `typeof()` ermitteln. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2874204c",
"metadata": {},
"outputs": [],
"source": [
"#| warning: true\n",
"#| error: true\n",
"for x ∈ (42, 12.0, 3.3e4, \"Hallo!\", true)\n",
" println(\"x = \", x, \" ..... Typ: \", typeof(x))\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "d5343251",
"metadata": {},
"source": [
"Die Standard-Gleitkommazahl hat eine Länge von 64 Bit, entspricht also einer `double` in C/C++/Java.\n",
"\n",
"Julia ist eine [dynamisch typisierte](https://de.wikipedia.org/wiki/Dynamische_Typisierung) Sprache. \n",
"Variablen haben keinen Typ. Sie sind typlose Referenzen (Zeiger) auf Objekte. \n",
"Wenn man vom „Typ einer Variablen“ spricht, meint man den Typ des Objektes, das der Variablen gerade zugewiesen ist. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "544f8fe6",
"metadata": {},
"outputs": [],
"source": [
"x = sqrt(2)\n",
"\n",
"println( typeof(x), \" - Wert von x = $x\" )\n",
"\n",
"x = \"Jetzt bin ich keine Gleitkommazahl mehr!\"\n",
"\n",
"println( typeof(x), \" - Wert von x = $x\" )"
]
},
{
"cell_type": "markdown",
"id": "b1734df1",
"metadata": {},
"source": [
"## Druckanweisungen\n",
"Die Funktion `println()` unterscheidet sich von `print()` dadurch, dass sie am Ende einen Zeilenvorschub ausgibt.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b44d0f53",
"metadata": {},
"outputs": [],
"source": [
"print(y)\n",
"print(\"...die Zeile geht weiter...\")\n",
"print(\"immernoch...\")\n",
"println(y)\n",
"println(\"Neue Zeile\")\n",
"println(\"Neue Zeile\")"
]
},
{
"cell_type": "markdown",
"id": "3baa2a89",
"metadata": {},
"source": [
"Beide Funkionen können als Argument eine Liste von *strings* und Variablen bekommen. Man kann Variablen auch in *strings* einbetten, indem man dem Variablennamen ein Dollarzeichen voranstellt *(string interpolation)*.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fa3b2601",
"metadata": {},
"outputs": [],
"source": [
"x = 23\n",
"y = 3x + 5\n",
"zz = \"Fertig!\"\n",
"println(\"x= \", x, \" ...und y= \", y, \"...\", zz) # 1. Variante\n",
"println(\"x= $x ...und y= $y...$zz\") # Variante mit string interpolation"
]
},
{
"cell_type": "markdown",
"id": "fe3b44d2",
"metadata": {},
"source": [
":::{.callout-note .titlenormal collapse=true icon=false }\n",
"## Wenn man ein Dollarzeichen drucken will...\n",
"\n",
"muss man einen *backslash* voranstellen. Wenn man einen *backslash* drucken will, muss man ihn verdoppeln.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "198c1231",
"metadata": {},
"outputs": [],
"source": [
"println(\"Ein Dollar: 1\\$ und drei backslashs: \\\\\\\\\\\\ \")"
]
},
{
"cell_type": "markdown",
"id": "847182e6",
"metadata": {},
"source": [
":::\n",
"\n",
"## Funktionen\n",
"Funktionsdefinitionen beginnen mit dem Schlüsselwort `function` und enden mit dem Schlüsselwort `end`. In der Regel haben sie eine oder mehrere Argumente und geben beim Aufruf ein berechnetes Objekt mit der `return`-Anweisung zurück.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8c4c8af3",
"metadata": {},
"outputs": [],
"source": [
"function hypotenuse(a, b) # heute besonders umständlich\n",
" c2 = a^2 + b^2\n",
" c = sqrt(c2)\n",
" return c \n",
"end"
]
},
{
"cell_type": "markdown",
"id": "270a968d",
"metadata": {},
"source": [
"Nach ihrer Definition kann die Funktion benutzt (aufgerufen) werden. Die in der Definition verwendeten Variablen `a,b,c,c2` sind lokale Variablen und stehen außerhalb der Funktionsdefinition nicht zur Verfügung. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aeb1b763",
"metadata": {},
"outputs": [],
"source": [
"#| error: true\n",
"x = 3\n",
"z = hypotenuse(x, 4)\n",
"println(\"z = $z\")\n",
"println(\"c = $c\")"
]
},
{
"cell_type": "markdown",
"id": "83623a5d",
"metadata": {},
"source": [
"Sehr einfache Funktionen können auch als Einzeiler definiert werden.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bb93d920",
"metadata": {},
"outputs": [],
"source": [
"hypotenuse(a, b) = sqrt(a^2+b^2)"
]
},
{
"cell_type": "markdown",
"id": "28cfec18",
"metadata": {},
"source": [
"## Tests\n",
"Tests liefern einen Wahrheitswert zurück. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a778d1c9",
"metadata": {},
"outputs": [],
"source": [
"x = 3^2\n",
"x < 2^3"
]
},
{
"cell_type": "markdown",
"id": "43717a30",
"metadata": {},
"source": [
"Neben den üblichen arithmetischen Vergleichen `==, !=, <, <= ,> ,>=` \n",
"gibt es noch viele andere Tests. Natürlich kann man das Ergebnis eines Tests auch einer Variablen zuweisen, welche dann vom Typ `Bool` ist. Die logischen Operatoren `&&`, `||` und Negation `!` können in Tests verwendet werden. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b425b2bf",
"metadata": {},
"outputs": [],
"source": [
"test1 = \"Auto\" in [\"Fahrrad\", \"Auto\", \"Bahn\"]\n",
"test2 = x == 100 || !(x <= 30 && x > 8)\n",
"test3 = startswith(\"Lampenschirm\", \"Lamp\") \n",
"println(\"$test1 $test2 $test3\")"
]
},
{
"cell_type": "markdown",
"id": "b8b63af7",
"metadata": {},
"source": [
"## Verzweigungen\n",
"Verzweigungen (bedingte Anweisungen) haben die Form \n",
"\n",
"```default\n",
"if <Test> \n",
" <Anweisung1> \n",
" <Anweisung2>\n",
" ...\n",
"end\n",
"``` \n",
"\n",
"\n",
"Ein `else`-Zweig und `elseif`-Zweige sind möglich.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "759c7b60",
"metadata": {},
"outputs": [],
"source": [
"x = sqrt(100)\n",
"\n",
"if x > 20\n",
" println(\"Seltsam!\")\n",
"else\n",
" println(\"OK\")\n",
" y = x + 3\n",
"end "
]
},
{
"cell_type": "markdown",
"id": "92f05a99",
"metadata": {},
"source": [
"Einrückungen verbessern die Lesbarkeit, sind aber fakultativ. Zeilenumbrüche trennen Anweisungen. Das ist auch durch Semikolon möglich. Obiger Codeblock ist für Julia identisch zu folgender Zeile:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "75c38c3c",
"metadata": {},
"outputs": [],
"source": [
"# Bitte nicht so programmieren! Sie werden es bereuen!\n",
"x=sqrt(100); if x > 20 println(\"Seltsam!\") else println(\"OK\"); y = x + 3 end "
]
},
{
"cell_type": "markdown",
"id": "6c916fa7",
"metadata": {},
"source": [
"Es wird dringend empfohlen, von Anfang an den eigenen Code übersichtlich mit sauberen Einrückungen zu formatieren!\n",
"\n",
"\n",
"## Einfache `for`-Schleifen\n",
"\n",
"zum wiederholten Abarbeiten von Anweisungen haben die Form\n",
"```default\n",
"for <Zähler> = Start:Ende\n",
" <Anweisung1> \n",
" <Anweisung2>\n",
" ...\n",
"end\n",
"```\n",
"Beispiel:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8f6ff3c3",
"metadata": {},
"outputs": [],
"source": [
"sum = 0\n",
"for i = 1:100\n",
" sum = sum + i\n",
"end \n",
"sum"
]
},
{
"cell_type": "markdown",
"id": "6ba98544",
"metadata": {},
"source": [
"## Arrays\n",
"1-dimensionale Arrays (Vektoren) sind eine einfache Form von Containern. Man kann sie mit echigen Klammern anlegen\n",
"und auf die Elemente per Index zugreifen. Die Indizierung beginnt mit 1. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bde3f18d",
"metadata": {},
"outputs": [],
"source": [
"v = [12, 33.2, 17, 19, 22]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ab7ae1b1",
"metadata": {},
"outputs": [],
"source": [
"typeof(v)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cd6f6101",
"metadata": {},
"outputs": [],
"source": [
"v[1] = v[4] + 10\n",
"v"
]
},
{
"cell_type": "markdown",
"id": "4cd8e309",
"metadata": {},
"source": [
"Man kann leere Vektoren anlegen und sie verlängern.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4e643897",
"metadata": {},
"outputs": [],
"source": [
"v = [] # leerer Vektor\n",
"push!(v, 42)\n",
"push!(v, 13)\n",
"v"
]
},
{
"cell_type": "markdown",
"id": "d3e2209e",
"metadata": {},
"source": [
":::{.callout-note icon=\"false\" .titlenormal collapse=\"true\" font-variant-ligatures=\"no-contextual\" }\n",
"\n",
"## Nachtrag: wie die Wirkung der Tab-Taste auf dieser Seite simuliert wurde...\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8bb956d4",
"metadata": {},
"outputs": [],
"source": [
"using REPL\n",
"\n",
"function Tab(s)\n",
" l = filter(x->startswith(x,s), REPL.doc_completions(s))\n",
" println.(l[2:end])\n",
" return # return nothing, since broadcast println produces empty vector\n",
"end\n",
"\n",
"▷ = |> # https://docs.julialang.org/en/v1/manual/functions/#Function-composition-and-piping\n",
"\n",
"pri = \"pri\";"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a417e43d",
"metadata": {},
"outputs": [],
"source": [
"pri ▷ Tab"
]
},
{
"cell_type": "markdown",
"id": "71efa254",
"metadata": {},
"source": [
":::"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.10.2",
"language": "julia",
"name": "julia-1.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,493 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "cd3f6abe",
"metadata": {},
"source": [
"# First Contact\n",
"\n",
"Dieses Kapitel enthält einige \"pädagogische Halbwahrheiten\", d.h., es vereinfacht und lässt Details weg.\n",
"\n",
"## Julia als Taschenrechner\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0dbe789e",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:34.132000Z",
"iopub.status.busy": "2023-03-08T16:05:33.746000Z",
"iopub.status.idle": "2023-03-08T16:05:37.286000Z",
"shell.execute_reply": "2023-03-08T16:05:37.175000Z"
}
},
"outputs": [],
"source": [
"#| eval: true\n",
"#| echo: false\n",
"#| output: false\n",
"IJulia.set_verbose(true)"
]
},
{
"cell_type": "markdown",
"id": "a2b52996",
"metadata": {},
"source": [
"Berechne $\\qquad 12^{1/3} + \\frac{3\\sqrt{2}}{\\sin(0.5)-\\cos(\\frac{\\pi}{4})\\log(3)}+ e^5$\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c831420f",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:37.336000Z",
"iopub.status.busy": "2023-03-08T16:05:37.335000Z",
"iopub.status.idle": "2023-03-08T16:05:37.620000Z",
"shell.execute_reply": "2023-03-08T16:05:37.618000Z"
}
},
"outputs": [],
"source": [
"12^(1/3) + 3sqrt(2) / (sin(.5) - cos(pi/4)*log(3)) + exp(5)"
]
},
{
"cell_type": "markdown",
"id": "a9f3359b",
"metadata": {},
"source": [
"Man beachte:\n",
"\n",
"- Potenzen schreibt man `a^b`.\n",
"- Die Konstante `pi` ist vordefiniert.\n",
"- `log()` ist der natürliche Logarithmus.\n",
"- Das Multiplikationszeichen `a*b` kann nach einer Zahl weggelassen werden, wenn eine Variable, Funktion oder Klammer folgt.\n",
"\n",
"\n",
"## Variablen und Zuweisungen\n",
"\n",
"Variablen entstehen durch Zuweisung *(assignment)*. Durch Zuweisung definierte Variablen können danach in weiteren Anweisungen verwendet werden.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5ff20c70",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:37.625000Z",
"iopub.status.busy": "2023-03-08T16:05:37.624000Z",
"iopub.status.idle": "2023-03-08T16:05:37.657000Z",
"shell.execute_reply": "2023-03-08T16:05:37.655000Z"
}
},
"outputs": [],
"source": [
"x = 1 + sqrt(5) \n",
"y = x / 2"
]
},
{
"cell_type": "markdown",
"id": "e7db7bb5",
"metadata": {},
"source": [
":::{.indentb}\n",
"Zuweisungen sind keine mathematischen Gleichungen. Die Semantik des Zuweisungsoperators (d.h., des Gleichheitszeichens) ist: \n",
"\n",
"- berechne die rechte Seite und\n",
"- weise das Ergebnis der linken Seite zu.\n",
"\n",
"Ausdrücke wie `x + y = sin(2)` sind daher unzulässig, links darf nur ein Variablenname stehen.\n",
":::\n",
"\n",
"\n",
"## Datentypen\n",
"\n",
"Julia ist eine [stark typisierte](https://de.wikipedia.org/wiki/Starke_Typisierung) Sprache. Alle Objekte haben einen Typ. \n",
"So gibt es unter anderem die Basistypen \n",
"\n",
"- Ganze Zahlen *(integers)*,\n",
"- Gleitkommazahlen *(floating point numbers)*,\n",
"- Zeichenketten *(strings)* und \n",
"- Wahrheitswerte *(booleans)*.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae3af394",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:37.662000Z",
"iopub.status.busy": "2023-03-08T16:05:37.661000Z",
"iopub.status.idle": "2023-03-08T16:05:38.219000Z",
"shell.execute_reply": "2023-03-08T16:05:38.217000Z"
}
},
"outputs": [],
"source": [
"#| warning: true\n",
"#| error: true\n",
"for x ∈ (42, 12.0, 3.3e4, \"Hallo!\", true)\n",
" println(\"x = \", x, \" ..... Typ: \", typeof(x))\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "213bef1c",
"metadata": {},
"source": [
"Die Standard-Gleitkommazahl hat eine Länge von 64 Bit, entspricht also einer `double` in C/C++/Java.\n",
"\n",
"Julia ist eine [dynamisch typisierte](https://de.wikipedia.org/wiki/Dynamische_Typisierung) Sprache. \n",
"Variablen haben keinen Typ. Sie sind typlose Referenzen (Zeiger) auf Objekte. \n",
"Wenn man vom „Typ einer Variablen“ spricht, meint man den Typ des Objektes, das der Variablen gerade zugewiesen ist. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2d6c0d1b",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:38.225000Z",
"iopub.status.busy": "2023-03-08T16:05:38.223000Z",
"iopub.status.idle": "2023-03-08T16:05:38.316000Z",
"shell.execute_reply": "2023-03-08T16:05:38.315000Z"
}
},
"outputs": [],
"source": [
"x = sqrt(2)\n",
"println( typeof(x) )\n",
"x = \"Jetzt bin ich keine Gleitkommazahl mehr!\"\n",
"println( typeof(x) )"
]
},
{
"cell_type": "markdown",
"id": "f2329446",
"metadata": {},
"source": [
"## Druckanweisungen\n",
"Die Funktion `println()` unterscheidet sich von `print()` dadurch, dass sie am Ende einen Zeilenvorschub ausgibt.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d4a7260d",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:38.321000Z",
"iopub.status.busy": "2023-03-08T16:05:38.320000Z",
"iopub.status.idle": "2023-03-08T16:05:38.369000Z",
"shell.execute_reply": "2023-03-08T16:05:38.367000Z"
}
},
"outputs": [],
"source": [
"print(y)\n",
"print(\"...die Zeile geht weiter...\")\n",
"print(\"immernoch...\")\n",
"println(y)\n",
"println(\"Neue Zeile\")\n",
"println(\"Neue Zeile\")"
]
},
{
"cell_type": "markdown",
"id": "dccc9577",
"metadata": {},
"source": [
"Beide Funkionen können als Argument eine Liste von *strings* und Variablen bekommen. Man kann Variablen auch in *strings* einbetten, indem man dem Variablennamen ein Dollarzeichen voranstellt *(string interpolation)*.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7a2116bd",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:38.374000Z",
"iopub.status.busy": "2023-03-08T16:05:38.373000Z",
"iopub.status.idle": "2023-03-08T16:05:38.402000Z",
"shell.execute_reply": "2023-03-08T16:05:38.400000Z"
}
},
"outputs": [],
"source": [
"x = 23\n",
"y = 3x + 5\n",
"zz = \"Fertig!\"\n",
"println(\"x= \", x, \" ...und y= \", y, \"...\", zz) # 1. Variante\n",
"println(\"x= $x ...und y= $y...$zz\") # Variante mit string interpolation"
]
},
{
"cell_type": "markdown",
"id": "ae5eaf6f",
"metadata": {},
"source": [
":::{.indentb}\n",
"Wenn man ein Dollarzeichen drucken will, muss man einen *backslash* voranstellen. Wenn man einen *backslash* drucken will, muss man ihn verdoppeln.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f7d26a60",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:38.407000Z",
"iopub.status.busy": "2023-03-08T16:05:38.406000Z",
"iopub.status.idle": "2023-03-08T16:05:38.434000Z",
"shell.execute_reply": "2023-03-08T16:05:38.432000Z"
}
},
"outputs": [],
"source": [
"println(\"Ein Dollar: 1\\$ und drei backslashs: \\\\\\\\\\\\ \")"
]
},
{
"cell_type": "markdown",
"id": "f40cee12",
"metadata": {},
"source": [
":::\n",
"\n",
"## Funktionen\n",
"Funktionsdefinitionen beginnen mit dem Schlüsselwort `function` und enden mit dem Schlüsselwort `end`. In der Regel haben sie eine oder mehrere Argumente und geben beim Aufruf ein berechnetes Objekt mit der `return`-Anweisung zurück.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b6574086",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:38.439000Z",
"iopub.status.busy": "2023-03-08T16:05:38.438000Z",
"iopub.status.idle": "2023-03-08T16:05:38.633000Z",
"shell.execute_reply": "2023-03-08T16:05:38.631000Z"
}
},
"outputs": [],
"source": [
"function hypotenuse(a, b)\n",
" c2 = a^2 + b^2\n",
" c = sqrt(c2)\n",
" return c \n",
"end"
]
},
{
"cell_type": "markdown",
"id": "d70272a0",
"metadata": {},
"source": [
"Nach ihrer Definition kann die Funktion benutzt (aufgerufen) werden. Die in der Definition verwendeten Variablen `a,b,c,c2` sind lokale Variablen und stehen außerhalb der Funktionsdefinition nicht zur Verfügung. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5df842f6",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:38.638000Z",
"iopub.status.busy": "2023-03-08T16:05:38.636000Z",
"iopub.status.idle": "2023-03-08T16:05:39.346000Z",
"shell.execute_reply": "2023-03-08T16:05:39.344000Z"
}
},
"outputs": [],
"source": [
"#| error: true\n",
"x = 3\n",
"z = hypotenuse(x, 4)\n",
"println(z)\n",
"println(c)"
]
},
{
"cell_type": "markdown",
"id": "dc012140",
"metadata": {},
"source": [
"Sehr einfache Funktionen können auch kürzer als Einzeiler definiert werden.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6aec78b0",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:39.351000Z",
"iopub.status.busy": "2023-03-08T16:05:39.350000Z",
"iopub.status.idle": "2023-03-08T16:05:39.381000Z",
"shell.execute_reply": "2023-03-08T16:05:39.379000Z"
}
},
"outputs": [],
"source": [
"hypotenuse(a, b) = sqrt(a^2+b^2)"
]
},
{
"cell_type": "markdown",
"id": "d57bc14f",
"metadata": {},
"source": [
"## Tests\n",
"Tests liefern einen Wahrheitswert zurück. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0e42d502",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:39.387000Z",
"iopub.status.busy": "2023-03-08T16:05:39.386000Z",
"iopub.status.idle": "2023-03-08T16:05:39.420000Z",
"shell.execute_reply": "2023-03-08T16:05:39.418000Z"
}
},
"outputs": [],
"source": [
"x = 2^8\n",
"x < 3"
]
},
{
"cell_type": "markdown",
"id": "814e4e5c",
"metadata": {},
"source": [
"Neben den üblichen arithmetischen Vergleichen `==, !=, <, <= ,> ,>=` \n",
"gibt es noch viele andere Tests. Natürlich kann man das Ergebnis eines Tests auch einer Variablen zuweisen, welche dann vom Typ `Bool` ist. Die logischen Operatoren `&&`, `||` und Negation `!` können in Tests verwendet werden. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3899c1c9",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:39.425000Z",
"iopub.status.busy": "2023-03-08T16:05:39.424000Z",
"iopub.status.idle": "2023-03-08T16:05:39.479000Z",
"shell.execute_reply": "2023-03-08T16:05:39.477000Z"
}
},
"outputs": [],
"source": [
"test1 = \"Auto\" in [\"Fahrrad\", \"Auto\", \"Bahn\"]\n",
"test2 = x == 100 || x in [1,2,4,7]\n",
"test3 = startswith(\"Lampenschirm\", \"Lamp\") \n",
"println(\"$test1 $test2 $test3\")"
]
},
{
"cell_type": "markdown",
"id": "067897ae",
"metadata": {},
"source": [
"## Verzweigungen\n",
"Verzweigungen (bedingte Anweisungen) haben die Form `if <Test> <Anweisungen> end`. Ein `else`-Zweig ist möglich.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "34db87a5",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:39.484000Z",
"iopub.status.busy": "2023-03-08T16:05:39.483000Z",
"iopub.status.idle": "2023-03-08T16:05:39.518000Z",
"shell.execute_reply": "2023-03-08T16:05:39.516000Z"
}
},
"outputs": [],
"source": [
"x = sqrt(100)\n",
"\n",
"if x > 20\n",
" println(\"Seltsam!\")\n",
"else\n",
" println(\"OK\")\n",
" y = x + 3\n",
"end "
]
},
{
"cell_type": "markdown",
"id": "2c0677f6",
"metadata": {},
"source": [
"Einrückungen und Zeilenumbrüche verbessern die Lesbarkeit, sind aber fakultativ. Anweisungen können auch durch Semikolon getrennt werden.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3b169201",
"metadata": {
"execution": {
"iopub.execute_input": "2023-03-08T16:05:39.523000Z",
"iopub.status.busy": "2023-03-08T16:05:39.521000Z",
"iopub.status.idle": "2023-03-08T16:05:39.554000Z",
"shell.execute_reply": "2023-03-08T16:05:39.552000Z"
}
},
"outputs": [],
"source": [
"if x > 20 println(\"Seltsam!\") else println(\"OK\"); y = x + 3 end "
]
},
{
"cell_type": "markdown",
"id": "f225e8eb",
"metadata": {},
"source": [
"## Einfache Schleifen\n",
"\n",
"\n",
"\n",
"## Arrays\n",
"1-dimensionale Arrays (Vektoren) sind eine einfache Form von Containern. Man kann sie mit echigen Klammern anlegen\n",
"\n",
"\n",
"und auf die Elemente per Index zugreifen. Die Indizierung beginnt mit 1. \n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.8.5",
"language": "julia",
"name": "julia-1.8"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,114 +0,0 @@
{
"cells": [
{
"cell_type": "raw",
"id": "10c7d783",
"metadata": {},
"source": [
"---\n",
"title: Introduction\n",
"---"
]
},
{
"cell_type": "markdown",
"id": "f2e8fc05",
"metadata": {},
"source": [
"## Noch eine Programmiersprache?\n",
"\n",
"Die Ziele der Schöpfer von Julia kann man in [Why we created Julia](https://julialang.org/blog/2012/02/why-we-created-julia/) nachlesen. Kurzfassung:\n",
"\n",
"“We want a language that is\n",
"\n",
"open source\n",
"with the speed of C\n",
"obvious, familiar mathematical notation like Matlab\n",
"as usable for general programming as Python\n",
"as easy for statistics as R\n",
"as natural for string processing as Perl\n",
"as powerful for linear algebra as Matlab\n",
"as good at gluing programs together as the shell\n",
"dirt simple to learn, yet keeps the most serious hackers happy”\n",
"\n",
"\n",
"\"Wir wollen eine Sprache, die\n",
"\n",
"- *open source* ist \n",
"- die Geschwindigkeit von C hat \n",
"- obvious, familiar mathematical notation like Matlab\n",
"- as usable for general programming as Python\n",
"- as easy for statistics as R\n",
"- as natural for string processing as Perl\n",
"- as powerful for linear algebra as Matlab\n",
"- as good at gluing programs together as the shell\n",
"- dirt simple to learn, yet keeps the most serious hackers happy\"\n",
"\n",
"vs code: erzeuge eine Datei mit der Endung `.jl`, starte ein REPL mit dem Kommando \n",
"Alt-Enter am Ende einer Zeile oder Anweisung f\"uhrt dazu, dass die Anweisung \n",
"is REPL kopiert und ausgefuehrt wird\n",
"\n",
"alt-enter execute in julia Repl\n",
"shift-enter: ex. and move to next line\n",
"\n",
"die Erstinstallation von Paketen kann sehr lange dauern. \n",
"\n",
"im Jupyterhub sind die im Kurs nenötigten Pakete vorinstalliert. \n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"## colored console graphs produced by `Benchmarktools.jl`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "62fcada8",
"metadata": {},
"outputs": [],
"source": [
"using BenchmarkTools\n",
"\n",
"@benchmark sum(rand(1000))"
]
},
{
"cell_type": "markdown",
"id": "00dc9599",
"metadata": {},
"source": [
"## structure of floating point numbers\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ccc6afab",
"metadata": {},
"outputs": [],
"source": [
"function printbitsf64(x::Float64)\n",
" s = bitstring(x)\n",
" printstyled(s[1], color = :blue, reverse=true)\n",
" printstyled(s[2:12], color = :green, reverse=true)\n",
" printstyled(s[13:end], color=:red, bold=true, reverse=true)\n",
" print(\"\\n\")\n",
"end\n",
"\n",
"printbitsf64(27.56640625)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.8.5",
"language": "julia",
"name": "julia-1.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,77 +0,0 @@
{
"cells": [
{
"cell_type": "raw",
"id": "7d6e8e63",
"metadata": {},
"source": [
"---\n",
"title: makie\n",
"---"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fff03da7",
"metadata": {},
"outputs": [],
"source": [
"using CairoMakie\n",
"\n",
"\n",
"f = Figure()\n",
"Axis(f[1, 1])\n",
"\n",
"xs = 1:0.2:10\n",
"ys_low = -0.2 .* sin.(xs) .- 0.25\n",
"ys_high = 0.2 .* sin.(xs) .+ 0.25\n",
"\n",
"band!(xs, ys_low, ys_high)\n",
"band!(xs, ys_low .- 1, ys_high .-1, color = :red)\n",
"\n",
"f"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "242380da",
"metadata": {},
"outputs": [],
"source": [
"f = Figure()\n",
"Axis(f[1, 1])\n",
"\n",
"xs = LinRange(0, 10, 100)\n",
"ys = LinRange(0, 15, 100)\n",
"zs = [cos(x) * sin(y) for x in xs, y in ys]\n",
"\n",
"contour!(zs,levels=-1:0.1:1)\n",
"\n",
"f"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ff5c9a2d",
"metadata": {},
"outputs": [],
"source": [
"fig, ax, hm = heatmap(randn(20, 20))\n",
"Colorbar(fig[1, 2], hm)\n",
"fig"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.8.5",
"language": "julia",
"name": "julia-1.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

File diff suppressed because it is too large Load Diff

View File

@ -1,989 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "69149570",
"metadata": {},
"source": [
"# Ein Fallbeispiel: Der parametrisierte Datentyp PComplex\n",
"\n",
"Wir wollen als neuen numerischen Typen **komplexe Zahlen in Polardarstellung $z=r e^{i\\phi}=(r,ϕ)$** einführen. \n",
"\n",
"- Der Typ soll sich in die Typhierarchie einfügen als Subtyp von 'Number'.\n",
"- $r$ und $\\phi$ sollen Gleitkommazahlen sein. (Im Unterschied zu komplexen Zahlen in 'kartesischen' Koordinaten hat eine Einschränkung auf ganzzahlige Werte von r oder ϕ mathematisch wenig Sinn.)\n",
"\n",
"## Die Definition von `PComplex`\n",
"\n",
"Ein erster Versuch könnte so aussehen:\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "3ee9c4ae",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"z1 = PComplex1{Float64}(-32.0, 33.0)\n",
"z2 = PComplex1{Float32}(12.0f0, 13.0f0)\n"
]
}
],
"source": [
"struct PComplex1{T <: AbstractFloat} <: Number\n",
" r :: T\n",
" ϕ :: T\n",
"end\n",
"\n",
"z1 = PComplex1(-32.0, 33.0)\n",
"z2 = PComplex1{Float32}(12, 13)\n",
"@show z1 z2;"
]
},
{
"cell_type": "markdown",
"id": "729a1d8e",
"metadata": {},
"source": [
"Julia stellt automatisch *default constructors* zur Verfügung:\n",
"\n",
"- den Konstruktor `PComplex1`, bei dem der Typ `T` von den übergebenen Argumenten abgeleitet wird und\n",
"- Konstruktoren `PComplex{Float64},...` mit expliziter Typangabe. Hier wird versucht, die Argumente in den angeforderten Typ zu konvertieren. \n",
"\n",
"------\n",
"\n",
"Wir wollen nun, dass der Konstruktor noch mehr tut. \n",
"In der Polardarstellung soll $0\\le r$ und $0\\le \\phi<2\\pi$ gelten.\n",
"\n",
"Wenn die übergebenen Argumente das nicht erfüllen, sollten sie entsprechend umgerechnet werden.\n",
"\n",
"Dazu definieren wir einen _inner constructor_, der den _default constructor_ ersetzt.\n",
"\n",
"- Ein _inner constructor_ ist eine Funktion innerhalb der `struct`-Definition.\n",
"- In einem _inner constructor_ kann man die spezielle Funktion `new` verwenden, die wie der _default constructor_ wirkt.\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "214480f6",
"metadata": {},
"outputs": [],
"source": [
"struct PComplex{T <: AbstractFloat} <: Number\n",
" r :: T\n",
" ϕ :: T\n",
"\n",
" function PComplex{T}(r::T, ϕ::T) where T<:AbstractFloat\n",
" if r<0 # flip the sign of r and correct phi\n",
" r = -r\n",
" ϕ += π\n",
" end\n",
" if r==0 ϕ=0 end # normalize r=0 case to phi=0 \n",
" ϕ = mod(ϕ, 2π) # map phi into interval [0,2pi)\n",
" new(r, ϕ) # new() ist special function,\n",
" end # available only inside inner constructors\n",
"\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "873d5dc6",
"metadata": {},
"outputs": [],
"source": [
"#| echo: false\n",
"#| output: false\n",
"\n",
"#=\n",
"in den ganzen quarto-runs wollen bir hier noch das default-show benutzen\n",
"=#\n",
"zz = @which Base.show(stdout, PComplex{Float64}(2.,3.))\n",
"if zz.module != Base\n",
" Base.delete_method(zz)\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "95c7386c",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"PComplex{Float64}(3.3, 1.0)"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"z1 = PComplex{Float64}(-3.3, 7π+1)"
]
},
{
"cell_type": "markdown",
"id": "eb213995",
"metadata": {},
"source": [
"Für die explizite Angabe eines *inner constructors* müssen wir allerdings einen Preis zahlen: Die sonst von Julia bereitgestellten *default constructors* fehlen. \n",
"\n",
"Den Konstruktor, der ohne explizite Typangabe in geschweiften Klammern auskommt und den Typ der Argumente übernimmt, wollen wir gerne auch haben:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "e87d3a42",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"PComplex{Float64}(2.0, 0.3)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"PComplex(r::T, ϕ::T) where {T<:AbstractFloat} = PComplex{T}(r,ϕ)\n",
"\n",
"z2 = PComplex(2.0, 0.3)"
]
},
{
"cell_type": "markdown",
"id": "0512b019",
"metadata": {},
"source": [
"## Eine neue Schreibweise\n",
"\n",
"Julia verwendet `//` als Infix-Konstruktor für den Typ `Rational`. Sowas Schickes wollen wir auch. \n",
"\n",
"In der Elektronik/Elektrotechnik werden [Wechselstromgrößen durch komplexe Zahlen beschrieben.](https://de.wikipedia.org/wiki/Komplexe_Wechselstromrechnung). Dabei ist eine Darstellung komplexer Zahlen durch \"Betrag\" und \"Phase\" üblich und sie wird gerne in der sogenannten [Versor-Form](https://de.wikipedia.org/wiki/Versor) (engl. *phasor*) dargestellt:\n",
"$$\n",
" z= r\\enclose{phasorangle}{\\phi} = 3.4\\;\\enclose{phasorangle}{45^\\circ}\n",
"$$\n",
"wobei man in der Regel den Winkel in Grad notiert. \n",
"\n",
":::{.callout-note .titlenormal collapse=\"true\"}\n",
"\n",
"## Mögliche Infix-Operatoren in Julia\n",
"\n",
"In Julia ist eine große Anzahl von Unicode-Zeichen reserviert für die Verwendung als Operatoren. Die definitive Liste ist im [Quellcode des Parsers.](https://github.com/JuliaLang/julia/blob/eaa2c58aeb12f27c1d8c116ab111773a4fc4495f/src/julia-parser.scm#L13-L31)\n",
"\n",
"Auf Details werden wir in einem späteren Kapitel noch eingehen. \n",
"\n",
"Und ja, der Julia-Parser ist in einem Lisp(genauer: Scheme)-Dialekt geschrieben. In Julia ist ein kleiner Scheme-Interpreter namens [femtolisp](https://github.com/JeffBezanson/femtolisp) integriert. Geschrieben hat ihn einer der \"Väter\" von Julia bevor er mit der Arbeit an Julia begann. \n",
"\n",
":::\n",
"\n",
"Das Winkel-Zeichen `∠` steht leider nicht als Operatorsymbol zur Verfügung. Wir weichen aus auf `⋖`. Das kann in Julia als als `\\lessdot<tab>` eingegeben werden.\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "81818d42",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"PComplex{Float64}(2.0, 1.5707963267948966)"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
" ⋖(r::Real, ϕ::Real) = PComplex(r, π*ϕ/180)\n",
"\n",
"z3 = 2. ⋖ 90."
]
},
{
"cell_type": "markdown",
"id": "bf0863e9",
"metadata": {},
"source": [
"(Die Typ-Annotation -- `Real` statt `AbstractFloat` -- ist ein Vorgriff auf kommende weitere Konstruktoren. Im Moment funktioniert der Operator `⋖` erstmal nur mit `Float`s.)\n",
"\n",
"\n",
"Natürlich wollen wir auch die Ausgabe so schön haben. Details dazu findet man in der [Dokumentation](https://docs.julialang.org/en/v1/manual/types/#man-custom-pretty-printing).\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "4cf73e28",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"z3 = 2.0⋖90.0°\n"
]
}
],
"source": [
"using Printf\n",
"\n",
"function Base.show(io::IO, z::PComplex)\n",
" # wir drucken die Phase in Grad, auf Zehntelgrad gerundet, \n",
" p = z.ϕ * 180/π\n",
" sp = @sprintf \"%.1f\" p\n",
" print(io, z.r, \"⋖\", sp, '°')\n",
"end\n",
"\n",
"@show z3;"
]
},
{
"cell_type": "markdown",
"id": "0dae2fef",
"metadata": {},
"source": [
"## Methoden für `PComplex`\n",
"\n",
"Damit unser Typ ein anständiges Mitglied der von `Number` abstammenden Typfamilie wird, brauchen wir allerdings noch eine ganze Menge mehr. Es müssen Arithmetik, Vergleichsoperatoren, Konvertierungen usw. definiert werden. \n",
"\n",
"\n",
"Wir beschränken uns auf Multiplikation und Quadratwurzeln.\n",
"\n",
"\n",
":::{.callout-note collapse=\"true\"}\n",
"## Module \n",
"\n",
"- Um die `methods` der existierenden Funktionen und Operationen zu ergänzen, muss man diese mit ihrem 'vollen Namen' ansprechen.\n",
"- Alle Objekte gehören zu einem Namensraum oder `module`.\n",
"- Die meisten Basisfunktionen gehören zum Modul `Base`, welches standardmäßig immer ohne explizites `using ...` geladen wird. \n",
"- Solange man keine eigenen Module definiert, sind die eigenen Definitionen im Modul `Main`.\n",
"- Das Macro `@which`, angewendet auf einen Namen, zeigt an, in welchem Modul der Name definiert wurde. \n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "042418fd",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Main"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f(x) = 3x^3\n",
"@which f"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "c20d10e5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Modul für Addition: Base, Modul für sqrt: Base\n"
]
}
],
"source": [
"wp = @which +\n",
"ws = @which(sqrt)\n",
"println(\"Modul für Addition: $wp, Modul für sqrt: $ws\")"
]
},
{
"cell_type": "markdown",
"id": "82fe20b4",
"metadata": {},
"source": [
":::\n"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "a53f0e79",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"qwurzel (generic function with 1 method)"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"qwurzel(z::PComplex) = PComplex(sqrt(z.r), z.ϕ / 2)"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "d6987594",
"metadata": {},
"outputs": [],
"source": [
"#| echo: false\n",
"#| output: false\n",
"\n",
"#=\n",
"damit das length(methods(sqrt)) klappt\n",
"=#\n",
"if hasmethod(sqrt, (PComplex,))\n",
" zz = @which Base.sqrt(PComplex{Float64}(1.,1.))\n",
" Base.delete_method(zz)\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "53f4bb77",
"metadata": {},
"source": [
"Die Funktion `sqrt()` hat schon einige Methoden:\n"
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "f93f63c6",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"19"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"length(methods(sqrt))"
]
},
{
"cell_type": "markdown",
"id": "7b4f323a",
"metadata": {},
"source": [
"Jetzt wird es eine Methode mehr:\n"
]
},
{
"cell_type": "code",
"execution_count": 32,
"id": "b88cd74b",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"20"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Base.sqrt(z::PComplex) = qwurzel(z)\n",
"\n",
"length(methods(sqrt))"
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "e077b8bf",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1.4142135623730951⋖8.6°"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sqrt(z2)"
]
},
{
"cell_type": "markdown",
"id": "e223fdd1",
"metadata": {},
"source": [
"und nun zur Multiplikation:\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "5537f7ec",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"z1 * z2 = 6.6⋖74.5°\n"
]
}
],
"source": [
"Base.:*(x::PComplex, y::PComplex) = PComplex(x.r * y.r, x.ϕ + y.ϕ)\n",
"\n",
"@show z1 * z2;"
]
},
{
"cell_type": "markdown",
"id": "7189f0c6",
"metadata": {},
"source": [
"(Da das Operatorsymbol kein normaler Name ist, muss der Doppelpunkt bei der Zusammensetzung mit `Base.` sein.)\n",
"\n",
"Wir können allerdings noch nicht mit anderen numerischen Typen multiplizieren. Dazu könnte man nun eine Vielzahl von entsprechenden Methoden definieren. Julia stellt *für numerische Typen* noch einen weiteren Mechanismus zur Verfügung, der das etwas vereinfacht.\n",
"\n",
"\n",
"## Typ-Promotion und Konversion \n",
"\n",
"In Julia kann man bekanntlich die verschiedensten numerischen Typen nebeneinander verwenden.\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "610a38fe",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"265.53333333333336"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1//3 + 5 + 5.2 + 0xff"
]
},
{
"cell_type": "markdown",
"id": "bc39d089",
"metadata": {},
"source": [
"Wenn man in die zahlreichen Methoden schaut, die z.B. für `+` und `*` definiert sind, findet man u.a. eine Art 'catch-all-Definition'\n",
"\n",
"```julia\n",
"+(x::Number, y::Number) = +(promote(x,y)...)\n",
"*(x::Number, y::Number) = *(promote(x,y)...)\n",
"```\n",
"\n",
"\n",
"\n",
"(Die 3 Punkte sind der splat-Operator, der das von promote() zurückgegebene Tupel wieder in seine Bestandteile zerlegt.)\n",
"\n",
"Da die Methode mit den Typen `(Number, Number)` sehr allgemein ist, wird sie erst verwendet, wenn spezifischere Methoden nicht greifen.\n",
"\n",
"Was passiert hier?\n",
"\n",
"### Die Funktion `promote(x,y,...)`\n",
"\n",
"Diese Funktion versucht, alle Argumente in einen gemeinsamen Typen umzuwandeln, der alle Werte (möglichst) exakt darstellen kann.\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "48cae0ae",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(12.0, 34.555, 0.7777777777777778, 255.0)"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"promote(12, 34.555, 77/99, 0xff)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "768934ac",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"z = (33, 27)\n",
"typeof(z) = Tuple{BigInt, BigInt}\n"
]
}
],
"source": [
"z = promote(BigInt(33), 27)\n",
"@show z typeof(z);"
]
},
{
"cell_type": "markdown",
"id": "df2672c5",
"metadata": {},
"source": [
"Die Funktion `promote()` verwendet dazu zwei Helfer, die Funktionen\n",
" `promote_type(T1, T2)` und `convert(T, x)`\n",
"\n",
"Wie üblich in Julia, kann man diesen Mechanismus durch [eigene *promotion rules* und `convert(T,x)`-Methoden erweitern.](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/) \n",
"\n",
"\n",
"### Die Funktion `promote_type(T1, T2,...)` \n",
"\n",
"Sie ermittelt, zu welchem Typ umgewandelt werden soll. Argumente sind Typen, nicht Werte.\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "70306adc",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"promote_type(Rational{Int64}, ComplexF64, Float32) = ComplexF64\n"
]
}
],
"source": [
"@show promote_type(Rational{Int64}, ComplexF64, Float32);"
]
},
{
"cell_type": "markdown",
"id": "ec999b3a",
"metadata": {},
"source": [
"### Die Funktion `convert(T,x)`\n",
"\n",
"Die Methoden von \n",
"`convert(T, x)` wandeln `x` in ein Objekt vom Typ `T` um. Dabei sollte eine solche Umwandlung verlustfrei möglich sein.\n"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "b326a121",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3.0"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"z = convert(Float64, 3)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "57606643",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"23"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"z = convert(Int64, 23.00)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "a3b39504",
"metadata": {},
"outputs": [
{
"ename": "LoadError",
"evalue": "InexactError: Int64(2.3)",
"output_type": "error",
"traceback": [
"InexactError: Int64(2.3)",
"",
"Stacktrace:",
" [1] Int64",
" @ ./float.jl:912 [inlined]",
" [2] convert(::Type{Int64}, x::Float64)",
" @ Base ./number.jl:7",
" [3] top-level scope",
" @ In[20]:1"
]
}
],
"source": [
"z = convert(Int64, 2.3)"
]
},
{
"cell_type": "markdown",
"id": "06251c1d",
"metadata": {},
"source": [
"Die spezielle Rolle von `convert()` liegt darin, dass es an verschiedenen Stellen _implizit_ und automatisch eingesetzt wird: \n",
"\n",
"> [The following language constructs call convert](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/#When-is-convert-called?):\n",
"> \n",
" - Assigning to an array converts to the array's element type.\n",
" - Assigning to a field of an object converts to the declared type of the field.\n",
" - Constructing an object with new converts to the object's declared field types.\n",
" - Assigning to a variable with a declared type (e.g. local x::T) converts to that type.\n",
" - A function with a declared return type converts its return value to that type.\n",
"\n",
"-- und natürlich in `promote()`\n",
"\n",
"Für selbstdefinierte Datentypen kann man convert() um weitere Methoden ergänzen.\n",
"\n",
"Für Datentypen innerhalb der Number-Hierarchie gibt es wieder eine 'catch-all-Definition'\n",
"```julia\n",
"convert(::Type{T}, x::Number) where {T<:Number} = T(x)\n",
"```\n",
"\n",
"Also: Wenn für einen Typen `T` aus der Hierarchie `T<:Number` ein Konstruktor `T(x)` mit einem numerischen Argument `x` existiert, dann wird dieser Konstruktor `T(x)` automatisch für Konvertierungen benutzt. (Natürlich können auch speziellere Methoden für `convert()` definiert werden, die dann Vorrang haben.)\n",
"\n",
"\n",
"### Weitere Konstruktoren für `PComplex`\n"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "e258330e",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"PComplex"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"## (a) r, ϕ beliebige Reals, z.B. Integers, Rationals\n",
"\n",
"PComplex{T}(r::T1, ϕ::T2) where {T<:AbstractFloat, T1<:Real, T2<: Real} = \n",
" PComplex{T}(convert(T, r), convert(T, ϕ))\n",
"\n",
"PComplex(r::T1, ϕ::T2) where {T1<:Real, T2<: Real} = \n",
" PComplex{promote_type(Float64, T1, T2)}(r, ϕ) \n",
"\n",
"## (b) Zur Umwandlung von Reals: Konstruktor mit \n",
"## nur einem Argument r\n",
"\n",
"PComplex{T}(r::S) where {T<:AbstractFloat, S<:Real} = \n",
" PComplex{T}(convert(T, r), convert(T, 0)) \n",
"\n",
"PComplex(r::S) where {S<:Real} = \n",
" PComplex{promote_type(Float64, S)}(r, 0.0)\n",
"\n",
"## (c) Umwandlung Complex -> PComplex\n",
"\n",
"PComplex{T}(z::Complex{S}) where {T<:AbstractFloat, S<:Real} = \n",
" PComplex{T}(abs(z), angle(z))\n",
"\n",
"PComplex(z::Complex{S}) where {S<:Real} = \n",
" PComplex{promote_type(Float64, S)}(abs(z), angle(z))\n"
]
},
{
"cell_type": "markdown",
"id": "ccb96089",
"metadata": {},
"source": [
"Ein Test der neuen Konstruktoren:\n"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "ec747779",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(0.6⋖45.0°, 1.4142135623730951⋖45.0°, 13.0⋖180.0°)"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"3//5 ⋖ 45, PComplex(Complex(1,1)), PComplex(-13) "
]
},
{
"cell_type": "markdown",
"id": "fd8541cf",
"metadata": {},
"source": [
"Wir brauchen nun noch *promotion rules*, die festlegen, welcher Typ bei `promote(x::T1, y::T2)` herauskommen soll. Damit wird `promote_type()` intern um die nötigen weiteren Methoden erweitert. \n",
"\n",
"### *Promotion rules* für `PComplex`\n"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "806fff6a",
"metadata": {},
"outputs": [],
"source": [
"Base.promote_rule(::Type{PComplex{T}}, ::Type{S}) where {T<:AbstractFloat,S<:Real} = \n",
" PComplex{promote_type(T,S)}\n",
"\n",
"Base.promote_rule(::Type{PComplex{T}}, ::Type{Complex{S}}) where \n",
" {T<:AbstractFloat,S<:Real} = PComplex{promote_type(T,S)}"
]
},
{
"cell_type": "markdown",
"id": "97c7de69",
"metadata": {},
"source": [
"1. Regel:\n",
": Wenn ein `PComplex{T}` und ein `S<:Real` zusammentreffen, dann sollen beide zu `PComplex{U}` umgewandelt werden, wobei `U` der Typ ist, zu dem `S` und `T` beide umgewandelt (_promoted_) werden können. \n",
"\n",
"2. Regel\n",
": Wenn ein `PComplex{T}` und ein `Complex{S}` zusammentreffen, dann sollen beide zu `PComplex{U}` umgewandelt werden, wobei `U` der Typ ist, zu dem `S` und `T` beide umgewandelt werden können. \n",
"\n",
"\n",
"\n",
"Damit klappt nun die Multiplikation mit beliebigen numerischen Typen.\n"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "cc47939d",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(2.0⋖90.0°, 6.0⋖90.0°)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"z3, 3z3"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "63c20bc7",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(43.26661530556787⋖64.0°, 16.970562748477143⋖8.6°)"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(3.0+2im) * (12⋖30.3), 12sqrt(z2) "
]
},
{
"cell_type": "markdown",
"id": "e94c6b15",
"metadata": {},
"source": [
":::{.callout-caution icon=\"false\" collapse=\"true\" .titlenormal}\n",
"\n",
"## Zusammenfassung: unser Typ `PComplex`\n",
"\n",
"```julia\n",
"struct PComplex{T <: AbstractFloat} <: Number\n",
" r :: T\n",
" ϕ :: T\n",
"\n",
" function PComplex{T}(r::T, ϕ::T) where T<:AbstractFloat\n",
" if r<0 # flip the sign of r and correct phi\n",
" r = -r\n",
" ϕ += π\n",
" end\n",
" if r==0 ϕ=0 end # normalize r=0 case to phi=0 \n",
" ϕ = mod(ϕ, 2π) # map phi into interval [0,2pi)\n",
" new(r, ϕ) # new() ist special function,\n",
" end # available only inside inner constructors\n",
"\n",
"end\n",
"\n",
"# additional constructors\n",
"PComplex(r::T, ϕ::T) where {T<:AbstractFloat} = PComplex{T}(r,ϕ)\n",
"\n",
"\n",
"PComplex{T}(r::T1, ϕ::T2) where {T<:AbstractFloat, T1<:Real, T2<: Real} = \n",
" PComplex{T}(convert(T, r), convert(T, ϕ))\n",
"\n",
"PComplex(r::T1, ϕ::T2) where {T1<:Real, T2<: Real} = \n",
" PComplex{promote_type(Float64, T1, T2)}(r, ϕ) \n",
"\n",
"\n",
"PComplex{T}(r::S) where {T<:AbstractFloat, S<:Real} = \n",
" PComplex{T}(convert(T, r), convert(T, 0)) \n",
"\n",
"PComplex(r::S) where {S<:Real} = \n",
" PComplex{promote_type(Float64, S)}(r, 0.0)\n",
"\n",
"\n",
"PComplex{T}(z::Complex{S}) where {T<:AbstractFloat, S<:Real} = \n",
" PComplex{T}(abs(z), angle(z))\n",
"\n",
"PComplex(z::Complex{S}) where {S<:Real} = \n",
" PComplex{promote_type(Float64, S)}(abs(z), angle(z))\n",
"\n",
"# nice input\n",
"⋖(r::Real, ϕ::Real) = PComplex(r, π*ϕ/180)\n",
"\n",
"# nice output\n",
"using Printf\n",
"\n",
"function Base.show(io::IO, z::PComplex)\n",
" # wir drucken die Phase in Grad, auf Zehntelgrad gerundet, \n",
" p = z.ϕ * 180/π\n",
" sp = @sprintf \"%.1f\" p\n",
" print(io, z.r, \"⋖\", sp, '°')\n",
"end\n",
"\n",
"# arithmetic\n",
"Base.sqrt(z::PComplex) = PComplex(sqrt(z.r), z.ϕ / 2)\n",
"\n",
"Base.:*(x::PComplex, y::PComplex) = PComplex(x.r * y.r, x.ϕ + y.ϕ)\n",
"\n",
"# promotion rules\n",
"Base.promote_rule(::Type{PComplex{T}}, ::Type{S}) where \n",
" {T<:AbstractFloat,S<:Real} = PComplex{promote_type(T,S)}\n",
"\n",
"Base.promote_rule(::Type{PComplex{T}}, ::Type{Complex{S}}) where \n",
" {T<:AbstractFloat,S<:Real} = PComplex{promote_type(T,S)}\n",
"```\n",
":::\n",
"\n",
":::{.content-hidden unless-format=\"xxx\"}\n",
"\n",
"Jetzt geht sowas wie `PComplex(1, 0)` noch nicht. Wir wollen auch andere reelle Typen für `r` und `ϕ` zulassen. Der Einfachheit halber wandeln wir hier alles nach `Float64` um. Analog verfahren wir auch, wenn nur ein reelles oder komplexes Argument verwendet wird.\n",
"\n",
"```julia\n",
"PComplex(r::Real, ϕ::Real) = PComplex(Float64(r), Float64(ϕ))\n",
"PComplex(r::Real) = PComplex(Float64(r), 0.0)\n",
"PComplex(z::Complex) = PComplex(abs(z), angle(z))\n",
"\n",
"z3 = PComplex(-2); z4 = PComplex(3im)\n",
"@show z3 z4;\n",
"```\n",
"\n",
":::"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.10.2",
"language": "julia",
"name": "julia-1.10"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.10.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,8 +0,0 @@
#!/bin/bash
cp ../chapters/*.quarto_ipynb .
for i in *.quarto_ipynb
do
echo $i
mv $i "${i%.quarto_ipynb}.ipynb"
jupyter nbconvert --inplace --clear-output --to notebook "${i%.quarto_ipynb}.ipynb"
done

View File

@ -1,167 +0,0 @@
{
"cells": [
{
"cell_type": "raw",
"id": "bb4361d9",
"metadata": {},
"source": [
"---\n",
"title: summary\n",
"---"
]
},
{
"cell_type": "markdown",
"id": "58e5805d",
"metadata": {},
"source": [
"format:\n",
" html:\n",
" include-in-header:\n",
" text: |\n",
" <script type=\"application/javascript\">\n",
" requirejs.config({ baseUrl: '.',\n",
" //paths: {\n",
" // Plotly: 'plotly-latest.min.js'\n",
" // }\n",
" });\n",
" </script>\n",
"\n",
"\n",
"https://github.com/JuliaPlots/PlotlyJS.jl/issues/322\n",
"\n",
"In summary, this book has no content whatsoever.\n",
"\n",
"https://discourse.julialang.org/t/seven-lines-of-julia-examples-sought/50416\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "caf6e3b3",
"metadata": {},
"outputs": [],
"source": [
"#| error: false\n",
"using PlotlyJS, Random\n",
"using HypertextLiteral\n",
"using JSON, UUIDs\n",
"using Base64\n",
"\n",
"function IJulia.display_dict(p::PlotlyJS.SyncPlot)\n",
" Dict(\n",
" # \"application/vnd.plotly.v1+json\" => JSON.lower(p),\n",
" # \"text/plain\" => sprint(show, \"text/plain\", p),\n",
" \"text/html\" => let\n",
" buf = IOBuffer()\n",
" show(buf, MIME(\"text/html\"), p)\n",
" String(resize!(buf.data, buf.size))\n",
" end,\n",
" \"image/png\" => let\n",
" buf = IOBuffer()\n",
" buf64 = Base64EncodePipe(buf)\n",
" show(buf64, MIME(\"image/png\"), p)\n",
" String(resize!(buf.data, buf.size))\n",
" end,\n",
"\n",
" )\n",
" end\n",
" \n",
" function Base.show(io::IO, mimetype::MIME\"text/html\", p::PlotlyJS.SyncPlot)\n",
" uuid = string(UUIDs.uuid4())\n",
" show(io,mimetype,@htl(\"\"\"\n",
" <div style=\"height: auto\" id=\\\"$(uuid)\\\"></div>\n",
" <script>\n",
" require(['../js/plotly-latest.min.js'], function(plotly) { \n",
" plotly.newPlot($(uuid),\n",
" $(HypertextLiteral.JavaScript(json(p.plot.data))),\n",
" $(HypertextLiteral.JavaScript(json(p.plot.layout))),{responsive: true});\n",
" });\n",
" </script>\n",
"\"\"\"))\n",
"end "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a6260dc2",
"metadata": {},
"outputs": [],
"source": [
"Random.seed!(42)\n",
"\n",
"N = 100\n",
"random_x = range(0, stop=1, length=N)\n",
"random_y0 = randn(N) .+ 5\n",
"random_y1 = randn(N)\n",
"random_y2 = randn(N) .- 5\n",
"\n",
"plot([\n",
" scatter(x=random_x, y=random_y0, mode=\"markers\", name=\"markers\"),\n",
" scatter(x=random_x, y=random_y1, mode=\"lines\", name=\"lines\"),\n",
" scatter(x=random_x, y=random_y2, mode=\"markers+lines\", name=\"markers+lines\")\n",
"])"
]
},
{
"cell_type": "markdown",
"id": "dd0a1a29",
"metadata": {},
"source": [
"jkjkjkj\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "813b97ce",
"metadata": {},
"outputs": [],
"source": [
"#| warning: false\n",
"\n",
"plot([\n",
" scatter(x=random_x, y=random_y0, mode=\"markers\", name=\"markers\") ])"
]
},
{
"cell_type": "markdown",
"id": "c271b5dc",
"metadata": {},
"source": [
";;l;l;l\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6cb53248",
"metadata": {},
"outputs": [],
"source": [
"#| warning: false\n",
"\n",
"plot([\n",
" scatter(x=random_x, y=random_y2, mode=\"markers\", name=\"markers\") ])"
]
},
{
"cell_type": "markdown",
"id": "7df06b26",
"metadata": {},
"source": [
"lllklk"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.8.5",
"language": "julia",
"name": "julia-1.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff