4 Commits

Author SHA1 Message Date
552438aebe some small improvements in English 2026-02-22 19:18:21 +01:00
3b9c141c44 Manifest.toml added 2026-02-22 18:27:58 +01:00
04b8a23362 opencode files added 2026-02-22 18:26:58 +01:00
9e418381ca english translation started 2026-02-22 18:22:46 +01:00
20 changed files with 4499 additions and 1929 deletions

216
AGENTS.md Normal file
View File

@@ -0,0 +1,216 @@
# AGENTS.md - Guidelines for Agentic Coding in JuliaKurs23
This is a **Quarto-based Julia programming course book** in English. The book teaches scientific computing with Julia using interactive Jupyter notebooks rendered with Quarto.
**Translation Note:** The book was originally written in German and has been translated to professional, concise English suitable for mathematicians. All code, LaTeX equations, and formatting have been preserved during translation. Only text descriptions and code comments were translated to English.
## Project Overview
- **Type**: Educational book website/PDF generated from Quarto (.qmd) files
- **Language**: English (all content)
- **Build System**: Quarto with Julia Jupyter kernel
- **Julia Version**: 1.10
- **Output**: HTML website and PDF
- **License**: CC BY-NC-SA 4.0
---
## Build Commands
### Build the Book
```bash
# Build HTML website
quarto render
# Build only HTML
quarto render --to julia-color-html
# Build only PDF
quarto render --to julia-color-pdf
# Preview locally
quarto preview
```
### Development Commands
```bash
# Render a specific chapter
quarto render chapters/first_contact.qmd
# Build with specific output directory
quarto render --output-dir _book
# Run in daemon mode (faster rebuilds)
quarto render --execute-daemon 3600
```
### Deployment
```bash
# Deploy to web server (rsync _book/)
./deploy.sh
```
### Testing Individual Code Blocks
Quarto executes Julia code in Jupyter notebooks. To test individual code blocks:
1. Open the `.qmd` file in VS Code with Julia extension
2. Use Julia REPL to execute code blocks interactively
3. Or use IJulia/Jupyter to run specific cells
```julia
# In Julia REPL, test code from a cell:
include("path/to/notebook.jl")
```
### Julia Package Management
```bash
# Install dependencies (from Project.toml)
julia -e 'using Pkg; Pkg.instantiate()'
# Add a new package
julia -e 'using Pkg; Pkg.add("PackageName")'
```
---
## Code Style Guidelines
### General Structure (.qmd files)
- All `.qmd` files start with YAML front matter specifying `engine: julia`
- Code blocks use triple backticks with `julia` language identifier
- Use Quarto cell options in comments like `#| option: value`
- Common options: `eval:`, `echo:`, `output:`, `error:`, `hide_line:`
Example:
```markdown
---
engine: julia
---
```{julia}
#| eval: true
#| echo: true
#| output: true
using Statistics
mean([1, 2, 3])
```
```
### Julia Code Conventions
#### Imports
```julia
# Prefer using for packages with many exports
using Statistics, LinearAlgebra, Plots
# Use import when you need specific exports or module name
import Base: convert, show
```
#### Naming Conventions
- **Variables/functions**: lowercase with underscores (`my_variable`, `calculate_mean`)
- **Types**: CamelCase (`MyType`, `AbstractMatrix`)
- **Constants**: ALL_UPPERCASE (`MAX_ITER`, `PI`)
- **Modules**: PascalCase (`Statistics`, `LinearAlgebra`)
#### Formatting
- Use 4 spaces for indentation (Julia default)
- Limit lines to ~92 characters when practical
- Use spaces around operators: `a + b`, not `a+b`
- No spaces before commas: `f(a, b)`, not `f(a , b)`
#### Types
- Use explicit types when needed for performance or clarity
- Parameterize types when useful: `Vector{Float64}`, `Dict{Symbol, Int}`
- Prefer concrete types for fields in structs
#### Error Handling
```julia
# Use try-catch for expected errors
try
parse(Int, user_input)
catch e
println("Invalid input: $e")
end
# Use assertions for internal checks
@assert x >= 0 "x must be non-negative"
```
### Quarto-Specific Guidelines
#### Cell Options
Use these in code block comments:
- `#| eval: true/false` - whether to execute
- `#| echo: true/false` - show source code
- `#| output: true/false` - show output
- `#| error: true/false` - show errors
- `#| hide_line: true` - hide this line from output
- `#| fig-cap: "Caption"` - figure caption
#### Embedding Notebooks
```markdown
{{< embed notebooks/nb-types.ipynb#nb1 >}}
```
#### Conditional Content
```markdown
::: {.content-visible when-format="html"}
... HTML only content
:::
::: {.content-visible when-format="pdf"}
... PDF only content
:::
```
---
## File Organization
```
/
├── _quarto.yml # Quarto configuration
├── Project.toml # Julia dependencies
├── index.qmd # Book index
├── chapters/ # Chapter .qmd files
├── notebooks/ # Jupyter notebooks (.ipynb)
├── css/ # Custom styles
├── images/ # Images and logos
├── fonts/ # Custom fonts
└── _book/ # Built output (generated)
```
---
## VS Code Settings
The project uses VS Code with:
- Julia environment: `/home/hellmund/Julia/23`
- LTEx for spell checking (disabled for code blocks)
- Auto-exclude: `.ipynb`, `.md`, `.quarto_ipynb` files
---
## Important Notes
1. **All content is in English** - Comments, documentation, variable names in examples should be English (professional, concise, suitable for mathematicians)
2. **Code comments were translated** - German text and code comments were translated to English; all Julia code, LaTeX equations, and Quarto formatting were preserved
3. **Code execution is cached** - Use `#| eval: true` to execute cells
4. **ansi color codes** - The `julia-color` extension handles ANSI escape sequences in output
5. **Freeze mode** - Set to `auto` in _quarto.yml; use `freeze: false` to re-run all code
6. **Keep intermediate files** - `keep-ipynb`, `keep-tex`, `keep-md` are all true

2339
Manifest.toml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -11,96 +11,97 @@ import QuartoNotebookWorker
Base.stdout = QuartoNotebookWorker.with_context(stdout)
```
# Zeichen, Strings und Unicode
# Characters, Strings, and Unicode
## Zeichencodierungen (Frühgeschichte)
## Character Encodings (Early History)
Es gab - abhängig von Hersteller, Land, Programmiersprache, Betriebsssystem,... - eine große Vielzahl von Codierungen.
There were - depending on manufacturer, country, programming language, operating system, etc. - a large variety of encodings.
Bis heute relevant sind:
Still relevant today:
### ASCII
Der _American Standard Code for Information Interchange_ wurde 1963 in den USA als Standard veröffentlicht.
The _American Standard Code for Information Interchange_ was published as a standard in the USA in 1963.
- Er definiert $2^7=128$ Zeichen, und zwar:
- 33 Steuerzeichen, wie `newline`, `escape`, `end of transmission/file`, `delete`
- 95 graphisch darstellbare Zeichen:
- 52 lateinische Buchstaben `a-z, A-Z`
- 10 Ziffern `0-9`
- 7 Satzzeichen `.,:;?!"`
- 1 Leerzeichen ` `
- 6 Klammern `[{()}]`
- 7 mathematische Operationen `+-*/<>=`
- 12 Sonderzeichen ``` #$%&'\^_|~`@ ```
- It defines $2^7=128$ characters, namely:
- 33 control characters, such as `newline`, `escape`, `end of transmission/file`, `delete`
- 95 graphically printable characters:
- 52 Latin letters `a-z, A-Z`
- 10 digits `0-9`
- 7 punctuation marks `.,:;?!"`
- 1 space ` `
- 6 parentheses `[{()}]`
- 7 mathematical operations `+-*/<>=`
- 12 special characters ``` #$%&'\^_|~`@ ```
- ASCII ist heute noch der "kleinste gemeinsame Nenner" im Codierungs-Chaos.
- Die ersten 128 Unicode-Zeichen sind identisch mit ASCII.
- ASCII is still the "lowest common denominator" in the encoding chaos.
- The first 128 Unicode characters are identical to ASCII.
### ISO 8859-Zeichensätze
### ISO 8859 Character Sets
- ASCII nutzt nur 7 Bits.
- In einem Byte kann man durch Setzen des 8. Bits weitere 128 Zeichen unterbringen.
- 1987/88 wurden im ISO 8859-Standard verschiedene 1-Byte-Codierungen festgelegt, die alle ASCII-kompatibel sind, darunter:
- ASCII uses only 7 bits.
- In a byte, one can fit another 128 characters by setting the 8th bit.
- In 1987/88, various 1-byte encodings were standardized in ISO 8859, all ASCII-compatible, including:
:::{.narrow}
|Codierung | Region | Sprachen|
|Encoding | Region | Languages|
|:-----------|:----------|:-------|
|ISO 8859-1 (Latin-1) | Westeuropa | Deutsch, Französisch,...,Isländisch
|ISO 8859-2 (Latin-2) | Osteuropa | slawische Sprachen mit lateinischer Schrift
|ISO 8859-3 (Latin-3) | Südeuropa | Türkisch, Maltesisch,...
|ISO 8859-4 (Latin-4) | Nordeuropa | Estnisch, Lettisch, Litauisch, Grönländisch, Sami
|ISO 8859-5 (Latin/Cyrillic) | Osteuropa | slawische Sprachen mit kyrillischer Schrift
|ISO 8859-1 (Latin-1) | Western Europe | German, French,..., Icelandic
|ISO 8859-2 (Latin-2) | Eastern Europe | Slavic languages with Latin script
|ISO 8859-3 (Latin-3) | Southern Europe | Turkish, Maltese,...
|ISO 8859-4 (Latin-4) | Northern Europe | Estonian, Latvian, Lithuanian, Greenlandic, Sami
|ISO 8859-5 (Latin/Cyrillic) | Eastern Europe | Slavic languages with Cyrillic script
|ISO 8859-6 (Latin/Arabic) | |
|ISO 8859-7 (Latin/Greek) | |
|...| |
|ISO 8859-15 (Latin-9)| | 1999: Revision von Latin-1: jetzt u.a. mit Euro-Zeichen
|ISO 8859-15 (Latin-9)| | 1999: Revision of Latin-1: now including Euro sign
:::
## Unicode
Das Ziel des Unicode-Consortiums ist eine einheitliche Codierung für alle Schriften der Welt.
The goal of the Unicode Consortium is a uniform encoding for all scripts of the world.
- Unicode Version 1 erschien 1991
- Unicode Version 15.1 erschien 2023 mit 149 813 Zeichen, darunter:
- 161 Schriften
- mathematische und technische Symbole
- Emojis und andere Symbole, Steuer- und Formatierungszeichen
- davon entfallen über 90 000 Zeichen auf die CJK-Schriften (Chinesisch/Japanisch/Koreanisch)
### Technische Details
- Unicode version 1 was published in 1991
- Unicode version 15.1 was published in 2023 with 149,813 characters, including:
- 161 scripts
- mathematical and technical symbols
- Emojis and other symbols, control and formatting characters
- Over 90,000 characters are assigned to the CJK scripts (Chinese/Japanese/Korean)
- Jedem Zeichen wird ein `codepoint` zugeordnet. Das ist einfach eine fortlaufende Nummer.
- Diese Nummer wird hexadezimal notiert
- entweder 4-stellig als `U+XXXX` (0-te Ebene)
- oder 6-stellig als `U+XXXXXX` (weitere Ebenen)
- Jede Ebene geht von `U+XY0000` bis `U+XYFFFF`, kann also $2^{16}=65\;534$ Zeichen enthalten.
- Vorgesehen sind bisher 17 Ebenen `XY=00` bis `XY=10`, also der Wertebereich von `U+0000` bis `U+10FFFF`.
- Damit sind maximal 21 Bits pro Zeichen nötig.
- 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.
- Bisher wurden nur Codepoints aus den Ebenen
- Ebene 0 = BMP _Basic Multilingual Plane_ `U+0000 - U+FFFF`,
- Ebene 1 = SMP _Supplementary Multilingual Plane_ `U+010000 - U+01FFFF`,
- Ebene 2 = SIP _Supplementary Ideographic Plane_ `U+020000 - U+02FFFF`,
- Ebene 3 = TIP _Tertiary Ideographic Plane_ `U+030000 - U+03FFFF` und
- Ebene 14 = SSP _Supplementary Special-purpose Plane_ `U+0E0000 - U+0EFFFF`
vergeben.
- `U+0000` bis `U+007F` ist identisch mit ASCII
- `U+0000` bis `U+00FF` ist identisch mit ISO 8859-1 (Latin-1)
### Eigenschaften von Unicode-Zeichen
### Technical Details
Im Standard wird jedes Zeichen beschrieben duch
- Each character is assigned a `codepoint`. This is simply a sequential number.
- This number is written hexadecimally
- either 4-digit as `U+XXXX` (0th plane)
- or 6-digit as `U+XXXXXX` (further planes)
- Each plane ranges from `U+XY0000` to `U+XYFFFF`, thus can contain $2^{16}=65\;534$ characters.
- 17 planes `XY=00` to `XY=10` are provided so far, thus the value range from `U+0000` to `U+10FFFF`.
- Thus, a maximum of 21 bits per character are needed.
- The total number of possible codepoints is slightly less than 0x10FFFF, as certain areas are not used for technical reasons. It is about 1.1 million, so there is still much room.
- So far, codepoints from the planes have been assigned only from
- Plane 0 = BMP _Basic Multilingual Plane_ `U+0000 - U+FFFF`,
- Plane 1 = SMP _Supplementary Multilingual Plane_ `U+010000 - U+01FFFF`,
- Plane 2 = SIP _Supplementary Ideographic Plane_ `U+020000 - U+02FFFF`,
- Plane 3 = TIP _Tertiary Ideographic Plane_ `U+030000 - U+03FFFF` and
- Plane 14 = SSP _Supplementary Special-purpose Plane_ `U+0E0000 - U+0EFFFF`
have been assigned.
- `U+0000` to `U+007F` is identical to ASCII
- `U+0000` to `U+00FF` is identical to ISO 8859-1 (Latin-1)
- seinen Codepoint (Nummer)
- einen Namen (welcher nur aus ASCII-Großbuchstaben, Ziffern und Minuszeichen besteht) und
- verschiedene Attributen wie
- Laufrichtung der Schrift
- Kategorie: Großbuchstabe, Kleinbuchstabe, modifizierender Buchstabe, Ziffer, Satzzeichen, Symbol, Seperator,....
### Properties of Unicode Characters
Im Unicode-Standard sieht das dann so aus (zur Vereinfachung nur Codepoint und Name):
In the standard, each character is described by
- its codepoint (number)
- a name (which consists only of ASCII uppercase letters, digits, and hyphens) and
- various attributes such as
- script direction
- category: uppercase letter, lowercase letter, modifier letter, digit, punctuation, symbol, separator,....
In the Unicode standard, this looks like this (simplified, only codepoint and name):
```
...
U+0041 LATIN CAPITAL LETTER A
@@ -118,29 +119,29 @@ U+21B4 RIGHTWARDS ARROW WITH CORNER DOWNWARDS
...
```
Wie sieht 'RIGHTWARDS ARROW WITH CORNER DOWNWARDS' aus?
What does 'RIGHTWARDS ARROW WITH CORNER DOWNWARDS' look like?
Julia verwendet `\U...` zur Eingabe von Unicode Codepoints.
Julia uses `\U...` for input of Unicode codepoints.
```{julia}
'\U21b4'
```
### Eine Auswahl an Schriften
### A Selection of Scripts
::: {.content-visible when-format="html"}
:::{.callout-note}
Falls im Folgenden einzelne Zeichen oder Schriften in Ihrem Browser nicht darstellbar sind, müssen Sie geeignete
Fonts auf Ihrem Rechner installieren.
If individual characters or scripts are not displayable in your browser, you must install appropriate
fonts on your computer.
Alternativ können Sie die PDF-Version dieser Seite verwenden. Dort sind alle Fonts eingebunden.
Alternatively, you can use the PDF version of this page. There, all fonts are embedded.
:::
:::
Eine kleine Hilfsfunktion:
A small helper function:
```{julia}
function printuc(c, n)
for i in 0:n-1
@@ -149,14 +150,15 @@ function printuc(c, n)
end
```
__Kyrillisch__
__Cyrillic__
```{julia}
printuc('\U0400', 100)
```
__Tamilisch__
__Tamil__
:::{.cellmerge}
```{julia}
@@ -177,21 +179,21 @@ printuc('\U0be7',20)
:::
__Schach__
__Chess__
```{julia}
printuc('\U2654', 12)
```
__Mathematische Operatoren__
__Mathematical Operators__
```{julia}
printuc('\U2200', 255)
```
__Runen__
__Runes__
```{julia}
@@ -200,12 +202,11 @@ printuc('\U16a0', 40)
:::{.cellmerge}
__Scheibe (Diskus) von Phaistos__
- Diese Schrift ist nicht entziffert.
- Es ist unklar, welche Sprache dargestellt wird.
- Es gibt nur ein einziges Dokument in dieser Schrift: die Tonscheibe von Phaistos aus der Bronzezeit
__Phaistos Disc__
- This script is not deciphered.
- It is unclear what language is represented.
- There is only one single document in this script: the Phaistos Disc from the Bronze Age
```{julia}
@@ -226,54 +227,54 @@ printuc('\U101D0', 46 )
:::
### Unicode transformation formats: UTF-8, UTF-16, UTF-32
### Unicode Transformation Formats: UTF-8, UTF-16, UTF-32
_Unicode transformation formats_ legen fest, wie eine Folge von Codepoints als eine Folge von Bytes dargestellt wird.
_Unicode transformation formats_ define how a sequence of codepoints is represented as a sequence of bytes.
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?
Since the codepoints are of different lengths, they cannot simply be written down one after the other. Where does one end and the next begin?
- __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.
- Bei __UTF-16__ wird ein Codepoint entweder mit 2 Bytes oder mit 4 Bytes dargestellt.
- Bei __UTF-8__ wird ein Codepoint mit 1,2,3 oder 4 Bytes dargestellt.
- __UTF-8__ ist das Format mit der höchsten Verbreitung. Es wird auch von Julia verwendet.
- __UTF-32__: The simplest but also most memory-intensive is to make them all the same length. Each codepoint is encoded in 4 bytes = 32 bits.
- In __UTF-16__, a codepoint is represented either with 2 bytes or with 4 bytes.
- In __UTF-8__, a codepoint is represented with 1, 2, 3, or 4 bytes.
- __UTF-8__ is the format with the highest prevalence. Julia also uses it.
### UTF-8
- Für jeden Codepoint werden 1, 2, 3 oder 4 volle Bytes verwendet.
- For each codepoint, 1, 2, 3, or 4 full bytes are used.
- Bei einer Codierung mit variabler Länge muss man erkennen können, welche Bytefolgen zusammengehören:
- Ein Byte der Form 0xxxxxxx steht für einen ASCII-Codepoint der Länge 1.
- Ein Byte der Form 110xxxxx startet einen 2-Byte-Code.
- Ein Byte der Form 1110xxxx startet einen 3-Byte-Code.
- Ein Byte der Form 11110xxx startet einen 4-Byte-Code.
- Alle weiteren Bytes eines 2-,3- oder 4-Byte-Codes haben die Form 10xxxxxx.
- With variable-length encoding, one must be able to recognize which byte sequences belong together:
- A byte of the form 0xxxxxxx represents an ASCII codepoint of length 1.
- A byte of the form 110xxxxx starts a 2-byte code.
- A byte of the form 1110xxxx starts a 3-byte code.
- A byte of the form 11110xxx starts a 4-byte code.
- All further bytes of a 2-, 3-, or 4-byte code have the form 10xxxxxx.
- Damit ist der Platz, der für den Codepoint zur Verfügung steht (Anzahl der x):
- Ein-Byte-Code: 7 Bits
- Zwei-Byte-Code: 5 + 6 = 11 Bits
- Drei-Byte-Code: 4 + 6 + 6 = 16 Bits
- Vier-Byte-Code: 3 + 6 + 6 + 6 = 21 Bits
- Thus, the space available for the codepoint (number of x):
- One-byte code: 7 bits
- Two-byte code: 5 + 6 = 11 bits
- Three-byte code: 4 + 6 + 6 = 16 bits
- Four-byte code: 3 + 6 + 6 + 6 = 21 bits
- Damit ist jeder ASCII-Text automatisch auch ein korrekt codierter UTF-8-Text.
- Thus, every ASCII text is automatically also a correctly encoded UTF-8 text.
- 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.
## Zeichen und Zeichenketten in Julia
### Zeichen: `Char`
Der Datentyp `Char` kodiert ein einzelnes Unicode-Zeichen.
- Julia verwendet dafür einfache Anführungszeichen: `'a'`.
- Ein `Char` belegt 4 Bytes Speicher und
- repräsentiert einen Unicode-Codepoint.
- `Char`s können von/zu `UInt`s umgewandelt werden und
- der Integer-Wert ist gleich dem Unicode-codepoint.
- If the 17 planes (= 21 bits = 1.1 million possible characters) defined for Unicode so far are ever expanded, UTF-8 will be expanded to 5- and 6-byte codes.
`Char`s können von/zu `UInt`s umgewandelt werden.
## Characters and Character Strings in Julia
### Characters: `Char`
The `Char` type encodes a single Unicode character.
- Julia uses single quotes for this: `'a'`.
- A `Char` occupies 4 bytes of memory and
- represents a Unicode codepoint.
- `Char`s can be converted to/from `UInt`s and
- the integer value is equal to the Unicode codepoint.
`Char`s can be converted to/from `UInt`s.
```{julia}
UInt('a')
@@ -284,10 +285,10 @@ UInt('a')
b = Char(0x2656)
```
### Zeichenketten: `String`
### Character Strings: `String`
- Für Strings verwendet Julia doppelte Anführungszeichen: `"a"`.
- Sie sind UTF-8-codiert, d.h., ein Zeichen kann zwischen 1 und 4 Bytes lang sein.
- For strings, Julia uses double quotes: `"a"`.
- They are UTF-8 encoded, i.e., one character can be between 1 and 4 bytes long.
```{julia}
@@ -297,21 +298,21 @@ b = Char(0x2656)
__Bei einem Nicht-ASCII-String unterscheiden sich Anzahl der Bytes und Anzahl der Zeichen:__
__For a non-ASCII string, the number of bytes and the number of characters differ:__
```{julia}
asciistr = "Hello World!"
@show length(asciistr) ncodeunits(asciistr);
```
(Das Leerzeichen zählt natürlich auch.)
(The space, of course, also counts.)
```{julia}
str = "😄 Hellö 🎶"
@show length(str) ncodeunits(str);
```
__Iteration über einen String iteriert über die Zeichen:__
__Iterating over a string iterates over the characters:__
```{julia}
@@ -320,76 +321,76 @@ for i in str
end
```
### Verkettung von Strings
### Concatenation of Strings
"Strings mit Verkettung bilden ein nichtkommutatives Monoid."
"Strings with concatenation form a non-commutative monoid."
Deshalb wird in Julia die Verkettung multiplikativ geschrieben.
Therefore, Julia writes concatenation multiplicatively.
```{julia}
str * asciistr * str
```
Damit sind auch Potenzen mit natürlichem Exponenten definiert.
Powers with natural exponents are thus also defined.
```{julia}
str^3, str^0
```
### Stringinterpolation
### String Interpolation
Das Dollarzeichen hat in Strings eine Sonderfunktion, die wir schon oft in
`print()`-Anweisungen genutzt haben. MAn kann damit eine Variable oder einen Ausdruck interpolieren:
The dollar sign has a special function in strings, which we have often used in
`print()` statements. One can interpolate a variable or expression with it:
```{julia}
a = 33.4
b = "x"
s = "Das Ergebnis für $b ist gleich $a und die verdoppelte Wurzel daraus ist $(2sqrt(a))\n"
s = "The result for $b is equal to $a and the doubled square root of it is $(2sqrt(a))\n"
```
### Backslash escape sequences
### Backslash Escape Sequences
Der _backslash_ `\` hat in Stringkonstanten ebenfalls eine Sonderfunktion.
Julia benutzt die von C und anderen Sprachen bekannten _backslash_-Codierungen für Sonderzeichen und für Dollarzeichen und Backslash selbst:
The _backslash_ `\` also has a special function in string constants.
Julia uses the backslash codings known from C and other languages for special characters and for dollar signs and backslashes themselves:
```{julia}
s = "So bekommt man \'Anführungszeichen\" und ein \$-Zeichen und einen\nZeilenumbruch und ein \\ usw... "
s = "This is how one gets \'quotes\" and a \$ sign and a\nline break and a \\ etc... "
print(s)
```
### Triple-Quotes
### Triple Quotes
Man kann Strings auch mit Triple-Quotes begrenzen.
In dieser Form bleiben Zeilenumbrüche und Anführungszeichen erhalten:
Strings can also be delimited with triple quotes.
In this form, line breaks and quotes are preserved:
```{julia}
s = """
Das soll
ein "längerer"
'Text' sein.
This should
be a "longer"
'text'.
"""
print(s)
```
### Raw strings
### Raw Strings
In einem `raw string` sind alle backslash-Codierungen außer `\"` abgeschaltet:
In a `raw string`, all backslash codings except `\"` are disabled:
```{julia}
s = raw"Ein $ und ein \ und zwei \\ und ein 'bla'..."
s = raw"A $ and a \ and two \\ and a 'bla'..."
print(s)
```
## Weitere Funktionen für Zeichen und Strings (Auswahl)
## Further Functions for Characters and Strings (Selection)
### Tests für Zeichen
### Tests for Characters
```{julia}
@@ -397,9 +398,9 @@ print(s)
@show isnumeric('½') iscntrl('\n') ispunct(';');
```
### Anwendung auf Strings
### Application to Strings
Diese Tests lassen sich z.B. mit `all()`, `any()` oder `count()` auf Strings anwenden:
These tests can e.g. be used with `all()`, `any()`, or `count()` on strings:
```{julia}
@@ -408,7 +409,7 @@ all(ispunct, ";.:")
```{julia}
any(isdigit, "Es ist 3 Uhr! 🕒" )
any(isdigit, "It is 3 o'clock! 🕒" )
```
@@ -416,7 +417,7 @@ any(isdigit, "Es ist 3 Uhr! 🕒" )
count(islowercase, "Hello, du!!")
```
### Weitere String-Funktionen
### Other String Functions
```{julia}
@@ -438,50 +439,50 @@ count(islowercase, "Hello, du!!")
```{julia}
split("π ist irrational.")
split("π is irrational.")
```
```{julia}
replace("π ist irrational.", "ist" => "ist angeblich")
replace("π is irrational.", "is" => "is allegedly")
```
## Indizierung von Strings
## Indexing of Strings
Strings sind nicht mutierbar aber indizierbar. Dabei gibt es ein paar Besonderheiten.
Strings are immutable but indexable. There are a few special features here.
- Der Index nummeriert die Bytes des Strings.
- Bei einem nicht-ASCII-String sind nicht alle Indizes gültig, denn
- ein gültiger Index adressiert immer ein Unicode-Zeichen.
- The index numbers the bytes of the string.
- For a non-ASCII string, not all indices are valid, because
- a valid index always addresses a Unicode character.
Unser Beispielstring:
Our example string:
```{julia}
str
```
Das erste Zeichen
The first character
```{julia}
str[1]
```
Dieses Zeichen ist in UTF8-Kodierung 4 Bytes lang. Damit sind 2,3 und 4 ungültige Indizes.
This character is 4 bytes long in UTF-8 encoding. Thus, 2, 3, and 4 are invalid indices.
```{julia}
str[2]
```
Erst das 5. Byte ist ein neues Zeichen:
Only the 5th byte is a new character:
```{julia}
str[5]
```
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.
Even when addressing substrings, start and end must always be valid indices, i.e., the end index must also index the first byte of a character, and that character is the last of the substring.
```{julia}
str[1:7]
```
Die Funktion `eachindex()` liefert einen Iterator über die gültigen Indizes:
The function `eachindex()` returns an iterator over the valid indices:
```{julia}
for i in eachindex(str)
@@ -490,24 +491,24 @@ for i in eachindex(str)
end
```
Wie üblich macht collect() aus einem Iterator einen Vektor.
As usual, `collect()` makes an iterator into a vector.
```{julia}
collect(eachindex(str))
```
Die Funktion `nextind()` liefert den nächsten gültigen Index.
The function `nextind()` returns the next valid index.
```{julia}
@show nextind(str, 1) nextind(str, 2);
```
Warum verwendet Julia einen Byte-Index und keinen Zeichenindex? Der Hauptgrund dürfte die Effizienz der Indizierung sein.
Why does Julia use a byte index instead of a character index? The main reason is the efficiency of indexing.
- In einem langen String, z.B. einem Buchtext, ist die Stelle `s[123455]` mit einem Byte-Index schnell zu finden.
- 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.
- In a long string, e.g., a book text, the position `s[123455]` can be found quickly with a byte index.
- A character index would have to traverse the entire string in UTF-8 encoding to find the n-th character, since the characters can be 1, 2, 3, or 4 bytes long.
Einige Funktionen liefern Indizes oder Ranges als Resultat. Sie liefern immer gültige Indizes:
Some functions return indices or ranges as results. They always return valid indices:
```{julia}
@@ -529,9 +530,8 @@ str2 = "αβγδϵ"^3
n = findfirst('γ', str2)
```
So kann man ab dem nächsten nach `n=5` gültigen Index weitersuchen:
So one can continue searching from the next valid index after `n=5`:
```{julia}
findnext('γ', str2, nextind(str2, n))
```

View File

@@ -9,15 +9,15 @@ engine: julia
using InteractiveUtils
```
# Lineare Algebra in Julia
# Linear Algebra in Julia
```{julia}
using LinearAlgebra
```
Das `LinearAlgebra`-Paket liefert unter anderem:
The `LinearAlgebra` package provides among other things:
- zusätzliche Subtypen von `AbstractMatrix`: genauso verwendbar, wie andere Matrizen, z.B.
- additional subtypes of `AbstractMatrix`: usable like other matrices, e.g.,
- `Tridiagonal`
- `SymTridiagonal`
@@ -25,26 +25,26 @@ Das `LinearAlgebra`-Paket liefert unter anderem:
- `UpperTriangular`
- zusätzliche/erweiterte Funktionen: `norm`, `opnorm`, `cond`, `inv`, `det`, `exp`, `tr`, `dot`, `cross`, ...
- additional/extended functions: `norm`, `opnorm`, `cond`, `inv`, `det`, `exp`, `tr`, `dot`, `cross`, ...
- einen universellen Solver für lineare Gleichungssysteme: `\`
- `x = A \ b` löst $A \mathbf{x}=\mathbf{b}$ durch geeignete Matrixfaktorisierung und Vorwärts/Rückwärtssubstition
- a universal solver for systems of linear equations: `\`
- `x = A \ b` solves $A \mathbf{x}=\mathbf{b}$ by appropriate matrix factorization and forward/backward substitution
- [Matrixfaktorisierungen](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#man-linalg-factorizations)
- [Matrix factorizations](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#man-linalg-factorizations)
- `LU`
- `QR`
- `Cholesky`
- `SVD`
- ...
- Berechnung von Eigenwerte/-vektoren
- Computation of eigenvalues/eigenvectors
- `eigen`, `eigvals`, `eigvecs`
- Zugriff auf BLAS/LAPACK-Funktionen
- Access to BLAS/LAPACK functions
## Matrixtypen
## Matrix Types
@@ -57,31 +57,31 @@ A = SymTridiagonal(fill(1.0, 4), fill(-0.3, 3))
B = UpperTriangular(A)
```
Diese Typen werden platzsparend gespeichert. Die üblichen Rechenoperationen sind implementiert:
These types are stored space-efficiently. The usual arithmetic operations are implemented:
```{julia}
A + B
```
Lesende Indexzugriffe sind möglich,
Read-only index access is possible,
```{julia}
A[1,4]
```
schreibende nicht unbedingt:
write operations not necessarily:
```{julia}
#| error: true
A[1,3] = 17
```
Die Umwandlung in eine 'normale' Matrix ist z.B. mit `collect()` möglich:
Conversion to a 'normal' matrix is possible, for example, with `collect()`:
```{julia}
A2 = collect(A)
```
### Die Einheitsmatrix `I`
### The Identity Matrix `I`
`I` bezeichnet eine Einheitsmatrix (quadratisch, Diagonalelemente = 1, alle anderen = 0) in der jeweils erforderlichen Größe
`I` denotes an identity matrix (square, diagonal elements = 1, all others = 0) of the respective required size
```{julia}
@@ -89,39 +89,39 @@ A + 4I
```
## Normen
## Norms
Um Fragen wie Kondition oder Konvergenz eines Algorithmus studieren zu können, brauchen wir eine Metrik. Für lineare Räume ist es zweckmäßig, die Metrik über eine Norm zu definieren:
To be able to study questions such as conditioning or convergence of an algorithm, we need a metric. For linear spaces, it is appropriate to define the metric via a norm:
$$
d(x,y) := ||x-y||
$$
### $p$-Normen
### $p$-Norms
Eine einfache Klasse von Normen im $^n$ sind die $p$-Normen
A simple class of norms in $^n$ are the $p$-norms
$$
||\mathbf{x}||_p = \left(\sum |x_i|^p\right)^\frac{1}{p},
$$
die die die euklidische Norm $p=2$ verallgemeinern.
which generalize the Euclidean norm $p=2$.
:::{.callout-note}
## Die Max-Norm $p=\infty$
## The Max-Norm $p=\infty$
Sei $x_{\text{max}}$ die _betragsmäßig_ größte Komponente von $\mathbf{x}\in ^n$. Dann gilt stets
Let $x_{\text{max}}$ be the _largest in absolute value_ component of $\mathbf{x}\in ^n$. Then always
$$ |x_{\text{max}}| \le ||\mathbf{x}||_p \le n^\frac{1}{p} |x_{\text{max}}|
$$
(Man betrachte einen Vektor, dessen Komponenten alle gleich $x_{\text{max}}$ sind bzw. einen Vektor, dessen Komponenten außer $x_{\text{max}}$ alle gleich Null sind.)
(Consider a vector whose components are all equal to $x_{\text{max}}$ respectively a vector whose components are all equal to zero except $x_{\text{max}}$.)
Damit folgt
Thus follows
$$
\lim_{p \rightarrow \infty} ||\mathbf{x}||_p = |x_{\text{max}}| =: ||\mathbf{x}||_\infty.
$$
:::
In Julia definiert das `LinearAlgebra`-Paket eine Funktion `norm(v, p)`.
In Julia, the `LinearAlgebra` package defines a function `norm(v, p)`.
```{julia}
v = [3, 4]
@@ -130,10 +130,10 @@ w = [-1, 2, 33.2]
@show norm(v) norm(v, 2) norm(v, 1) norm(v, 4) norm(w, Inf);
```
- Wenn das 2. Argument `p` fehlt, wird `p=2` gesetzt.
- Das 2. Argument kann auch `Inf` (also $+\infty$) sein.
- Das 1. Argument kann ein beliebiger Container voller Zahlen sein. Die Summe $\sum |x_i|^p$ erstreckt sich über *alle* Elemente des Containers.
- Damit ist für eine Matrix `norm(A)` gleich der _Frobenius-Norm_ der Matrix `A`.
- If the 2nd argument `p` is missing, `p=2` is set.
- The 2nd argument can also be `Inf` (i.e., $+\infty$).
- The 1st argument can be any container full of numbers. The sum $\sum |x_i|^p$ extends over *all* elements of the container.
- Thus, for a matrix `norm(A)` is equal to the _Frobenius norm_ of the matrix `A`.
```{julia}
A = [1 2 3
@@ -144,12 +144,12 @@ norm(A) # Frobenius norm
Da Normen homogen unter Multiplikation mit Skalaren sind,
$||\lambda \mathbf{x}|| = |\lambda|\cdot||\mathbf{x}||$, sind sie durch die Angabe der Einheitskugel vollständig bestimmt. Subadditivität der Norm (Dreiecksungleichung) ist äquivalent zur Konvexität der Einheitskugel
(Code durch anklicken sichtbar).
Since norms are homogeneous under multiplication with scalars,
$||\lambda \mathbf{x}|| = |\lambda|\cdot||\mathbf{x}||$, they are completely determined by the specification of the unit ball. Subadditivity of the norm (triangle inequality) is equivalent to the convexity of the unit ball
(code visible by clicking).
```{julia}
#| code-fold: true
#| fig-cap: "Einheitskugeln im $^2$ für verschiedene $p$-Normen: $p$=0.8; 1; 1.5; 2; 3.001 und 1000"
#| fig-cap: "Unit balls in $^2$ for different $p$-norms: $p$=0.8; 1; 1.5; 2; 3.001 and 1000"
using Plots
colors=[:purple, :green, :red, :blue,:aqua, :black]
@@ -163,35 +163,35 @@ for p ∈ (0.8, 1, 1.5, 2, 3.001, 1000)
end
fig1
```
Wie man sieht, muß $p\ge 1$ sein, damit die Einheitskugel konvex und $||.||_p$ eine Norm ist.
As one can see, $p\ge 1$ must hold so that the unit ball is convex and $||.||_p$ is a norm.
Die Julia-Funktion `norm(v, p)` liefert allerdings für beliebige Parameter `p` ein Ergebnis.
However, the Julia function `norm(v, p)` returns a result for arbitrary parameters `p`.
### Induzierte Normen (Operatornormen)
### Induced Norms (Operator Norms)
Matrizen $A$ repräsentieren lineare Abbildungen $\mathbf{v}\mapsto A\mathbf{v}$. Die von einer Vektornorm Induzierte Matrixnorm beantwortet die Frage:
Matrices $A$ represent linear mappings $\mathbf{v}\mapsto A\mathbf{v}$. The matrix norm induced by a vector norm answers the question:
> _„Um welchen Faktor kann ein Vektor durch die Transformation $A$ maximal gestreckt werden?“_
> _"By what factor can a vector be maximally stretched by the transformation $A$?"_
Auf Grund der Homogenität der Norm unter Multiplikation mit Skalaren reicht es aus, das Bild der Einheitskugel unter der Transformation $A$ zu betrachten.
Due to the homogeneity of the norm under multiplication with scalars, it is sufficient to consider the image of the unit ball under the transformation $A$.
::: {.callout-tip}
## Definition
Sei $V$ ein Vektorraum mit einer Dimension $0<n<\infty$ und
$A$ eine $n\times n$-Matrix. Dann ist
Let $V$ be a vector space with dimension $0<n<\infty$ and
$A$ an $n\times n$-matrix. Then
$$
||A||_p = \max_{||\mathbf{v}||_p=1} ||A\mathbf{v}||_p
$$
:::
Induzierte Normen lassen sich für allgemeines $p$ nur schwer berechnen. Ausnahmen sind die Fälle
Induced norms can only be calculated with difficulty for general $p$. Exceptions are the cases
- $p=1$: Spaltensummennorm
- $p=2$: Spektralnorm und
- $p=\infty$: Zeilensummennorm
- $p=1$: column sum norm
- $p=2$: spectral norm and
- $p=\infty$: row sum norm
Diese 3 Fälle sind in Julia in der Funktion `opnorm(A, p)` aus dem `LinearAlgebra`-Paket implementiert, wobei wieder `opnorm(A) = opnorm(A, 2)` gilt.
These 3 cases are implemented in Julia in the function `opnorm(A, p)` from the `LinearAlgebra` package, where again `opnorm(A) = opnorm(A, 2)` holds.
```{julia}
A = [ 0 1
@@ -200,7 +200,7 @@ A = [ 0 1
@show opnorm(A, 1) opnorm(A, Inf) opnorm(A, 2) opnorm(A);
```
Das folgende Bild zeigt die Wirkung von $A$ auf Einheitsvektoren. Vektoren gleicher Farbe werden aufeinander abgebildet. (Code durch anklicken sichtbar):
The following picture shows the effect of $A$ on unit vectors. Vectors of the same color are mapped onto each other. (Code visible by clicking):
```{julia}
#| error: false
@@ -214,12 +214,12 @@ CairoMakie.activate!(type = "svg")
```{julia}
#| code-fold: true
#| fig-cap: "Bild der Einheitskugel unter $v \\mapsto Av$ mit $||A||\\approx 2.088$"
#| fig-cap: "Image of the unit ball under $v \\mapsto Av$ with $||A||\\approx 2.088$"
using CairoMakie
# Makie bug https://github.com/MakieOrg/Makie.jl/issues/3255
# Würgaround https://github.com/MakieOrg/Makie.jl/issues/2607#issuecomment-1385816645
# Workaround https://github.com/MakieOrg/Makie.jl/issues/2607#issuecomment-1385816645
tri = BezierPath([
MoveTo(Point2f(-0.5, -1)), LineTo(0, 0), LineTo(0.5, -1), ClosePath()
])
@@ -253,9 +253,9 @@ arrows!(fig2[1,3], x, y, Auv[1], Auv[2], arrowsize=10, arrowhead=tri, colormap=:
fig2
```
### Konditionszahl
### Condition Number
Für p = 1, p = 2 (default) oder p = Inf liefert `cond(A,p)` die Konditionszahl in der $p$-Norm
For p = 1, p = 2 (default) or p = Inf, `cond(A,p)` returns the condition number in the $p$-norm
$$
\text{cond}_p(A) = ||A||_p \cdot ||A^{-1}||_p
$$
@@ -264,37 +264,37 @@ $$
@show cond(A, 1) cond(A, 2) cond(A) cond(A, Inf);
```
## Matrixfaktorisierungen
## Matrix Factorizations
Basisaufgaben der numerischen linearen Algebra:
Basic tasks of numerical linear algebra:
- Löse ein lineares Gleichungssystem $A\mathbf{x} = \mathbf{b}$.
- Falls keine Lösung existiert, finde die beste Annäherung, d.h., den Vektor $\mathbf{x}$, der $||A\mathbf{x} - \mathbf{b}||$ minimiert.
- Finde Eigenwerte und Eigenvektoren $A\mathbf{x} = \lambda \mathbf{x}$ von $A$.
- Solve a system of linear equations $A\mathbf{x} = \mathbf{b}$.
- If no solution exists, find the best approximation, i.e., the vector $\mathbf{x}$ that minimizes $||A\mathbf{x} - \mathbf{b}||$.
- Find eigenvalues and eigenvectors $A\mathbf{x} = \lambda \mathbf{x}$ of $A$.
Diese Aufgaben sind mit Matrixfaktorisierungen lösbar. Einige grundlegende Matrixfaktorisierungen:
These tasks can be solved using matrix factorizations. Some fundamental matrix factorizations:
- **LU-Zerlegung** $A=L\cdot U$
- faktorisiert eine Matrix als Produkt einer _lower_ und einer _upper_ Dreiecksmatrix
- im Deutschen auch LR-Zerlegung (aber die Julia-Funktion heisst `lu()`)
- geht (eventuell nach Zeilenvertauschung - Pivoting) immer
- **Cholesky-Zerlegung** $A=L\cdot L^*$
- die obere Dreiecksmatrix ist die konjugierte der unteren,
- halber Aufwand im Vergleich zu LU
- geht nur, wenn $A$ hermitesch und positiv definit ist
- **QR-Zerlegung** $A=Q\cdot R$
- zerlegt $A$ als Produkt einer orthogonalen (bzw. unitären im komplexen Fall) Matrix und einer oberen Dreiecksmatrix
- $Q$ ist längenerhaltend (Drehungen und/oder Spiegelungen); die Stauchungen/Streckungen werden durch $R$ beschrieben
- geht immer
- **LU decomposition** $A=L\cdot U$
- factorizes a matrix as a product of a _lower_ and an _upper_ triangular matrix
- in German also called LR decomposition (but the Julia function is called `lu()`)
- always works (possibly after row exchanges - pivoting)
- **Cholesky decomposition** $A=L\cdot L^*$
- the upper triangular matrix is the conjugate of the lower,
- half the effort compared to LU
- only works if $A$ is Hermitian and positive definite
- **QR decomposition** $A=Q\cdot R$
- decomposes $A$ as a product of an orthogonal (or unitary in the complex case) matrix and an upper triangular matrix
- $Q$ is length-preserving (rotations and/or reflections); the scalings are described by $R$
- always works
- **SVD** _(Singular value decomposition)_: $A = U\cdot D \cdot V^*$
- $U$ und $V$ sind orthogonal (bzw. unitär), $D$ ist eine Diagonalmatrix mit Einträgen in der Diagonale $σ_i\ge 0$, den sogenannten _Singulärwerten_ von $A$.
- Jede lineare Transformation $\mathbf{v} \mapsto A\mathbf{v}$ läßt sich somit darstellen als eine Drehung (und/oder Spiegelung) $V^*$, gefolgt von einer reinen Skalierung $v_i \mapsto \sigma_i v_i$ und einer weitere Drehung $U$.
- $U$ and $V$ are orthogonal (or unitary), $D$ is a diagonal matrix with entries on the diagonal $σ_i\ge 0$, the so-called _singular values_ of $A$.
- Every linear transformation $\mathbf{v} \mapsto A\mathbf{v}$ can thus be represented as a rotation (and/or reflection) $V^*$, followed by a pure scaling $v_i \mapsto \sigma_i v_i$ and another rotation $U$.
### LU-Faktorisierung
### LU Factorization
LU-Faktorisierung ist Gauß-Elimination. Das Resultat der Gauß-Elimination ist die obere Dreiecksmatrix $U$. Die untere Dreiecksmatrix $L$ enthält Einsen auf der Diagonale und die nichtdiagonalen Einträge $l_{ij}$ sind gleich minus den Koeffizienten, mit denen im Gauß-Algorithmus Zeile $Z_j$ multipliziert und zu Zeile $Z_i$ addiert wird.
Ein Beispiel:
LU factorization is Gaussian elimination. The result of Gaussian elimination is the upper triangular matrix $U$. The lower triangular matrix $L$ contains ones on the diagonal and the non-diagonal entries $l_{ij}$ are equal to minus the coefficients by which row $Z_j$ is multiplied and added to row $Z_i$ in the Gaussian algorithm.
An example:
$$
A=\left[
\begin{array}{ccc}
@@ -303,10 +303,10 @@ A=\left[
-2 & 1 & 5
\end{array}\right]
~ \begin{array}{c}
~\\
Z_2 \mapsto Z_2 \mathbin{\color{red}-}\textcolor{red}{3} Z_1\\
Z_3 \mapsto Z_3 + \textcolor{red}{2} Z_1
\end{array} \quad \Longrightarrow\
~\\
Z_2 \mapsto Z_2 \mathbin{\color{red}-}\textcolor{red}{3} Z_1\\
Z_3 \mapsto Z_3 + \textcolor{red}{2} Z_1
\end{array} \quad \Longrightarrow\
\left[
\begin{array}{ccc}
1 &2 &2 \\
@@ -314,10 +314,10 @@ A=\left[
& 5 & 9
\end{array}\right]
~ \begin{array}{c}
~\\
~\\
Z_3 \mapsto Z_3 + \textcolor{red}{\frac{1}{2}} Z_2
\end{array} \quad \Longrightarrow\
~\\
~\\
Z_3 \mapsto Z_3 + \textcolor{red}{\frac{1}{2}} Z_2
\end{array} \quad \Longrightarrow\
\left[
\begin{array}{ccc}
1 &2 &2 \\
@@ -342,11 +342,11 @@ A = \left[
$$
- Häufig in der Praxis: $A\mathbf{x}=\mathbf{b}$ muss für ein $A$ und viele rechte Seiten $\mathbf{b}$ gelöst werden.
- Die Faktorisierung, deren Aufwand kubisch $\sim n^3$ mit der Matrixgröße $n$ wächst, muss nur einmal gemacht werden.
- Der anschliessende Aufwand der Vorwärts/Rückwärtssubstition für jedes $\mathbf{b}$ ist nur noch quadratisch $\sim n^2$.
- Often in practice: $A\mathbf{x}=\mathbf{b}$ must be solved for one $A$ and many right-hand sides $\mathbf{b}$.
- The factorization, whose effort grows cubically $\sim n^3$ with the matrix size $n$, only needs to be done once.
- The subsequent effort of forward/backward substitution for each $\mathbf{b}$ is only quadratically $\sim n^2$.
Das `LinearAlgebra`-Paket von Julia enthält zur Berechnung einer LU-Zerlegung die Funktion `lu(A, options)`:
The `LinearAlgebra` package of Julia contains the function `lu(A, options)` for calculating an LU decomposition:
```{julia}
A = [ 1 2 2
3 -4 4
@@ -361,7 +361,7 @@ display(U)
#### Pivoting
Sehen wir uns einen Schritt der Gauß-Elimination an:
Let's look at one step of Gaussian elimination:
$$
\left[
\begin{array}{cccccc}
@@ -375,37 +375,34 @@ $$
\end{array}
\right]
$$
Ziel ist es, als nächstes den Eintrag $a_{i+1,j}$ zum Verschwinden zu bringen, indem zur Zeile $Z_{i+1}$ ein geeignetes Vielfaches von Zeile $Z_i$ addiert wird. Das geht nur, wenn das _Pivotelement_ $\textcolor{red}{a_{ij}}$ nicht Null ist. Falls $\textcolor{red}{a_{ij}}=0$, müssen wir Zeilen vertauschen um dies zu beheben.
The goal is to make the entry $a_{i+1,j}$ disappear by adding an appropriate multiple of row $Z_i$ to row $Z_{i+1}$. This only works if the _pivot element_ $\textcolor{red}{a_{ij}}$ is not zero. If $\textcolor{red}{a_{ij}}=0$, we must exchange rows to fix this.
Darüber hinaus ist die Kondition des Algorithmus am besten, wenn man bei jedem Schritt die Matrix so anordnet, dass das Pivotelement das betragsmäßig größte
in der entsprechenden Spalte der noch zu bearbeitenden Umtermatrix ist. Beim (Zeilen-)Pivoting wird bei jedem Schritt durch Zeilenvertauschung sichergestellt, dass
gilt:
Furthermore, the conditioning of the algorithm is best if we arrange the matrix at each step so that the pivot element is the largest in absolute value in the corresponding column of the remaining submatrix. In (row) pivoting, rows are exchanged at each step to ensure that
$$
|\textcolor{red}{a_{ij}}|=\max_{k=i,...,m} |\textcolor{blue}{a_{kj}}|
$$
#### LU in Julia
- Die Faktorisierungen in Julia geben ein spezielles Objekt zurück, das die Matrixfaktoren und weitere
Informationen enthält.
- Die Julia-Funktion `lu(A)` führt eine LU-Faktorisierung mit Pivoting durch.
- The factorizations in Julia return a special object that contains the matrix factors and additional information.
- The Julia function `lu(A)` performs an LU factorization with pivoting.
```{julia}
F = lu(A)
typeof(F)
```
Elemente des Objekts:
Elements of the object:
```{julia}
@show F.L F.U F.p;
```
Man kann auch gleich auf der linken Seite ein entsprechendes Tupel verwenden:
One can also use an appropriate tuple on the left side:
```{julia}
L, U, p = lu(A);
p
```
Der Permutationsvektor zeigt an, wie die Zeilen der Matrix permutiert wurden. Es gilt: $$ L\cdot U = PA$$. Die Syntax der indirekten Indizierung erlaubt es, die Zeilenpermutation durch die Schreibweise `A[p,:]` anzuwenden:
The permutation vector indicates how the rows of the matrix have been permuted. It holds: $$ L\cdot U = PA$$. The syntax of indirect indexing allows applying the row permutation with the notation `A[p,:]`:
```{julia}
display(A)
display(A[p,:])
@@ -413,28 +410,28 @@ display(L*U)
```
Die Vorwärts/Rückwärtssubstition mit einem `LU`- erledigt der Operator `\`:
Forward/backward substitution with an `LU`-object is performed by the `\` operator:
```{julia}
b = [1, 2, 3]
x = F \ b
```
Probe:
Verification:
```{julia}
A * x - b
```
In Julia verbirgt sich hinter dem `\`-Operator ein ziemlich universeller "matrix solver" und man kann ihn auch direkt anwenden:
In Julia, the `\` operator hides a quite universal "matrix solver", and it can also be applied directly:
```{julia}
A \ b
```
Dabei wird implizit eine geeignete Faktorisierung durchgeführt, deren Ergebnis allerdings nicht abgespeichert.
An appropriate factorization is performed implicitly, but its result is not saved.
### QR-Zerlegung
### QR Decomposition
Die Funktion `qr()` liefert ein epezielles QR-Objekt zurück, das die Komponenten $Q$ und $R$ enthält. Die orthogonale (bzw. unitäre) Matrix $Q$ ist
[in einer optimierten Form](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#man-linalg-abstractq) abgespeichert. Umwandlung in eine "normale" Matrix ist bei Bedarf wie immer mit `collect()` möglich.
The function `qr()` returns a special QR object that contains the components $Q$ and $R$. The orthogonal (or unitary) matrix $Q$ is
[in an optimized form](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#man-linalg-abstractq) stored. Conversion to a "normal" matrix is, as always, possible with `collect()` if needed.
```{julia}
F = qr(A)
@show typeof(F) typeof(F.Q)
@@ -442,11 +439,11 @@ display(collect(F.Q))
display(F.R)
```
### Passende Faktorisierung
### Appropriate Factorization
Die Funktion `factorize()` liefert eine dem Matrixtyp angepasste Form der Faktorisierung, siehe [Dokumentation](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#LinearAlgebra.factorize) für Details.
Wenn man Lösungen zu mehreren rechten Seiten $\mathbf{b_1}, \mathbf{b_2},...$ benötigt, sollte man die Faktorisierung nur einmal durchführen:
The function `factorize()` returns a factorization form adapted to the matrix type, see [documentation](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#LinearAlgebra.factorize) for details.
If solutions for several right-hand sides $\mathbf{b_1}, \mathbf{b_2},...$ are needed, the factorization should only be performed once:
```{julia}
@@ -462,4 +459,3 @@ Af \ [1, 2, 3]
```{julia}
Af \ [5, 7, 9]
```

View File

@@ -2,7 +2,23 @@
engine: julia
---
# Ein- und Ausgabe
```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
import QuartoNotebookWorker
Base.stdout = QuartoNotebookWorker.with_context(stdout)
```
```{julia}
#| error: false
#| echo: false
#| output: false
flush(stdout)
```
# Input and Output
```{julia}
@@ -22,51 +38,50 @@ Base.active_module() = myactive_module()
```
## Konsole
## Console
Das Betriebssystem stellt für ein Programm üblicherweise 3 Kanäle _(streams)_ zur Verfügung:
The operating system normally provides 3 channels (_streams_) for a program:
- Standardeingabekanal `stdin`
- Standardausgabekanal `stdout` und
- Standardfehlerausgabekanal `stderr`.
- Standard input channel `stdin`
- Standard output channel `stdout` and
- Standard error output channel `stderr`.
Wenn das Programm in einem Terminal (oder Konsole bzw. Shell) gestartet wird, kann das Programm über `stdin` die Tastatureingaben
einlesen und Ausgaben über `stdout` sowie `stdout` erscheinen im Terminal.
When the program is started in a terminal (or console or shell), the program can read keyboard input via `stdin` and output appears in the terminal via `stdout` and `stdout`.
- Schreiben nach `stdout`: `print()`,`println()`,`printstyled()`
- Schreiben nach `stderr`: `print(strerr,...)`, `println(stderr,...)`, `printstyled(stderr,...)`
- Lesen von `stdin`: `readline()`
- Writing to `stdout`: `print()`,`println()`,`printstyled()`
- Writing to `stderr`: `print(strerr,...)`, `println(stderr,...)`, `printstyled(stderr,...)`
- Reading from `stdin`: `readline()`
### Eingaben
### Input
Die Sprache _Python_ stellt eine Funktion `input()` zur Verfügung:
The language _Python_ provides a function `input()`:
```{.python}
ans = input("Bitte eine positive Zahl eingeben!")
ans = input("Please enter a positive number!")
```
Die Funktion gibt den Prompt aus, wartet auf eine Eingabe und liefert die
Eingabe als `string` zurück.
The function prints the prompt, waits for input, and returns the
input as a `string`.
In Julia kann man diese Funktion so implementieren:
In Julia, you can implement this function as follows:
```{julia}
function input(prompt = "Eingabe:")
function input(prompt = "Input:")
println(prompt)
flush(stdout)
return chomp(readline())
end
```
**Anmerkungen**
**Comments**
- Schreibanweisungen werden von modernen Betriebssystemen gebuffert. Mit `flush(stdout)` wird die Leerung des Buffers und sofortige Schreiboperation erzwungen.
- `readline()` liefert einen String zurück, der mit einer Newline `\n` endet. Die Funktion `chomp()` entfernt einen eventuellen Zeilenumbruch vom Ende eines Strings.
- Write instructions are buffered by modern operating systems. With `flush(stdout)`, the buffer is emptied and the write operation is forced to complete immediately.
- `readline()` returns a string ending with a newline `\n`. The function `chomp()` removes a possible line break from the end of a string.
```{julia}
#| eval: false
a = input("Bitte 2 Zahlen eingeben!")
a = input("Please enter 2 numbers!")
```
```{julia}
#| echo: false
@@ -74,32 +89,33 @@ a = "34 56"
```
### Verarbeitung der Eingabe
### Processing the Input
> `split(str)` zerlegt einen String in "Wörter" und liefert einen _(array of strings)_:
> `split(str)` splits a string into "words" and returns an _(array of strings)_:
```{julia}
av = split(a)
```
> `parse(T, str)` versucht, `str` in den Typ `T` umzuwandeln:
> `parse(T, str)` tries to convert `str` to type `T`:
```{julia}
v = parse.(Int, av)
```
`parse()` erzeugt einen Fehler, wenn der String sich nicht als Wertangabe von Typ `T` parsen lässt. Man kann den Fehler mit
`try/catch` abfangen oder die Funktion `tryparse(T, str)` verwenden, die in so einem Fall `nothing` zurückgibt - worauf man dann
z.B. mit `isnothing()` testen kann.
`parse()` generates an error if the string cannot be parsed as a value of type `T`. You can catch the error with
`try/catch` or use the function `tryparse(T, str)`, which returns `nothing` in such a case - on which you can then
e.g. test with `isnothing()`.
### Einzelne Tastenanschläge einlesen
- `readline()` u.ä. warten auf den Abschluss der Eingabe durch Drücken der `Enter`-Taste.
- Techniken zum Einlesen einzelner _keystrokes_ findet man hier:
### Reading Individual Keystrokes
- `readline()` and similar functions wait for the input to be completed by pressing the `Enter` key.
- Techniques for reading individual _keystrokes_ can be found here:
- [https://stackoverflow.com/questions/56888266/how-to-read-keyboard-inputs-at-every-keystroke-in-julia](https://stackoverflow.com/questions/56888266/how-to-read-keyboard-inputs-at-every-keystroke-in-julia)
- [https://stackoverflow.com/questions/60954235/how-can-i-test-whether-stdin-has-input-available-in-julia](https://stackoverflow.com/questions/60954235/how-can-i-test-whether-stdin-has-input-available-in-julia)
@@ -107,30 +123,30 @@ z.B. mit `isnothing()` testen kann.
## Formatierte Ausgabe mit dem `Printf`-Makro
## Formatted Output with the `Printf` Macro
Oft möchte man Zahlen oder Strings mit einer strikten Formatvorgabe - Gesamtlänge, Nachkommastellen, rechts/linksbündig usw - ausgeben.
Often you want to output numbers or strings with a strict format specification - total length, decimal places, right/left-aligned, etc.
Dazu definiert das Paket `Printf` die Makros `@sprintf` und `@printf`, welche sehr ähnlich wie die gleichnamigen C-Funktionen arbeiten.
To this end, the `Printf` package defines the macros `@sprintf` and `@printf`, which work very similarly to the corresponding C functions.
```{julia}
using Printf
x = 123.7876355638734
@printf("Ausgabe rechtsbündig mit max. 10 Zeichen Platz und 3 Nachkommastellen: x= %10.3f", x)
@printf("Output right-aligned with max. 10 character width and 3 decimal places: x= %10.3f", x)
```
Das erste Argument ist ein String, der Platzhalter (hier: `%10.3`) für auszugebende Variablen enthält; gefolgt von diesen Variablen als weitere Argumente.
The first argument is a string containing placeholders (here: `%10.3`) for variables to be output; followed by these variables as further arguments.
Platzhalter haben die Form
Placeholders have the form
```
%[flags][width][.precision]type
```
wobei die Angaben in eckigen Klammern alle optional sind.
where the entries in square brackets are all optional.
**Typangaben im Platzhalter**
**Type specifications in placeholders**
| | |
|:--|:------------|
@@ -149,9 +165,9 @@ wobei die Angaben in eckigen Klammern alle optional sind.
| | |
|:----|:-----|
|Pluszeichen| rechtsbündig (Standard)|
|Minuszeichen| linksbündig|
|Null| mit führenden Nullen|
|Plus sign| right-aligned (default)|
|Minus sign| left-aligned|
|Zero| with leading zeros|
: {.striped .hover}
@@ -159,37 +175,37 @@ wobei die Angaben in eckigen Klammern alle optional sind.
**Width**
```
Anzahl der minimal verwendeten Zeichen (wenn nötig, werden auch mehr genommen)
Number of minimum characters used (more will be taken if necessary)
```
### Beispiele:
### Examples:
```{julia}
using Printf # Paket laden nicht vergessen!
using Printf # Don't forget to load the package!
```
```{julia}
@printf("|%s|", "Hallo") # string mit Platzhalter für String
@printf("|%s|", "Hello") # string with placeholder for string
```
Die senkrechten Striche sind nicht Teil des Platzhalters. Sie sollen die Begrenzung des Ausgabefeldes anzeigen.
The vertical bars are not part of the placeholder. They are intended to indicate the boundaries of the output field.
```{julia}
@printf("|%10s|", "Hallo") # Minimallänge, rechtsbündig
@printf("|%10s|", "Hello") # Minimum length, right-aligned
```
```{julia}
@printf("|%-10s|", "Hallo") # linksbündig
@printf("|%-10s|", "Hello") # left-aligned
```
```{julia}
@printf("|%3s|", "Hallo") # Längenangabe kann überschritten werden
# besser eine 'kaputt formatierte' Tabelle als falsche Werte!
@printf("|%3s|", "Hello") # Length specification can be exceeded
# Better a 'badly formatted' table than incorrect values!
```
@@ -198,37 +214,36 @@ j = 123
k = 90019001
l = 3342678
@printf("j= %012i, k= %-12i, l = %12i", j, k, l) # 0-Flag für führende Nullen
@printf("j= %012i, k= %-12i, l = %12i", j, k, l) # 0-flag for leading zeros
```
`@printf` und `@sprintf` können wie alle Makros wie Funktionen aufgerufen werden:
`@printf` and `@sprintf` can be called like functions or as macros:
```{julia}
@printf("%i %i", 22, j)
```
-- oder wie Makros, also ohne Funktionsklammern und ohne Komma:
-- or as macros, i.e., without function parentheses and without comma:
```{julia}
@printf "%i %i" 22 j
```
`@printf` kann als erstes Argument noch einen Stream übergeben bekommen.
`@printf` can take a stream as its first argument.
Ansonsten besteht die Argumentliste aus
Otherwise, the argument list consists of
- Formatstring mit Platzhaltern
- Variablen in der Reihenfolge der Platzhalter, in Anzahl und Typ zu den Platzhaltern passend
- format string with placeholders
- variables in the order of the placeholders, matching in number and type to the placeholders
```{julia}
@printf(stderr, "Erstes Resultat: %i %s\nZweites Resultat %i",
j, "(geschätzt)" ,k)
@printf(stderr, "First result: %i %s\nSecond result %i",
j, "(estimated)" ,k)
```
Das Makro `@sprintf` druckt nichts, sondern liefert den ausgefüllten formatierten String zurück:
The macro `@sprintf` does not print anything but returns the filled formatted string:
```{julia}
@@ -240,52 +255,52 @@ str = @sprintf("x = %10.6f", π );
str
```
### Formatierung der Gleitkommazahlen:
### Formatting Floating Point Numbers:
Bedeutung des _Precision_-Wertes:
Meaning of the _precision_ value:
- `%f` und `%e`-Format: maximale Anzahl der Nachkommastellen
- `%g`-Format: maximale Anzahl von ausgegebenen Ziffern (Vor- + Nachkommastellen)
- `%f` and `%e` format: maximum number of decimal places
- `%g` format: maximum number of digits output (integer + decimal places)
```{julia}
x = 123456.7890123456
@printf("%20.4f %20.4e", x, x) # 4 Nachkommastellen
@printf("%20.4f %20.4e", x, x) # 4 decimal places
```
```{julia}
@printf("%20.7f %20.7e", x, x) # 7 Nachkommastellen
@printf("%20.7f %20.7e", x, x) # 7 decimal places
```
```{julia}
@printf("%20.7g %20.4g", x, x) # insgesamt 7 bzw. 4 Stellen
@printf("%20.7g %20.4g", x, x) # total 7 and 4 digits respectively
```
## Dateioperationen
## File Operations
Dateien werden
Files are
- geöffnet $\Longrightarrow$ dabei ensteht ein neues _stream_-Objekt (zusätzlich zu `stdin, stdout, stderr`)
- dann kann dieser _stream_ gelesen und geschrieben werden
- geschlossen $\Longrightarrow$ _stream_-Objekt wird von Datei getrennt
```{.julia}
stream = open(path, mode)
```
- path: Dateiname/pfad
- mode:
- opened $\Longrightarrow$ a new _stream_-object is created (in addition to `stdin, stdout, stderr`)
- then this _stream_ can be read from and written to
- closed $\Longrightarrow$ _stream_-object is detached from file
```{.julia}
stream = open(path, mode)
```
- path: filename/path
- mode:
```
"r" read, öffnet am Dateianfang
"w" write, öffnet am Dateianfang (Datei wird neu angelegt oder überschrieben)
"a" append, öffnet zum Weiterschreiben am Dateiende
```
```
"r" read, opens at file beginning
"w" write, opens at file beginning (file is created or overwritten)
"a" append, opens to continue writing at file end
```
Schreiben wir mal eine Datei:
Let's write a file:
```{julia}
file = open("datei.txt", "w")
@@ -298,7 +313,7 @@ file = open("datei.txt", "w")
```{julia}
println(file, " zweite Zeile")
println(file, " second line")
```
@@ -306,59 +321,58 @@ println(file, " zweite Zeile")
close(file)
```
Schauen wir uns die Datei an:
Let's look at the file:
```{julia}
;cat datei.txt
```
...und jetzt öffnen wir sie wieder zum Einlesen:
...and now we open it again for reading:
```{julia}
stream = open("datei.txt", "r")
```
`readlines(stream)` liefert alle Zeilen einer Textdatei als Vector von Strings.
`readlines(stream)` returns all lines of a text file as a vector of strings.
`eachline(stream)` liefert einen Iterator über die Zeilen der Datei.
`eachline(stream)` returns an iterator over the lines of the file.
```{julia}
n = 0
for line in eachline(stream) # Lese zeilenweise
for line in eachline(stream) # Read line by line
n += 1
println(n, line) # Drucke mit Zeilennummer
println(n, line) # Print with line number
end
close(stream)
```
## Pakete für Dateiformate
## Packages for File Formats
Für die Ein- und Ausgabe in den verschiedensten Dateiformaten existieren Julia-Pakete, z.B.
For input and output in various file formats, there are Julia packages, e.g.,
- [PrettyTables.jl](https://ronisbr.github.io/PrettyTables.jl/stable/) Ausgabe von formatierten Tabellen
- [DelimitedFiles.jl](https://docs.julialang.org/en/v1/stdlib/DelimitedFiles/) Ein- und Ausgabe von Matrizen u.ä.
- [CSV.jl](https://csv.juliadata.org/stable/) Ein- und Ausgabe von Dateien mit "comma-separated values" u.ä.
- [XLSX.jl](https://felipenoris.github.io/XLSX.jl/stable/tutorial/) Ein- und Ausgabe von Excel-Dateien
- [PrettyTables.jl](https://ronisbr.github.io/PrettyTables.jl/stable/) Output of formatted tables
- [DelimitedFiles.jl](https://docs.julialang.org/en/v1/stdlib/DelimitedFiles/) Input and output of matrices, etc.
- [CSV.jl](https://csv.juliadata.org/stable/) Input and output of "comma-separated values" files, etc.
- [XLSX.jl](https://felipenoris.github.io/XLSX.jl/stable/tutorial/) Input and output of Excel files
und viele andere mehr...
and many more...
### DelimitedFiles.jl
Dieses Paket ermöglicht das bequeme Abspeichern/Einlesen von Matrizen. Dazu stellt es die Funktionen `writedlm()` und `readdlm()` zur
Verfügung.
This package enables convenient saving/reading of matrices. It provides the functions `writedlm()` and `readdlm()`.
```{julia}
using DelimitedFiles
```
Wir erzeugen eine 200×3-Matrix von Zufallszahlen
We generate a 200×3 matrix of random numbers
```{julia}
A = rand(200,3)
```
und speichern diese
and save it
```{julia}
f = open("data2.txt", "w")
writedlm(f, A)
@@ -366,23 +380,23 @@ close(f)
```
Die geschriebene Datei fängt so an:
The written file starts like this:
```{julia}
;head data2.txt
```
Das Wiedereinlesen ist noch einfacher:
Reading it back is even simpler:
```{julia}
B = readdlm("data2.txt")
```
Noch ein Punkt: Beim Umgang mit Dateien wird in Julia oft die `do`-Notation verwendet, s. @sec-do.
Dazu nutzt man, dass `open()` auch Methoden hat, bei denen das 1. Argument eine `function(iostream)` ist.
Diese wird dann auf den _stream_ angewendet und dieser abschliessend automatisch geschlossen. Die `do`-Notation erlaubt es,
diese Funktion anonym nach dem `do` zu definieren:
One more point: In Julia, the `do` notation is often used for file handling, see @sec-do.
This uses the fact that `open()` also has methods where the 1st argument is a `function(iostream)`.
This function is then applied to the _stream_ and the stream is automatically closed at the end. The `do` notation allows you to
define this function anonymously after the `do`:
```{julia}
open("data2.txt", "w") do io
@@ -390,18 +404,16 @@ open("data2.txt", "w") do io
end
```
### CSV und DataFrames
- Das CSV-Format wird oft benutzt, um Tabellen in einer nicht nur mit MS Excel lesbaren Form zur Verfügung zu stellen.
- Ein Beispiel ist die Wetter- und Klimadatenbank _Meteostat_.
- Das Paket [DataFrames.jl](https://dataframes.juliadata.org/stable/) stellt Funktionen zum bequemen Umgang mit tabellarischen Daten
zur Verfügung.
### CSV and DataFrames
- The CSV format is often used to provide tables in a form that can be read not only by MS Excel.
- An example is the weather and climate database _Meteostat_.
- The [DataFrames.jl](https://dataframes.juliadata.org/stable/) package provides functions for convenient handling of tabular data.
```{julia}
using CSV, DataFrames, Downloads
# Wetterdaten von Westerland, s. https://dev.meteostat.net/bulk/hourly.html
# Weather data from Westerland, see https://dev.meteostat.net/bulk/hourly.html
url = "https://bulk.meteostat.net/v2/hourly/10018.csv.gz"
http_response = Downloads.download(url)
@@ -409,25 +421,26 @@ file = CSV.File(http_response, header=false);
```
Die Daten sehen so aus:
The data looks like this:
```{julia}
# https://dev.meteostat.net/bulk/hourly.html#endpoints
#
# Spalte 1 Datum
# 2 Uhrzeit (Stunde)
# 3 Temp
# 5 Luftfeuchtigkeit
# 6 Niederschlag
# 8 Windrichtung
# 9 Windstärke
# Column 1 Date
# 2 Time (hour)
# 3 Temperature
# 5 Humidity
# 6 Precipitation
# 8 Wind direction
# 9 Wind speed
df = DataFrame(file)
```
```{julia}
#| error: false
#| echo: false
@@ -438,18 +451,19 @@ describe(df)
Zum bequemen Plotten und zum Umgang mit den Datums- und Zeitformaten in der Wettertabelle
laden wir noch 2 Helferlein:
For convenient plotting and handling of date and time formats in the weather table,
we load two helper packages:
```{julia}
using StatsPlots, Dates
```
Wir erzeugen eine neue Spalte, die Datum (aus Spalte 1) und Uhrzeit (aus Spalte 2) kombiniert:
We create a new column that combines date (from column 1) and time (from column 2):
```{julia}
# neue Spalte mit Sp.1 und 2 (date & time) kombiniert
# new column combining col. 1 and 2 (date & time)
df[!, :datetime] = DateTime.(df.Column1) .+ Hour.(df.Column2);
```
@@ -466,14 +480,12 @@ df[!, :datetime] = DateTime.(df.Column1) .+ Hour.(df.Column2);
@df df plot(:datetime, :Column3)
```
Und nun zum Plot:
And now to the plot:
```{julia}
@df df plot(:datetime, [:Column9, :Column6, :Column3],
xlims = (DateTime(2023,9,1), DateTime(2024,5,30)),
layout=(3,1), title=["Wind" "Regen" "Temp"],
layout=(3,1), title=["Wind" "Rain" "Temp"],
legend=:none, size=(800,800))
```

View File

@@ -10,41 +10,41 @@ using InteractiveUtils
```
# Plots und Datenvisualisierung in Julia: _Plots.jl_
# Plots and Data Visualization in Julia: _Plots.jl_
Es gibt zahlreiche Grafikpakete für Julia. Zwei oft genutzte sind [Makie.jl](https://docs.makie.org/stable/) und
[Plots.jl](https://docs.juliaplots.org/latest/). Bevor wir diese genauer vorstellen, seien noch einige andere Pakete aufgelistet.
There are numerous graphics packages for Julia. Two frequently used ones are [Makie.jl](https://docs.makie.org/stable/) and
[Plots.jl](https://docs.juliaplots.org/latest/). Before presenting these in more detail, some other packages are listed.
## Kurze Übersicht: einige Grafikpakete
## Brief Overview: Some Graphics Packages
| Paket/Doku | Tutorial | Beispiele | Bemerkungen |
| Package/Documentation | Tutorial | Examples | Remarks |
|:----|:--|:--|:--------|
|[Plots.jl](https://docs.juliaplots.org/latest/) | [Tutorial](https://docs.juliaplots.org/latest/tutorial/) | [Galerie](https://goropikari.github.io/PlotsGallery.jl/) | konzipiert als einheitliches Interface zu verschiedenen _backends_ (Grafikbibliotheken) |
| [Makie.jl](https://docs.makie.org/stable/) | [Basic tutorial](https://docs.makie.org/v0.21/tutorials/basic-tutorial) | [Beautiful Makie](https://beautiful.makie.org/) | "data visualization ecosystem for Julia", Backends: Cairo (Vektorgrafik), OpenGL, WebGL |
|[PlotlyJS.jl](http://juliaplots.org/PlotlyJS.jl/stable/) | [Getting started](https://plotly.com/julia/getting-started/)| [Examples](https://plotly.com/julia/plotly-fundamentals/)| Interface zur [Plotly](https://plotly.com/graphing-libraries/) Javascript-Grafikbibliothek |
| [Gadfly.jl](https://gadflyjl.org/stable/)| [Tutorial](https://gadflyjl.org/stable/tutorial/) | [Galerie](https://github.com/GiovineItalia/Gadfly.jl?tab=readme-ov-file#gallery)| "a plotting and data visualization system written in Julia, influenced by R's [ggplot2](https://ggplot2.tidyverse.org/)" |
| [Bokeh.jl](https://cjdoris.github.io/Bokeh.jl/stable/) | | [Galerie](https://cjdoris.github.io/Bokeh.jl/stable/gallery/)| Julia-Frontend für [Bokeh](https://bokeh.org/) |
|[VegaLite.jl](https://www.queryverse.org/VegaLite.jl/stable/) | [Tutorial](https://www.queryverse.org/VegaLite.jl/stable/gettingstarted/tutorial/)| [Examples](https://www.queryverse.org/VegaLite.jl/stable/examples/examples_barcharts/)| Julia-Frontend für [Vega-Lite](https://vega.github.io/vega-lite/)|
| [Luxor.jl](http://juliagraphics.github.io/Luxor.jl/stable/) |[Tutorial](https://juliagraphics.github.io/Luxor.jl/stable/tutorial/helloworld/)|[Examples](https://juliagraphics.github.io/Luxor.jl/stable/example/moreexamples/)| Allgemeine Vektorgrafik/Illustrationen |
| [Javis.jl](https://juliaanimators.github.io/Javis.jl/stable/) |[Tutorials](https://juliaanimators.github.io/Javis.jl/stable/tutorials/)| [Examples](https://juliaanimators.github.io/Javis.jl/stable/examples/)| *Animierte* Vektorgrafik
|[Plots.jl](https://docs.juliaplots.org/latest/) | [Tutorial](https://docs.juliaplots.org/latest/tutorial/) | [Gallery](https://goropikari.github.io/PlotsGallery.jl/) | designed as a unified interface to various _backends_ (graphics libraries) |
| [Makie.jl](https://docs.makie.org/stable/) | [Basic tutorial](https://docs.makie.org/v0.21/tutorials/basic-tutorial) | [Beautiful Makie](https://beautiful.makie.org/) | "data visualization ecosystem for Julia", backends: Cairo (vector graphics), OpenGL, WebGL |
|[PlotlyJS.jl](http://juliaplots.org/PlotlyJS.jl/stable/) | [Getting started](https://plotly.com/julia/getting-started/)| [Examples](https://plotly.com/julia/plotly-fundamentals/)| Interface to the [Plotly](https://plotly.com/graphing-libraries/) JavaScript graphics library |
| [Gadfly.jl](https://gadflyjl.org/stable/)| [Tutorial](https://gadflyjl.org/stable/tutorial/) | [Gallery](https://github.com/GiovineItalia/Gadfly.jl?tab=readme-ov-file#gallery)| "a plotting and data visualization system written in Julia, influenced by R's [ggplot2](https://ggplot2.tidyverse.org/)" |
| [Bokeh.jl](https://cjdoris.github.io/Bokeh.jl/stable/) | | [Gallery](https://cjdoris.github.io/Bokeh.jl/stable/gallery/)| Julia frontend for [Bokeh](https://bokeh.org/) |
|[VegaLite.jl](https://www.queryverse.org/VegaLite.jl/stable/) | [Tutorial](https://www.queryverse.org/VegaLite.jl/stable/gettingstarted/tutorial/)| [Examples](https://www.queryverse.org/VegaLite.jl/stable/examples/examples_barcharts/)| Julia frontend for [Vega-Lite](https://vega.github.io/vega-lite/)|
| [Luxor.jl](http://juliagraphics.github.io/Luxor.jl/stable/) |[Tutorial](https://juliagraphics.github.io/Luxor.jl/stable/tutorial/helloworld/)|[Examples](https://juliagraphics.github.io/Luxor.jl/stable/example/moreexamples/)| General vector graphics/illustrations |
| [Javis.jl](https://juliaanimators.github.io/Javis.jl/stable/) |[Tutorials](https://juliaanimators.github.io/Javis.jl/stable/tutorials/)| [Examples](https://juliaanimators.github.io/Javis.jl/stable/examples/)| *Animated* vector graphics
| [TidierPlots.jl](https://github.com/TidierOrg/TidierPlots.jl)| [Reference](https://tidierorg.github.io/TidierPlots.jl/latest/) || "is a 100% Julia implementation of the R package ggplot2 powered by Makie.jl"|
|[PythonPlot.jl](https://github.com/JuliaPy/PythonPlot.jl)| |[Examples (in Python)](https://matplotlib.org/stable/gallery/index.html)| Interface zu Matplotlib (Python), 1:1-Übertragung der Python-API, deswegen s. [Matplotlib-Dokumentation](https://matplotlib.org/stable/api/pyplot_summary.html)
|[PythonPlot.jl](https://github.com/JuliaPy/PythonPlot.jl)| |[Examples (in Python)](https://matplotlib.org/stable/gallery/index.html)| Interface to Matplotlib (Python), 1:1 transfer of the Python API, therefore see [Matplotlib documentation](https://matplotlib.org/stable/api/pyplot_summary.html)
: {.striped .hover}
{: .striped .hover}
<!--
| [PyPlot.jl](https://github.com/JuliaPy/PyPlot.jl) | | [Examples](https://gist.github.com/gizmaa/7214002)| Interface zu Matplotlib (Python), 1:1-Übertragung der Python-API, deswegen s. [Matplotlib-Dokumentation](https://matplotlib.org/stable/) |
| [PyPlot.jl](https://github.com/JuliaPy/PyPlot.jl) | | [Examples](https://gist.github.com/gizmaa/7214002)| Interface to Matplotlib (Python), 1:1 transfer of the Python API, therefore see [Matplotlib documentation](https://matplotlib.org/stable/) |
-->
## Plots.jl
### Einfache Plots
### Simple Plots
Die `plot()`-Funktion erwartet im einfachsten Fall:
The `plot()` function expects, in the simplest case:
- als erstes Argument einen Vektor von $x$-Werten der Länge $n$ und
- als zweites Argument einen gleichlangen Vektor mit den dazugehörigen $y$-Werten.
- Das zweite Argument kann auch eine $n\times m$-Matrix sein. Dann wird jeder Spaltenvektor als eigener Graph (in der Docu `series` genannt) angesehen und es werden $m$ Kurven geplottet:
- as the first argument a vector of $x$-values of length $n$ and
- as the second argument a vector of the same length with the corresponding $y$-values.
- The second argument can also be an $n\times m$-matrix. Then each column vector is regarded as a separate graph (called `series` in the documentation) and $m$ curves are plotted:
```{julia}
@@ -57,16 +57,16 @@ cx = @. cos(2x^(1/2))
plot(x, [sx cx])
```
- Die Funktionen des _Plots.jl_-Paketes wie `plot(), scatter(), contour(), heatmap(), histogram(), bar(),...` usw. starten alle einen neuen Plot.
- Die Versionen `plot!(), scatter!(), contour!(), heatmap!(), histogram!(), bar!(),...` erweitern einen existierenden Plot:
- The functions of the _Plots.jl_ package such as `plot(), scatter(), contour(), heatmap(), histogram(), bar(),...` etc. all start a new plot.
- The versions `plot!(), scatter!(), contour!(), heatmap!(), histogram!(), bar!(),...` extend an existing plot:
```{julia}
plot(x, sx) # plot only sin(x)
plot!(x, cx) # add second graph
plot!(x, sqrt.(x)) # add a thirth one
plot!(x, sqrt.(x)) # add a third one
```
Plots sind Objekte, die zugewiesen werden können. Dann kann man sie später weiterverwenden, kopieren und insbesondere mit den `!`-Funktionen erweitern:
Plots are objects that can be assigned. Then they can be used later, copied, and in particular extended with the `!` functions:
```{julia}
plot1 = plot(x, [sx cx])
@@ -74,7 +74,7 @@ plot1a = deepcopy(plot1) # plot objects are quite deep structures
scatter!(plot1, x, sx) # add scatter plot, i.e. unconnected data points
```
Die kopierte Version `plot1a` ist durch die `scatter!`-Anweisung nicht modifiziert worden und kann unabhängig weiterverwendet werden:
The copied version `plot1a` has not been modified by the `scatter!` statement and can be used independently:
```{julia}
plot!(plot1a, x, 2 .* sx)
@@ -82,7 +82,7 @@ plot!(plot1a, x, 2 .* sx)
Plot-Objekte kann man als Grafikdateien (PDF, SVG, PNG,...) abspeichern:
Plot objects can be saved as graphics files (PDF, SVG, PNG,...):
```{julia}
@@ -94,13 +94,13 @@ savefig(plot1, "plot.png")
;ls -l plot.png
```
Plot-Objekte können auch als Teilplot in andere Plots eingefügt werden, siehe Abschnitt @sec-subplot.
Plot objects can also be inserted as subplots into other plots, see section @sec-subplot.
### Funktionsplots
### Function Plots
Man kann `plot()` auch eine Funktion und einen Vektor mit $x$-Werten übergeben:
`plot()` can also be passed a function and a vector of $x$-values:
```{julia}
# https://mzrg.com/math/graphs.shtml
@@ -109,9 +109,9 @@ f(x) = abs(sin(x^x)/2^((x^x-π/2)/π))
plot(f, 0:0.01:3)
```
Die parametrische Form $x = x(t),\ y = y(t)$ kann durch die Übergabe von zwei Funktionen und einen Vektor von $t$-Werten an `plot()` gezeichnet werden.
The parametric form $x = x(t),\ y = y(t)$ can be drawn by passing two functions and a vector of $t$-values to `plot()`.
```{julia}
# https://en.wikipedia.org/wiki/Butterfly_curve_(transcendental)
@@ -123,16 +123,16 @@ plot(xt, yt, 0:0.01:12π)
```
### Plot-Themen
### Plot Themes
> "PlotThemes is a package to spice up the plots made with Plots.jl."\
Hier geht es zur illustrierten [Liste der Themen](https://docs.juliaplots.org/stable/generated/plotthemes/)
Here is the illustrated [list of themes](https://docs.juliaplots.org/stable/generated/plotthemes/)
oder:
or:
```{julia}
using PlotThemes
# Liste der Themen
# list of themes
keys(PlotThemes._themes)
```
@@ -149,48 +149,48 @@ plot(x, [sx cx 1 ./ (1 .+ x)])
```
### Plot-Attribute
### Plot Attributes
Die Funktionen des `Plots.jl`-Paketes haben eine große Anzahl von Optionen.
`Plots.jl` teilt die Attribute in 4 Gruppen ein:
The functions of the `Plots.jl` package have a large number of options.
`Plots.jl` divides the attributes into 4 groups:
::::{.cell}
```{julia}
#| output: asis
plotattr(:Plot) # Attribute für den Gesamtplot
plotattr(:Plot) # attributes for the overall plot
```
::::
::::{.cell}
```{julia}
#| output: asis
plotattr(:Subplot) # Attribute für einen Teilplot
plotattr(:Subplot) # attributes for a subplot
```
::::
::::{.cell}
```{julia}
#| output: asis
plotattr(:Axis) # Attribute für eine Achse
plotattr(:Axis) # attributes for an axis
```
::::
::::{.cell}
```{julia}
#| output: asis
plotattr(:Series) # Attribute für eine Serie, also zB ein Linienzug im Plot
plotattr(:Series) # attributes for a series, e.g., a line in the plot
```
::::
Man kann auch nachfragen, was die einzelnen Attribute bedeuten und welche Werte zulässig sind:
One can also ask what the individual attributes mean and which values are allowed:
```{julia}
plotattr("linestyle")
```
Ein Beispiel:
An example:
```{julia}
theme(:default) # zurück zum Standardthema
theme(:default) # return to default theme
x = 0:0.05:1
y = sin.(2π*x)
@@ -200,9 +200,9 @@ plot(x, y, seriestype = :sticks, linewidth = 4, seriescolor = "#00b300",
)
```
Viele Angaben können auch sehr weit abgekürzt werden, siehe z.B. die Angabe `Aliases:` in der obigen Ausgabe des Kommandos `plotattr("linestyle")`.
Many specifications can also be abbreviated significantly, see e.g. the `Aliases:` in the above output of the command `plotattr("linestyle")`.
Das folgende `plot()`-Kommando is äquivalent zum vorherigen:
The following `plot()` command is equivalent to the previous one:
```{julia}
#| eval: false
@@ -210,61 +210,61 @@ plot(x, y, t = :sticks, w = 4, c = "#00b300", m = (:circle, 8, :green ))
```
### Weitere Extras
### Additional Extras
```{julia}
using Plots # Wiederholung schadet nicht
using Plots.PlotMeasures # für Maßangaben in mm, cm,...
using LaTeXStrings # für LaTeX-Konstrukte in Plot-Beschriftungen
using PlotThemes # vorgefertigte Themen
using Plots # repetition does not hurt
using Plots.PlotMeasures # for measurements in mm, cm,...
using LaTeXStrings # for LaTeX constructs in plot labels
using PlotThemes # predefined themes
```
Das Paket `LaTeXStrings.jl` stellt einen String-Konstruktor `L"..."` zur Verfügung. Diese Strings können LaTeX-Konstrukte, insbesondere Formeln, enthalten. Wenn der String keine expliziten Dollarzeichen enthält, wird er automatisch im LaTeX-Math-Modus interpretiert.
The `LaTeXStrings.jl` package provides a string constructor `L"..."`. These strings can contain LaTeX constructs, especially formulas. If the string does not contain explicit dollar signs, it is automatically interpreted in LaTeX math mode.
```{julia}
xs = range(0, 2π, length = 100)
data = [sin.(xs) cos.(xs) 2sin.(xs) (x->sin(x^2)).(xs)] # 4 Funktionen
data = [sin.(xs) cos.(xs) 2sin.(xs) (x->sin(x^2)).(xs)] # 4 functions
theme(:ggplot2)
plot10 = plot(xs, data,
fontfamily="Computer Modern",
# LaTeX-String L"..."
# LaTeX string L"..."
title = L"Winkelfunktionen $\sin(\alpha), \cos(\alpha), 2\sin(\alpha), \sin(\alpha^2)$",
xlabel = L"Winkel $\alpha$",
ylabel = "Funktionswert",
# 1x4-Matrizen mit Farben, Marker,... für die 4 'Series'
# 1x4-matrices with colors, markers,... for the 4 'series'
color=[:black :green RGB(0.3, 0.8, 0.2) :blue ],
markers = [:rect :circle :utriangle :diamond],
markersize = [2 1 0 4],
linewidth = [1 3 1 2],
linestyle = [:solid :dash :dot :solid ],
# Achsen
# axes
xlim = (0, 6.6),
ylim = (-2, 2.3),
yticks = -2:.4:2.3, # mit Schrittweite
yticks = -2:.4:2.3, # with step size
# Legende
# legend
legend = :bottomleft,
label = [ L"\sin(\alpha)" L"\cos(\alpha)" L"2\sin(\alpha)" L"\sin(\alpha^2)"],
top_margin = 5mm, # hier wird Plots.PlotMeasures gebraucht
top_margin = 5mm, # here Plots.PlotMeasures is needed
)
# Zusatztext: annotate!(x-pos, y-pos, text("...", font, fontsize))
# additional text: annotate!(x-pos, y-pos, text("...", font, fontsize))
annotate!(plot10, 4.1, 1.8, text("nicht schön, aber viel","Computer Modern", 10) )
```
### Andere Plot-Funktionen
### Other Plot Functions
Bisher haben wir vor allem Linien geplottet. Es gibt noch viele andere Typen wie _scatter plot, contour, heatmap, histogram, stick,..._
So far, we have plotted mainly lines. There are many other types such as _scatter plot, contour, heatmap, histogram, stick,..._
Dies kann man mit dem `seriestype`-Attribut steuern:
This can be controlled with the `seriestype` attribute:
```{julia}
theme(:default)
@@ -273,7 +273,7 @@ x = range(0, 2π; length = 50)
plot(x, sin.(x), seriestype=:scatter)
```
oder indem man die spezielle Funktion benutzt, die so heißt wie der `seriestype`:
or by using the specific function named after the `seriestype`:
```{julia}
x = range(0, 2π; length = 50)
scatter(x, sin.(x))
@@ -281,9 +281,9 @@ scatter(x, sin.(x))
### Subplots und Layout {#sec-subplot}
### Subplots and Layout {#sec-subplot}
Mehrere Plots können zu einer Abbildung zusammengefasst werden. Die Anordnung bestimmt der `layout`-Parameter. Dabei bedeutet `layout=(m,n)`, dass die Plots in einem $m\times n$-Schema angeordnet werden:
Multiple plots can be combined into one figure. The arrangement is determined by the `layout` parameter. `layout=(m,n)` means that the plots are arranged in an $m\times n$ scheme:
```{julia}
x = range(0, 2π; length = 100)
@@ -300,7 +300,7 @@ plot(plots..., layout=(4,1), legend=false, title=["sin" "cos" "tan" "sinc"])
```
Man kann Layouts auch schachteln und mit dem `@layout`-Macro explizite Breiten/Höhenanteile vorgeben:
Layouts can also be nested and explicit width/height proportions can be specified using the `@layout` macro:
```{julia}
@@ -317,27 +317,27 @@ plot(plots..., layout=mylayout, legend=false, title=["sin" "cos" "tan" "sinc"])
### Backends
`Plots.jl` ist konzipiert als ein einheitliches Interface zu verschiedenen _backends_ (Grafik-Engines). Man kann zu einem anderen Backend wechseln und dieselben Plot-Kommandos und -Attribute verwenden.
`Plots.jl` is designed as a unified interface to various _backends_ (graphics engines). One can switch to another backend and use the same plot commands and attributes.
Allerdings unterstützen nicht alle _backends_ alle Plot-Typen und -Attribute. Einen Überblick gibt es [hier](https://docs.juliaplots.org/stable/generated/supported/).
However, not all _backends_ support all plot types and attributes. An overview is available [here](https://docs.juliaplots.org/stable/generated/supported/).
Bisher wurde das Standard-Backend verwendet. Es heißt [GR](https://gr-framework.org/about.html) und ist eine am Forschungszentrum Jülich entwickelte und hauptsächlich in C geschriebene Grafik-Engine.
So far, the default backend has been used. It is called [GR](https://gr-framework.org/about.html) and is a graphics engine developed at the Jülich Research Center and written primarily in C.
```{julia}
using Plots
backend() # Anzeige des gewählten backends, GR ist der default
backend() # display the selected backend, GR is the default
```
Nochmal ein Beispiel
Another example
```{julia}
x = 1:30
y = rand(30)
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Wasserstand")
```
und hier derselbe Plot mit dem `PlotlyJS`-Backend.
and here the same plot with the `PlotlyJS` backend.
```{julia}
@@ -345,22 +345,22 @@ plotlyjs() # change plots backend
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Wasserstand")
```
Dieses Backend ermöglich mit Hilfe von Javascript eine gewisse Interaktivität. Wenn man die Maus in das Bild bewegt, kann man mit der Maus zoomen, verschieben und 3D-Plots auch drehen.
This backend enables a certain interactivity using JavaScript. When moving the mouse into the image, one can zoom and pan with the mouse, and 3D plots can also be rotated.
```{julia}
gr() # zurück zu GR als backend
gr() # return to GR as backend
```
### 3D Plots
Die Funktionen `surface()` und `contour()` ermöglichen den Plot einer Funktion $f(x,y)$. Als Argumente werden benötigt:
The functions `surface()` and `contour()` allow plotting of a function $f(x,y)$. The required arguments are:
- eine Menge (Vektor) $X$ von $x$-Werten,
- eine Menge (Vektor) $Y$ von $y$-Werten und
- eine Funktion von zwei Variablen, die dann auf $X \times Y$ ausgewertet und geplottet wird.
- a set (vector) $X$ of $x$-values,
- a set (vector) $Y$ of $y$-values and
- a function of two variables that is then evaluated on $X \times Y$ and plotted.
```{julia}
f(x,y) = (1 - x/2 + x^5 + y^3) * exp(-x^2 - y^2)
@@ -372,8 +372,8 @@ surface( -3:0.02:3, -3:0.02:3, f)
contour( -3:0.02:3, -3:0.02:3, f, fill=true, colormap=:summer, levels=20, contour_labels=false)
```
Kurven (oder auch einfach Punktmengen) in drei Dimensionen lassen sich plotten, indem man `plot()` mit 3 Vektoren
aufruft, die jeweils die $x$, $y$ und $z$-Koordinaten der Datenpunkte enthalten.
Curves (or simply point sets) in three dimensions can be plotted by calling `plot()` with 3 vectors
containing the $x$, $y$ and $z$-coordinates of the data points, respectively.
```{julia}
plotlyjs()
@@ -387,25 +387,25 @@ plot(x, y, z, zcolor=reverse(z), markersize=3, markershape= :circle,
```
> Wir verwenden mal das `plotlyjs`-Backend, damit ist der Plot interaktiv und kann mit der Maus gedreht und gezoomt werden.
> We use the `plotlyjs` backend here, so the plot is interactive and can be rotated and zoomed with the mouse.
### Plots.jl und _recipes_
### Plots.jl and _recipes_
Andere Pakete können die Möglichkeiten von `Plots.jl` erweitern, indem sie sogenannte _recipes_ für spezielle Plots und Datenstrukturen definieren, siehe [https://docs.juliaplots.org/latest/ecosystem/](https://docs.juliaplots.org/latest/ecosystem/), z.B.:
Other packages can extend the capabilities of `Plots.jl` by defining so-called _recipes_ for special plots and data structures, see [https://docs.juliaplots.org/latest/ecosystem/](https://docs.juliaplots.org/latest/ecosystem/), e.g.:
- `StatsPlots.jl` direktes Plotten von _Dataframes_, spezielle statistische Plots usw. oder
- `GraphRecipes.jl` [Plotten von Graphstrukturen](https://docs.juliaplots.org/latest/GraphRecipes/examples/)
- `StatsPlots.jl` direct plotting of _Dataframes_, special statistical plots, etc. or
- `GraphRecipes.jl` [Plotting of graph structures](https://docs.juliaplots.org/latest/GraphRecipes/examples/)
### Ein Säulendiagramm
### A Bar Chart
Für das letzte Beispiel laden wir ein Paket, das über 700 freie (_"public domain"_) Datensätze, darunter z.B:
For the last example, we load a package that provides over 700 free (_"public domain"_) datasets, including, for example:
- die Passagierliste der _Titanic_,
- Verbrauchsdaten amerikanischer Autos aus den 70ern oder
- historische Währungskurse
- the passenger list of the _Titanic_,
- fuel consumption data of American cars from the 70s or
- historical exchange rates
bereitstellt:
provides:
```{julia}
using RDatasets
@@ -419,13 +419,13 @@ using RDatasets
#RDatasets.datasets()
```
Der Datensatz ["Motor Trend Car Road Tests"](https://rdrr.io/r/datasets/mtcars.html)
The dataset ["Motor Trend Car Road Tests"](https://rdrr.io/r/datasets/mtcars.html)
```{julia}
cars = dataset("datasets", "mtcars")
```
Wir brauchen für den Plot nur die beiden Spalten `cars.Model` und `cars.MPG`, den Benzinverbrauch in _miles per gallon_ (Mehr heißt sparsamer!)
We only need the two columns `cars.Model` and `cars.MPG` for the plot, the fuel consumption in _miles per gallon_ (more means more economical!)
```{julia}
theme(:bright)
@@ -443,10 +443,10 @@ bar(cars.Model, cars.MPG,
```
### Was noch fehlt: Animation
### What is Missing: Animation
Hier sei auf die [Dokumentation](https://docs.juliaplots.org/latest/animations/) verwiesen und nur ein Beispiel
(von <https://www.juliafordatascience.com/animations-with-plots-jl/>) angegeben:
Please refer to the [documentation](https://docs.juliaplots.org/latest/animations/) and only an example
(from <https://www.juliafordatascience.com/animations-with-plots-jl/>) is given:
```{julia}
#| error: false

View File

@@ -2,7 +2,18 @@
engine: julia
---
# Arbeit mit Julia: REPL, Pakete, Introspection
```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
import QuartoNotebookWorker
Base.stdout = QuartoNotebookWorker.with_context(stdout)
myactive_module() = Main.Notebook
Base.active_module() = myactive_module()
```
# Working with Julia: REPL, Packages, Introspection
```{julia}
#| error: false
@@ -17,37 +28,36 @@ Base.active_module() = myactive_module()
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L3073-L3077
```
## Dokumentation
## Documentation
Die offizielle Julia-Dokumentation [https://docs.julialang.org/](https://docs.julialang.org/) enthält zahlreiche Übersichten, darunter:
- [https://docs.julialang.org/en/v1/base/punctuation/](https://docs.julialang.org/en/v1/base/punctuation/) Verzeichnis der Symbole
- [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
- [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
The official Julia documentation [https://docs.julialang.org/](https://docs.julialang.org/) contains numerous overviews, including:
- [https://docs.julialang.org/en/v1/base/punctuation/](https://docs.julialang.org/en/v1/base/punctuation/) List of symbols
- [https://docs.julialang.org/en/v1/manual/unicode-input/](https://docs.julialang.org/en/v1/manual/unicode-input/) List of special Unicode symbols and their input methods via tab completion in Julia
- [https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions) List of mathematical functions
## Julia REPL (Read - Eval - Print - Loop)
Nach dem Start von Julia in einem Terminal kann man neben Julia-Code auch verschiedene Kommandos eingeben
After starting Julia in a terminal, you can enter both Julia code and various commands:
:::{.narrow}
| Kommando | Wirkung |
| Command | Effect |
| :----------------------------| :------------------------ |
| `exit()` oder `Ctrl-d` | exit Julia |
| `exit()` or `Ctrl-d` | exit Julia |
| `Ctrl-c` | interrupt |
| `Ctrl-l` | clear screen |
| Kommando mit `;` beenden | Ausgabe unterdrückt |
| `include("filename.jl")` | Datei mit Julia-Code einlesen und ausführen |
| End command with `;` | suppress output |
| `include("filename.jl")` | read and execute file with Julia code |
The REPL has several modes:
Der REPL hat verschiedene Modi:
| Modus | Prompt | Modus starten | Modus verlassen |
| Mode | Prompt | Start mode | Exit mode |
| :- | :- | :- | :- |
| default| `julia>` | | `Ctrl-d` (beendet Julia) |
| default| `julia>` | | `Ctrl-d` (exits Julia) |
| Package manager | `pkg>` | `]` | `backspace` |
| Help | `help?>` | `?`| `backspace `|
|Shell | `shell>` | `;` | `backspace`|
@@ -55,12 +65,12 @@ Der REPL hat verschiedene Modi:
:::
## Jupyter-Notebooks (IJulia)
## Jupyter Notebooks (IJulia)
In einem Jupyter-Notebook sind die Modi sind als Einzeiler in einer eigenen Input-Zelle nutzbar:
In a Jupyter notebook, the modes are usable as single-line commands in their own input cells:
(i) ein Kommando des Paket-Managers:
(i) a package manager command:
```{julia}
@@ -68,7 +78,7 @@ In einem Jupyter-Notebook sind die Modi sind als Einzeiler in einer eigenen Inpu
] status
```
(ii) eine Help-Abfrage:
(ii) a help query:
```{julia}
@@ -76,7 +86,7 @@ In einem Jupyter-Notebook sind die Modi sind als Einzeiler in einer eigenen Inpu
?sin
```
(iii) Ein Shell-Kommando:
(iii) a shell command:
```{julia}
@@ -84,33 +94,33 @@ In einem Jupyter-Notebook sind die Modi sind als Einzeiler in einer eigenen Inpu
;ls
```
## Der Paketmanager
## The Package Manager
Wichtiger Teil des _Julia Ecosystems_ sind die zahlreichen Pakete, die Julia erweitern.
An important part of the _Julia ecosystem_ is the numerous packages that extend Julia.
- Einige Pakete sind Teil jeder Julia-Installation und müssen nur mit einer `using Paketname`-Anweisung aktiviert werden.
- Sie bilden die sogenannte _Standard Library_ und dazu gehören
- `LinearAlgebra`, `Statistics`, `SparseArrays`, `Printf`, `Pkg` und andere.
- Über 9000 Pakete sind offiziell registriert, siehe [https://julialang.org/packages/](https://julialang.org/packages/).
- Diese können mit wenigen Tastendrücken heruntergeladen und installiert werden.
- Dazu dient der _package manager_ `Pkg`.
- Man kann ihn auf zwei Arten verwenden:
- als normale Julia-Anweisungen, die auch in einer `.jl`-Programmdatei stehen können:
- Some packages are part of every Julia installation and only need to be activated with a `using Packagename` statement.
- They form the so-called _standard library_, which includes
- `LinearAlgebra`, `Statistics`, `SparseArrays`, `Printf`, `Pkg`, and others.
- Over 9000 packages are officially registered, see [https://julialang.org/packages/](https://julialang.org/packages/).
- These can be downloaded and installed with just a few keystrokes.
- The _package manager_ `Pkg` is used for this purpose.
- It can be used in two ways:
- as normal Julia statements that can also be in a `.jl` program file:
```
using Pkg
Pkg.add("PaketXY")
Pkg.add("PackageXY")
```
- im speziellen pkg-Modus des Julia-REPLs:
- in the special pkg-mode of the Julia REPL:
```
] add PaketXY
] add PackageXY
```
- Anschließend kann das Paket mit `using PaketXY` verwendet werden.
- Man kann auch Pakete aus anderen Quellen und selbstgeschriebene Pakete installieren.
- Afterward, the package can be used with `using PackageXY`.
- You can also install packages from other sources and self-written packages.
### Einige Funktionen des Paketmanagers
### Some Package Manager Functions
| Funktion | `pkg` - Mode | Erklärung |
| Function | `pkg` - Mode | Explanation |
|:------------------------|:--------------------------| :-------------------------------------------------------|
| `Pkg.add("MyPack")` | `pkg> add MyPack` | add `MyPack.jl` to current environment |
| `Pkg.rm("MyPack")` | `pkg> remove MyPack` | remove `MyPack.jl` from current environment |
@@ -120,13 +130,13 @@ Wichtiger Teil des _Julia Ecosystems_ sind die zahlreichen Pakete, die Julia erw
| `Pkg.instantiate()` | `pg> instantiate` | install all packages according to `Project.toml` |
### Installierte Pakete und Environments
### Installed Packages and Environments
- Julia und der Paketmanager verwalten
1. eine Liste der mit dem Kommando `Pkg.add()` bzw. `]add` explizit installierten Pakete mit genauer Versionsbezeichnung in einer Datei `Project.toml` und
2. eine Liste aller dabei auch als implizite Abhängigkeiten installierten Pakete in der Datei `Manifest.toml`.
- Das Verzeichnis, in dem diese Dateien stehen, ist das `environment` und wird mit `Pkg.status()` bzw. `]status` angezeigt.
- Im Normalfall sieht das so aus:
- Julia and the package manager maintain
1. a list of packages explicitly installed with the command `Pkg.add()` or `]add` with exact version specifications in a file `Project.toml` and
2. a list of all packages installed as implicit dependencies in the file `Manifest.toml`.
- The directory in which these files are located is the `environment` and is displayed with `Pkg.status()` or `]status`.
- In the normal case, this looks like this:
```
(@v1.10) pkg> status
@@ -137,18 +147,18 @@ Wichtiger Teil des _Julia Ecosystems_ sind die zahlreichen Pakete, die Julia erw
[295af30f] Revise v3.5.14
```
- Man kann für verschiedene Projekte eigene `environments` benutzen. Dazu kann man entweder Julia mit
- You can use separate `environments` for different projects. You can either start Julia with
```shell
julia --project=path/to/myproject
```
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`)
or activate the environment in Julia with `Pkg.activate("path/to/myproject")`. Then `Project.toml, Manifest.toml` are created and managed there. (The installation of package files still takes place somewhere under `$HOME/.julia`)
### Zum Installieren von Paketen auf unserem Jupyter-Server `misun103`:
### For Installing Packages on Our Jupyter Server `misun103`:
- Es gibt ein zentrales Repository, in dem alle in diesem Kurs erwähnten Pakete bereits installiert sind.
- Dort haben Sie keine Schreibrechte.
- Sie können aber zusätzliche Pakete in Ihrem `HOME` installieren. Dazu ist als erster Befehl nötig, das aktuelle Verzeichnis zu aktivieren:
- There is a central repository in which all packages mentioned in this course are already installed.
- There you have no write permissions.
- However, you can install additional packages in your `HOME`. As a first command, you need to activate the current directory:
```{julia}
@@ -156,26 +166,27 @@ starten oder in Julia das environment mit `Pkg.activate("path/to/myproject")` ak
] activate .
```
(Man beachte den Punkt!)
(Note the dot!)
Danach können Sie mit `add` im Pkg-Modus auch Pakete installieren:
After that, you can install packages with `add` in the pkg-mode:
```{julia}
#| eval: false
] add PaketXY
] add PackageXY
```
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.
Warning! This can take a long time! Many packages have complex dependencies and trigger the installation of further packages. Many packages are precompiled during installation. You can see the installation progress in the REPL, but unfortunately not in the Jupyter notebook.
## The Julia JIT _(just in time)_ Compiler: Introspection
## Der Julia JIT _(just in time)_ Compiler: Introspection
Julia baut auf die Werkzeuge des _LLVM Compiler Infrastructure Projects_ auf.
Julia is built on the tools of the _LLVM Compiler Infrastructure Project_.
:::{.narrow}
Stages of Compilation
@@ -235,5 +246,3 @@ walk_tree(p)
```{julia}
@code_native f(2,4)
```

View File

@@ -2,73 +2,65 @@
engine: julia
---
```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
```
# Containers
Julia offers a wide selection of container types with largely similar interfaces.
We introduce `Tuple`, `Range`, and `Dict` here, and in the next chapter we will cover `Array`, `Vector`, and `Matrix`.
# Container
These containers are:
Julia bietet eine große Auswahl von Containertypen mit weitgehend ähnlichem Interface an.
Wir stellen hier `Tuple`, `Range` und `Dict` vor, im nächsten Kapitel dann `Array`, `Vector` und `Matrix`.
Diese Container sind:
- **iterierbar:** Man kann über die Elemente des Containers iterieren:
- **iterable:** You can iterate over the elements of the container:
```julia
for x ∈ container ... end
```
- **indizierbar:** Man kann auf Elemente über ihren Index zugreifen:
- **indexable:** You can access elements via their index:
```julia
x = container[i]
```
und einige sind auch
```
and some are also
- **mutierbar**: Man kann Elemente hinzufügen, entfernen und ändern.
- **mutable:** You can add, remove, and modify elements.
Weiterhin gibt es eine Reihe gemeinsamer Funktionen, z.B.
Furthermore, there are several common functions, e.g.,
- `length(container)` --- Anzahl der Elemente
- `eltype(container)` --- Typ der Elemente
- `isempty(container)` --- Test, ob Container leer ist
- `empty!(container)` --- leert Container (nur wenn mutierbar)
- `length(container)` --- number of elements
- `eltype(container)` --- type of elements
- `isempty(container)` --- test whether container is empty
- `empty!(container)` --- empties container (only if mutable)
## Tupeln
## Tuples
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.
A tuple is an immutable container of elements. It is therefore not possible to add new elements or change the value of an element.
```{julia}
t = (33, 4.5, "Hello")
@show t[2] # indizierbar
@show t[2] # indexable
for i ∈ t println(i) end # iterierbar
for i ∈ t println(i) end # iterable
```
Ein Tupel ist ein **inhomogener** Typ. Jedes Element hat seinen eigenen Typ und das zeigt sich auch im Typ des Tupels:
A tuple is an **inhomogeneous** type. Each element has its own type, which is reflected in the tuple's type:
```{julia}
typeof(t)
```
Man verwendet Tupel gerne als Rückgabewerte von Funktionen, um mehr als ein Objekt zurückzulieferen.
Tuples are frequently used as function return values to return more than one object.
```{julia}
# Ganzzahldivision und Rest:
# Quotient und Rest werden den Variablen q und r zugewiesen
# Integer division and remainder:
# quotient and remainder are assigned to variables q and r
q, r = divrem(71, 6)
@show q r;
```
Wie man hier sieht, kann man in bestimmten Konstrukten die Klammern auch weglassen.
Dieses *implict tuple packing/unpacking* verwendet man auch gerne in Mehrfachzuweisungen:
As you can see here, parentheses can be omitted in certain constructs.
This *implicit tuple packing/unpacking* is also commonly used in multiple assignments:
```{julia}
@@ -80,56 +72,59 @@ x, y, z = 12, 17, 203
y
```
Manche Funktionen bestehen auf Tupeln als Argument oder geben immer Tupeln zurück. Dann braucht man manchmal ein Tupel aus einem Element.
Some functions require tuples as arguments or always return tuples. Then you sometimes need a tuple with a single element.
Das notiert man so:
This is written as:
```{julia}
x = (13,) # ein 1-Element-Tupel
x = (13,) # a 1-element tuple
```
Das Komma - und nicht die Klammern -- macht das Tupel.
The comma - not the parentheses - makes the tuple.
```{julia}
x= (13) # kein Tupel
x= (13) # not a tuple
```
## Ranges
Wir haben *range*-Objekte schon in numerischen `for`-Schleifen verwendet.
We have already used *range* objects in numerical `for` loops.
```{julia}
r = 1:1000
typeof(r)
```
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()`.
There are various *range* types. As you can see, they are parameterized types based on the numeric type, and `UnitRange` is, for example, a *range* with step size 1. Their constructors are usually named `range()`.
Der Doppelpunkt ist eine spezielle Syntax.
The colon is a special syntax.
- `a:b` wird vom Parser umgesetzt zu `range(a, b)`
- `a:b:c` wird umgesetzt zu `range(a, c, step=b)`
- `a:b` is parsed as `range(a, b)`
- `a:b:c` is parsed as `range(a, c, step=b)`
*Ranges* sind offensichtlich iterierbar, nicht mutierbar aber indizierbar.
*Ranges* are obviously iterable, not mutable, but indexable.
```{julia}
(3:100)[20] # das zwanzigste Element
(3:100)[20] # the 20th element
```
Wir erinnern an die Semantik der `for`-Schleife: `for i in 1:1000` heißt **nicht**:
- 'Die Schleifenvariable `i` wird bei jedem Durchlauf um eins erhöht' **sondern**
- 'Der Schleifenvariable werden nacheinander die Werte 1,2,3,...,1000 aus dem Container zugewiesen'.
Recall the semantics of the `for` loop: `for i in 1:1000` means **not**:
Allerdings wäre es sehr ineffektiv, diesen Container tatsächlich explizit anzulegen.
- 'The loop variable `i` is incremented by one in each iteration' **but rather**
- 'The loop variable is successively assigned the values 1,2,3,...,1000 from the container'.
- _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.
- Sie sind 'Rezepte' oder Generatoren, die auf die Abfrage 'Gib mir dein nächstes Element!' antworten.
- Tatsächlich ist der Muttertyp `AbstractRange` ein Subtyp von `AbstractVector`.
However, it would be very inefficient to actually create this container explicitly.
Das Macro `@allocated` gibt aus, wieviel Bytes an Speicher bei der Auswertung eines Ausdrucks alloziert wurden.
- _Ranges_ are "lazy" vectors that are never really stored as a concrete list anywhere. This makes them so useful as iterators in `for` loops: memory-efficient and fast.
- They are "recipes" or generators that respond to the query "Give me your next element!".
- In fact, the supertype `AbstractRange` is a subtype of `AbstractVector`.
The macro `@allocated` outputs how many bytes of memory were allocated during the evaluation of an expression.
```{julia}
@allocated r = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
@@ -142,34 +137,35 @@ Das Macro `@allocated` gibt aus, wieviel Bytes an Speicher bei der Auswertung ei
Zum Umwandeln in einen 'richtigen' Vektor dient die Funktion `collect()`.
The function `collect()` is used to convert to a "real" vector.
```{julia}
collect(20:-3:1)
```
Recht nützlich, z.B. beim Vorbereiten von Daten zum Plotten, ist der *range*-Typ `LinRange`.
Quite useful, e.g., when preparing data for plotting, is the *range* type `LinRange`.
```{julia}
LinRange(2, 50, 300)
```
`LinRange(start, stop, n)` erzeugt eine äquidistante Liste von `n` Werten von denen der erste und der letzte die vorgegebenen Grenzen sind.
Mit `collect()` kann man bei Bedarf auch daraus den entsprechenden Vektor gewinnen.
`LinRange(start, stop, n)` generates an equidistant list of `n` values where the first and last are the specified limits.
With `collect()` you can also obtain the corresponding vector if needed.
## Dictionaries
- _Dictionaries_ (deutsch: "assoziative Liste" oder "Zuordnungstabelle" oder ...) sind spezielle Container.
- Einträge in einem Vektor `v` sind durch einen Index 1,2,3.... addressierbar: `v[i]`
- Einträge in einem _dictionary_ sind durch allgemeinere _keys_ addressierbar.
- Ein _dictionary_ ist eine Ansammlung von _key-value_-Paaren.
- Damit haben _dictionaries_ in Julia den parametrisierten Typ `Dict{S,T}`, wobei `S` der Typ der _keys_ und `T` der Typ der _values_ ist
- _Dictionaries_ (German: "associative list" or "lookup table" or ...) are special containers.
- Entries in a vector `v` are addressable by an index 1,2,3....: `v[i]`
- Entries in a _dictionary_ are addressable by more general _keys_.
- A _dictionary_ is a collection of _key-value_ pairs.
- Thus, _dictionaries_ in Julia have the parameterized type `Dict{S,T}`, where `S` is the type of _keys_ and `T` is the type of _values_.
Man kann sie explizit anlegen:
They can be created explicitly:
```{julia}
# Einwohner 2020 in Millionen, Quelle: wikipedia
# Population in 2020 in millions, source: wikipedia
EW = Dict("Berlin" => 3.66, "Hamburg" => 1.85,
"München" => 1.49, "Köln" => 1.08)
@@ -180,29 +176,29 @@ EW = Dict("Berlin" => 3.66, "Hamburg" => 1.85,
typeof(EW)
```
und mit den _keys_ indizieren:
and indexed with the _keys_:
```{julia}
EW["Berlin"]
```
Das Abfragen eines nicht existierenden _keys_ ist natürlich ein Fehler.
Of course, querying a non-existent _key_ is an error.
```{julia}
EW["Leipzig"]
```
Man kann ja auch vorher mal anfragen...
You can also ask beforehand...
```{julia}
haskey(EW, "Leipzig")
```
... oder die Funktion `get(dict, key, default)` benutzen, die bei nicht existierendem Key keinen Fehler wirft sondern das 3. Argument zurückgibt.
... or use the function `get(dict, key, default)`, which does not throw an error for non-existent keys but returns the third argument.
```{julia}
@show get(EW, "Leipzig", -1) get(EW, "Berlin", -1);
```
Man kann sich auch alle `keys` und `values` als spezielle Container geben lassen.
You can also request all `keys` and `values` as special containers.
```{julia}
keys(EW)
```
@@ -213,24 +209,24 @@ values(EW)
```
Man kann über die `keys` iterieren...
You can iterate over the `keys`...
```{julia}
for i in keys(EW)
n = EW[i]
println("Die Stadt $i hat $n Millionen Einwohner.")
println("The city $i has $n million inhabitants.")
end
```
odere gleich über `key-value`-Paare.
or directly over `key-value` pairs.
```{julia}
for (stadt, ew) ∈ EW
println("$stadt : $ew Mill.")
println("$stadt : $ew Million.")
end
```
### Erweitern und Modifizieren
### Extending and Modifying
Man kann in ein `Dict` zusätzliche `key-value`-Paare eintragen...
You can add additional `key-value` pairs to a `Dict`...
```{julia}
EW["Leipzig"] = 0.52
EW["Dresden"] = 0.52
@@ -238,42 +234,42 @@ EW
```
und einen `value` ändern.
and change a `value`.
```{julia}
# Oh, das war bei Leipzig die Zahl von 2010, nicht 2020
# Oh, the Leipzig number was from 2010, not 2020
EW["Leipzig"] = 0.597
EW
```
Ein Paar kann über seinen `key` auch gelöscht werden.
A pair can also be deleted via its `key`.
```{julia}
delete!(EW, "Dresden")
```
Zahlreiche Funktionen können mit `Dicts` wie mit anderen Containern arbeiten.
Many functions can work with `Dicts` like with other containers.
```{julia}
maximum(values(EW))
```
### Anlegen eines leeren Dictionaries
### Creating an Empty Dictionary
Ohne Typspezifikation ...
Without type specification ...
```{julia}
d1 = Dict()
```
und mit Typspezifikation:
and with type specification:
```{julia}
d2 = Dict{String, Int}()
```
### Umwandlung in Vektoren: `collect()`
### Conversion to Vectors: `collect()`
- `keys(dict)` und `values(dict)` sind spezielle Datentypen.
- Die Funktion `collect()` macht daraus eine Liste vom Typ `Vector`.
- `collect(dict)` liefert eine Liste vom Typ `Vector{Pair{S,T}}`
- `keys(dict)` and `values(dict)` are special data types.
- The function `collect()` converts them to a `Vector` type.
- `collect(dict)` returns a list of type `Vector{Pair{S,T}}`
```{julia}
@@ -285,55 +281,55 @@ collect(EW)
collect(keys(EW)), collect(values(EW))
```
### Geordnetes Iterieren über ein Dictionary
### Ordered Iteration over a Dictionary
Wir sortieren die Keys. Als Strings werden sie alphabetisch sortiert. Mit dem `rev`-Parameter wird rückwärts sortiert.
We sort the keys. As strings, they are sorted alphabetically. With the `rev` parameter, sorting is done in reverse order.
```{julia}
for k in sort(collect(keys(EW)), rev = true)
n = EW[k]
println("$k hat $n Millionen Einw. ")
println("$k has $n million inhabitants ")
end
```
Wir sortieren `collect(dict)`. Das ist ein Vektor von Paaren. Mit `by` definieren wir, wonach zu sortieren ist: nach dem 2. Element des Paares.
We sort `collect(dict)`. This is a vector of pairs. With `by` we define what to sort by: the second element of the pair.
```{julia}
for (k,v) in sort(collect(EW), by = pair -> last(pair), rev=false)
println("$k hat $v Mill. EW")
println("$k has $v million inhabitants")
end
```
### Eine Anwendung von Dictionaries: Zählen von Häufigkeiten
### An Application of Dictionaries: Counting Frequencies
Wir machen 'experimentelle Stochastik' mit 2 Würfeln:
We do "experimental probability" with 2 dice:
Gegeben sei `l`, eine Liste mit den Ergebnissen von 100 000 Pasch-Würfen, also 100 000 Zahlen zwischen 2 und 12.
Given `l`, a list with the results of 100,000 double dice rolls, i.e., 100,000 numbers between 2 and 12.
Wie häufig sind die Zahlen 2 bis 12?
How frequently do the numbers 2 to 12 occur?
Wir (lassen) würfeln:
We (let) roll:
```{julia}
l = rand(1:6, 100_000) .+ rand(1:6, 100_000)
```
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`.
We count the frequencies of the events using a dictionary. We take the event as the `key` and its frequency as the `value`.
```{julia}
# In diesem Fall könnte man das auch mit einem einfachen Vektor
# lösen. Eine bessere Illustration wäre z.B. Worthäufigkeit in
# einem Text. Dann ist i keine ganze Zahl sondern ein Wort=String
# In this case, one could also solve this with a simple vector.
# A better illustration would be, e.g., word frequency in
# a text. Then i is not an integer but a word=string
d = Dict{Int,Int}() # das Dict zum 'reinzählen'
d = Dict{Int,Int}() # the dict for counting
for i in l # für jedes i wird d[i] erhöht.
for i in l # for each i, d[i] is incremented.
d[i] = get(d, i, 0) + 1
end
d
```
Das Ergebnis:
The result:
```{julia}
using Plots
@@ -341,7 +337,6 @@ using Plots
plot(collect(keys(d)), collect(values(d)), seriestype=:scatter)
```
##### Das Erklär-Bild dazu:
##### The explanatory image:
[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)

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
engine: julia
---
# Funktionen und Operatoren
# Functions and Operators
```{julia}
#| error: false
@@ -18,36 +18,36 @@ Base.active_module() = myactive_module()
```
Funktionen verarbeiten ihre Argumente zu einem Ergebnis, das sie beim Aufruf zurückliefern.
Functions process their arguments to produce a result, which they return when called.
## Formen
## Forms
Funktionen können in verschiedenen Formen definiert werden:
Functions can be defined in different forms:
I. Als `function ... end`-Block
I. As a `function ... end` block
```{julia}
function hyp(x,y)
sqrt(x^2+y^2)
end
```
II. Als "Einzeiler"
II. As a "single-liner"
```{julia}
hyp(x, y) = sqrt(x^2 + y^2)
```
III. Als anonyme Funktionen
III. As anonymous functions
```{julia}
(x, y) -> sqrt(x^2 + y^2)
```
### Block-Form und `return`
### Block Form and `return`
- Mit `return` wird die Abarbeitung der Funktion beendet und zum aufrufenden Kontext zurückgekehrt.
- Ohne `return` wird der Wert des letzten Ausdrucks als Funktionswert zurückgegeben.
- With `return`, function execution is terminated and control returns to the calling context.
- Without `return`, the value of the last expression is returned as the function value.
Die beiden Definitionen
The two definitions
```julia
function xsinrecipx(x)
@@ -57,7 +57,7 @@ function xsinrecipx(x)
return x * sin(1/x)
end
```
und ohne das zweite explizite `return` in der letzten Zeile:
and without the second explicit `return` in the last line:
```julia
function xsinrecipx(x)
@@ -68,11 +68,11 @@ function xsinrecipx(x)
end
```
sind also äquivalent.
are therefore equivalent.
- Eine Funktion, die "nichts" zurückgibt (_void functions_ in der C-Welt), gibt den Wert `nothing` vom Typ `Nothing` zurück. (So wie ein Objekt vom Typ `Bool` die beiden Werte `true` und `false` haben kann, so kann ein Objekt vom Typ `Nothing` nur einen einzigen Wert, eben `nothing`, annehmen.)
- Eine leere `return`-Anweisung ist äquivalent zu `return nothing`.
- A function that returns "nothing" (_void functions_ in the C world) returns the value `nothing` of type `Nothing`. (Just as an object of type `Bool` can have two values, `true` and `false`, an object of type `Nothing` can only take a single value, namely `nothing`.)
- An empty `return` statement is equivalent to `return nothing`.
```{julia}
@@ -95,27 +95,27 @@ a
```
### Einzeiler-Form
### Single-liner Form
Die Einzeilerform ist eine ganz normale Zuweisung, bei der links eine Funktion steht.
The single-liner form is a normal assignment where a function stands on the left side.
```julia
hyp(x, y) = sqrt(x^2 + y^2)
```
Julia kennt zwei Möglichkeiten, mehrere Anweisungen zu einem Block zusammenzufassen, der an Stelle einer Einzelanweisung stehen kann:
Julia knows two ways to combine multiple statements into a block that can stand in place of a single statement:
- `begin ... end`-Block
- Eingeklammerte durch Semikolon getrennte Anweisungen.
- `begin ... end` block
- Parenthesized statements separated by semicolons.
In beiden Fällen ist der Wert des Blockes der Wert der letzten Anweisung.
In both cases, the value of the block is the value of the last statement.
Damit funktioniert auch
Thus, the following also works:
```julia
hyp(x, y) = (z = x^2; z += y^2; sqrt(z))
```
und
and
```julia
hyp(x, y) = begin
z = x^2
@@ -124,15 +124,15 @@ hyp(x, y) = begin
end
```
### Anonyme Funktionen
### Anonymous Functions
Anonyme FUnktionen kann man der Anonymität entreisen, indem man ihnen einen Namen zuweist.
Anonymous functions can be "rescued from anonymity" by assigning them a name.
```julia
hyp = (x,y) -> sqrt(x^2 + y^2)
```
Ihre eigentliche Anwendung ist aber im Aufruf einer *(higher order)* Funktion, die eine Funktion als Argument erwartet.
Their actual application is in calling a *(higher order)* function that expects a function as an argument.
Typische Anwendungen sind `map(f, collection)`, welches eine Funktion auf alle Elemente einer Kollektion anwendet. In Julia funktioniert auch `map(f(x,y), collection1, collection2)`:
Typical applications are `map(f, collection)`, which applies a function to all elements of a collection. In Julia, `map(f(x,y), collection1, collection2)` also works:
```{julia}
map( (x,y) -> sqrt(x^2 + y^2), [3, 5, 8], [4, 12, 15])
@@ -142,24 +142,24 @@ map( (x,y) -> sqrt(x^2 + y^2), [3, 5, 8], [4, 12, 15])
map( x->3x^3, 1:8 )
```
Ein weiteres Beispiel ist `filter(test, collection)`, wobei ein Test eine Funktion ist, die ein `Bool` zurückgibt.
Another example is `filter(test, collection)`, where a test is a function that returns a `Bool`.
```{julia}
filter(x -> ( x%3 == 0 && x%5 == 0), 1:100 )
```
## Argumentübergabe
## Argument Passing
- Beim Funktionsaufruf werden von den als Funktionsargumente zu übergebenden Objekten keine Kopien gemacht. Die Variablen in der Funktion verweisen auf die Originalobjekte. Julia nennt dieses Konzept _pass_by_sharing_.
- Funktionen können also ihre Argumente wirksam modifizieren, falls es sich um _mutable_ Objekte, wie z.B. `Vector`, `Array` handelt.
- Es ist eine Konvention in Julia, dass die Namen von solchen argumentmodifizierenden Funktionen mit einem Ausrufungszeichen enden. Weiterhin steht dann üblicherweise das Argument, das modifiziert wird, an erster Stelle und es ist auch der Rückgabewert der Funktion.
- When calling a function, no copies are made of the objects passed as function arguments. Variables in the function refer to the original objects. Julia calls this concept _pass_by_sharing_.
- Functions can therefore effectively modify their arguments if they are _mutable_ objects, such as `Vector` or `Array`.
- It is a convention in Julia that the names of such argument-modifying functions end with an exclamation mark. Furthermore, the argument that is modified is usually first and is also the return value of the function.
```{julia}
V = [1, 2, 3]
W = fill!(V, 17)
# '===' ist Test auf Identität
@show V W V===W; # V und W benennen dasselbe Objekt
# '===' is test for identity
@show V W V===W; # V and W refer to the same object
```
```{julia}
@@ -175,16 +175,16 @@ U = fill_first!(V, 42)
## Varianten von Funktionsargumenten
## Variants of Function Arguments
- Es gibt Positionsargumente (1. Argument, 2. Argument, ....) und _keyword_-Argumente, die beim Aufruf durch ihren Namen angesprochen werden müssen.
- Sowohl Positions- als auch _keyword_-Argumente können _default_-Werte haben. Beim Aufruf können diese Argumente weggelassen werden.
- Die Reihenfolge der Deklaration muss sein:
1. Positionsargumente ohne Defaultwert,
2. Positionsargumente mit Defaultwert,
3. --- Semikolon ---,
4. kommagetrennte Liste der Keywordargumente (mit oder ohne Defaultwert)
- Beim Aufruf können _keyword_-Argumente an beliebigen Stellen in beliebiger Reihenfolge stehen. Man kann sie wieder durch ein Semikolon von den Positionsargumenten abtrennen, muss aber nicht.
- There are positional arguments (1st argument, 2nd argument, ...) and _keyword_ arguments, which must be addressed by name when calling.
- Both positional and _keyword_ arguments can have _default_ values. These arguments can be omitted when calling.
- The order of declaration must be:
1. Positional arguments without default value,
2. Positional arguments with default value,
3. --- semicolon ---,
4. comma-separated list of keyword arguments (with or without default value)
- When calling, _keyword_ arguments can appear at any position in any order. You can separate them from positional arguments with a semicolon, but you don't have to.
```{julia}
fa(x, y=42; a) = println("x=$x, y=$y, a=$a")
@@ -194,7 +194,7 @@ fa(6, 7; a=4)
fa(a=-2, 6)
```
Eine Funktion nur mit _keyword_-Argumenten wird so deklariert:
A function with only _keyword_ arguments is declared as follows:
```{julia}
fkw(; x=10, y) = println("x=$x, y=$y")
@@ -204,9 +204,9 @@ fkw(y=2)
## Funktionen sind ganz normale Objekte
## Functions are Normal Objects
- Sie können zugewiesen werden
- They can be assigned
```{julia}
@@ -215,11 +215,11 @@ f2(2)
```
- Sie können als Argumente an Funktionen übergeben werden.
- They can be passed as arguments to functions.
```{julia}
# sehr naive numerische Integration
# very naive numerical integration
function Riemann_integrate(f, a, b; NInter=1000)
delta = (b-a)/NInter
@@ -235,7 +235,7 @@ Riemann_integrate(sin, 0, π)
```
- Sie können von Funktionen erzeugt und als Ergebnis `return`t werden.
- They can be created by functions and returned as results.
@@ -263,16 +263,16 @@ h(1)
h(2), h(10)
```
Die obige Funktion `generate_add_func()` lässt sich auch kürzer definieren. Der innere Funktionsname `addx()` ist sowieso lokal und außerhalb nicht verfügbar. Also kann man eine anonyme Funktion verwenden.
The above function `generate_add_func()` can also be defined more briefly. The inner function name `addx()` is anyway local and not available outside. So one can use an anonymous function.
```{julia}
generate_add_func(x) = y -> x + y
```
## Zusammensetzung von Funktionen: die Operatoren $\circ$ und `|>`
## Function Composition: the Operators $\circ$ and `|>`
- Die Zusammensetzung _(composition)_ von Funktionen kann auch mit dem Operator $\circ$ (`\circ + Tab`) geschrieben werden
- Function composition can also be written with the $\circ$ operator (`\circ + Tab`)
$$(f\circ g)(x) = f(g(x))$$
@@ -289,11 +289,11 @@ f(.2)
```{julia}
@show map(uppercase ∘ first, ["ein", "paar", "grüne", "Blätter"]);
@show map(uppercase ∘ first, ["one", "a", "green", "leaves"]);
```
- Es gibt auch einen Operator, mit dem Funktionen "von rechts" wirken und zusammengesetzt werden können _(piping)_
- There is also an operator with which functions can act "from the right" and be composed (_piping_)
```{julia}
@@ -306,37 +306,37 @@ f(.2)
```
- Natürlich kann man auch diese Operatoren 'broadcasten' (s. @sec-broadcast). Hier wirkt ein Vektor von Funktionen elementweise auf einen Vektor von Argumenten:
- Of course, you can also 'broadcast' these operators (see @sec-broadcast). Here a vector of functions acts element-wise on a vector of arguments:
```{julia}
["a", "list", "of", "strings"] .|> [length, uppercase, reverse, titlecase]
```
## Die `do`-Notation {#sec-do}
## The `do` Notation {#sec-do}
Eine syntaktische Besonderheit zur Definition anonymer Funktionen als Argumente anderer Funktionen ist die `do`-Notation.
A syntactic peculiarity for defining anonymous functions as arguments of other functions is the `do` notation.
Sei `higherfunc(f,a,...)` eine Funktion, deren 1. Argument eine Funktion ist.
Let `higherfunc(f,a,...)` be a function whose first argument is a function.
Dann kann man `higherfunc()` auch ohne erstes Argument aufrufen und statt dessen die Funktion in einem unmittelbar folgenden `do`-Block definieren:
Then you can also call `higherfunc()` without the first argument and instead define the function in an immediately following `do` block:
```julia
higherfunc(a, b) do x, y
Körper von f(x,y)
body of f(x,y)
end
```
Am Beispiel von `Riemann_integrate()` sieht das so aus:
Using `Riemann_integrate()` as an example, this looks like this:
```{julia}
# das ist dasselbe wie Riemann_integrate(x->x^2, 0, 2)
# this is the same as Riemann_integrate(x->x^2, 0, 2)
Riemann_integrate(0, 2) do x x^2 end
```
Der Sinn besteht natürlich in der Anwendung mit komplexeren Funktionen, wie diesem aus zwei Teilstücken zusammengesetzten Integranden:
The purpose is of course in the application with more complex functions, such as this integrand composed of two parts:
```{julia}
r = Riemann_integrate(0, π) do x
z1 = sin(x)
@@ -349,12 +349,12 @@ r = Riemann_integrate(0, π) do x
end
```
## Funktionsartige Objekte
## Function-like Objects
Durch Definition einer geeigneten Methode für einen Typ kann man beliebige Objekte *callable* machen, d.h., sie anschließend wie Funktionen aufrufen.
By defining a suitable method for a type, arbitrary objects can be made *callable*, i.e., callable like functions afterwards.
```{julia}
# struct speichert die Koeffiziente eines Polynoms 2. Grades
# struct stores the coefficients of a 2nd degree polynomial
struct Poly2Grad
a0::Float64
a1::Float64
@@ -365,13 +365,13 @@ p1 = Poly2Grad(2,5,1)
p2 = Poly2Grad(3,1,-0.4)
```
Die folgende Methode macht diese Struktur `callable`.
The following method makes this structure `callable`.
```{julia}
function (p::Poly2Grad)(x)
p.a2 * x^2 + p.a1 * x + p.a0
end
```
Jetzt kann man die Objekte, wenn gewünscht, auch wie Funktionen verwenden.
Now the objects can, if desired, also be used like functions.
```{julia}
@show p2(5) p1(-0.7) p1;
@@ -379,9 +379,9 @@ Jetzt kann man die Objekte, wenn gewünscht, auch wie Funktionen verwenden.
## Operatoren und spezielle Formen
## Operators and Special Forms
- Infix-Operatoren wie `+,*,>,∈,...` sind Funktionen.
- Infix operators like `+,*,>,∈,...` are functions.
@@ -399,7 +399,7 @@ f = +
f(3, 7)
```
- Auch Konstruktionen wie `x[i]`, `a.x`, `[x; y]` werden vom Parser zu Funktionsaufrufen umgewandelt.
- Even constructions like `x[i]`, `a.x`, `[x; y]` are converted by the parser to function calls.
:::{.narrow}
@@ -410,53 +410,53 @@ f(3, 7)
| a.x | getproperty(a, :x) |
| a.x = z | setproperty!(a, :x, z) |
| [x; y;...] | vcat(x, y, ...) |
:Spezielle Formen [(Auswahl)](https://docs.julialang.org/en/v1/manual/functions/#Operators-With-Special-Names)
:Special Forms [(selection)](https://docs.julialang.org/en/v1/manual/functions/#Operators-With-Special-Names)
:::
(Der Doppelpunkt vor einer Variablen macht diese zu einem Symbol.)
(The colon before a variable makes it into a symbol.)
:::{.callout-note}
Für diese Funktionen kann man eigene Methoden implementieren. Zum Beispiel könnten bei einem eigenen Typ das Setzen eines Feldes (`setproperty!()`) die Gültigkeit des Wertes prüfen oder weitere Aktionen veranlassen.
For these functions, one can implement one's own methods. For example, for a custom type, setting a field (`setproperty!()`) could check the validity of the value or trigger further actions.
Prinzipiell können `get/setproperty` auch Dinge tun, die gar nichts mit einem tatsächlich vorhandenen Feld der Struktur zu tun haben.
In principle, `get/setproperty` can also do things that have nothing to do with an actually existing field of the structure.
:::
## Update-Form
## Update Form
Alle arithmetischen Infix-Operatoren haben eine update-Form: Der Ausdruck
All arithmetic infix operators have an update form: The expression
```julia
x = x ⊙ y
```
kann auch geschrieben werden als
can also be written as
```julia
x ⊙= y
```
Beide Formen sind semantisch äquivalent. Insbesondere wird in beiden Formen der Variablen `x` ein auf der rechten Seite geschaffenes neues Objekt zugewiesen.
Both forms are semantically equivalent. In particular, in both forms, a new object created on the right side is assigned to the variable `x`.
Ein Speicherplatz- und Zeit-sparendes __in-place-update__ eines Arrays/Vektors/Matrix ist möglich entweder durch explizite Indizierung
Memory- and time-saving __in-place-update__ of an array/vector/matrix is possible either through explicit indexing
```julia
for i in eachindex(x)
x[i] += y[i]
end
```
oder durch die dazu semantisch äquivalente _broadcast_-Form (s. @sec-broadcast):
or through the semantically equivalent _broadcast_ form (see @sec-broadcast):
```julia
x .= x .+ y
```
## Vorrang und Assoziativität von Operatoren {#sec-vorrang}
## Operator Precedence and Associativity {#sec-vorrang}
Zu berechnende Ausdrücke
Expressions to be computed
```{julia}
-2^3+500/2/10==8 && 13 > 7 + 1 || 9 < 2
```
werden vom Parser in eine Baumstruktur überführt.
are converted by the parser into a tree structure.
```{julia}
using TreeView
@@ -464,75 +464,75 @@ walk_tree(Meta.parse("-2^3+500/2/10==8 && 13 > 7 + 1 || 9 < 2"))
```
- Die Auswertung solcher Ausdrücke wird durch
- Vorrang _(precedence)_ und
- Assoziativität geregelt.
- 'Vorrang' definiert, welche Operatoren stärker binden im Sinne von "Punktrechnung geht vor Strichrechnung".
- 'Assoziativität' bestimmt die Auswertungsreihenfolge bei gleichen oder gleichrangigen Operatoren.
- [Vollständige Dokumentation](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Operator-Precedence-and-Associativity)
- The evaluation of such expressions is regulated by
- precedence and
- associativity.
- 'Precedence' defines which operators bind more strongly in the sense of "multiplication and division before addition and subtraction".
- 'Associativity' determines the evaluation order for operators of equal or same rank.
- [Complete documentation](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Operator-Precedence-and-Associativity)
### Assoziativität
### Associativity
Sowohl Addition und Subtraktion als auch Multiplikation und Divison sind jeweils gleichrangig und linksassoziativ, d.h. es wird von links ausgewertet.
Both addition and subtraction as well as multiplication and division are each of equal rank and left-associative, i.e., they are evaluated from left to right.
```{julia}
200/5/2 # wird von links ausgewertet als (200/5)/2
200/5/2 # evaluated left to right as (200/5)/2
```
```{julia}
200/2*5 # wird von links ausgewertet als (200/2)*5
200/2*5 # evaluated left to right as (200/2)*5
```
Zuweisungen wie `=`, `+=`, `*=`,... sind gleichrangig und rechtsassoziativ.
Assignments like `=`, `+=`, `*=`,... are of equal rank and right-associative.
```{julia}
x = 1
y = 10
# wird von rechts ausgewertet: x += (y += (z = (a = 20)))
# evaluated right to left: x += (y += (z = (a = 20)))
x += y += z = a = 20
@show x y z a;
```
Natürlich kann man die Assoziativität in Julia auch abfragen. Die entsprechenden Funktionen werden nicht explizit aus dem `Base`-Modul exportiert, deshalb muss man den Modulnamen beim Aufruf angeben.
Of course, you can also query the associativity in Julia. The corresponding functions are not explicitly exported from the `Base` module, so the module name must be specified when calling.
```{julia}
for i in (:/, :+=, :(=), :^)
a = Base.operator_associativity(i)
println("Operation $i is $(a)-assoziative")
println("Operation $i is $(a)-associative")
end
```
Also ist der Potenzoperator rechtsassoziativ.
So the power operator is right-associative.
```{julia}
2^3^2 # rechtsassoziativ, = 2^(3^2)
2^3^2 # right-associative, = 2^(3^2)
```
### Vorrang
### Precedence
- Julia ordnet den Operatoren Vorrangstufen von 1 bis 17 zu:
- Julia assigns operator precedence levels from 1 to 17:
```{julia}
for i in (:+, :-, :*, :/, :^, :(=))
p = Base.operator_precedence(i)
println("Vorrang von $i = $p")
println("Precedence of $i = $p")
end
```
- 11 ist kleiner als 12, also geht 'Punktrechnung vor Strichrechnung'
- Der Potenz-Operator `^` hat eine höhere _precedence_.
- Zuweisungen haben die kleinste _precedence_
- 11 is less than 12, so 'multiplication and division before addition and subtraction'
- The power operator `^` has a higher _precedence_.
- Assignments have the smallest _precedence_
```{julia}
# Zuweisung hat kleinsten Vorrang, daher Auswertung als x = (3 < 4)
# assignment has smallest precedence, therefore evaluation as x = (3 < 4)
x = 3 < 4
x
@@ -540,11 +540,11 @@ x
```{julia}
(y = 3) < 4 # Klammern schlagen natürlich jeden Vorrang
(y = 3) < 4 # parentheses当然 override any precedence
y
```
Nochmal zum Beispiel vom Anfang von @sec-vorrang:
Once more to the example from the beginning of @sec-vorrang:
```{julia}
-2^3+500/2/10==8 && 13 > 7 + 1 || 9 < 2
@@ -557,43 +557,43 @@ for i ∈ (:^, :+, :/, :(==), :&&, :>, :|| )
println(Base.operator_precedence(i))
end
```
Nach diesen Vorrangregeln wird der Beispielausdruck also wie folgt ausgewertet:
According to these precedence rules, the example expression is evaluated as follows:
```{julia}
((-(2^3)+((500/2)/10)==8) && (13 > (7 + 1))) || (9 < 2)
```
(Das entspricht natürlich dem oben gezeigten *parse-tree*)
(This of course corresponds to the *parse-tree* shown above)
Es gilt also für den Vorrang:
So the precedence is:
> Potenz > Multiplikation/Division > Addition/Subtraktion > Vergleiche > logisches && > logisches || > Zuweisung
> Power > Multiplication/Division > Addition/Subtraction > Comparisons > logical && > logical || > assignment
Damit wird ein Ausdruck wie
Thus, an expression like
```julia
a = x <= y + z && x > z/2
```
sinnvoll ausgewertet als `a = ((x <= (y+z)) && (x < (z/2)))`
is sensibly evaluated as `a = ((x <= (y+z)) && (x < (z/2)))`
- Eine Besonderheit sind noch
- unäre Operatoren, also insbesondere `+` und `-` als Vorzeichen
- _juxtaposition_, also Zahlen direkt vor Variablen oder Klammern ohne `*`-Symbol
Beide haben Vorrang noch vor Multiplikation und Division.
- A special case is still
- unary operators, in particular `+` and `-` as signs
- _juxtaposition_, i.e., numbers directly before variables or parentheses without `*` symbol
Both have precedence even before multiplication and division.
:::{.callout-important}
Damit ändert sich die Bedeutung von Ausdrücken, wenn man _juxtaposition_ anwendet:
Therefore, the meaning of expressions changes when one applies _juxtaposition_:
```{julia}
1/2*π, 1/2π
```
:::
- Im Vergleich zum Potenzoperator `^` gilt (s. [https://discourse.julialang.org/t/confused-about-operator-precedence-for-2-3x/8214/7](https://discourse.julialang.org/t/confused-about-operator-precedence-for-2-3x/8214/7) ):
- Compared to the power operator `^` (see [https://discourse.julialang.org/t/confused-about-operator-precedence-for-2-3x/8214/7](https://discourse.julialang.org/t/confused-about-operator-precedence-for-2-3x/8214/7) ):
> Unary operators, including juxtaposition, bind tighter than ^ on the right but looser on the left.
Beispiele:
Examples:
```{julia}
-2^2 # -(2^2)
```
@@ -615,28 +615,26 @@ x = 5
```
- Funktionsanwendung `f(...)` hat Vorrang vor allen Operatoren
- Function application `f(...)` has precedence over all operators
```{julia}
sin(x)^2 === (sin(x))^2 # nicht sin(x^2)
sin(x)^2 === (sin(x))^2 # not sin(x^2)
```
### Zusätzliche Operatoren
### Additional Operators
Der [Julia-Parser](https://github.com/JuliaLang/julia/blob/master/src/julia-parser.scm#L13-L31) definiert für zahlreiche Unicode-Zeichen einen Vorrang auf Vorrat, so dass diese Zeichen von Paketen und selbstgeschriebenem Code als Operatoren benutzt werden können.
The [Julia parser](https://github.com/JuliaLang/julia/blob/master/src/julia-parser.scm#L13-L31) assigns precedence to numerous Unicode characters in advance, so that these characters can be used as operators by packages and self-written code.
So haben z.B.
Thus, for example,
```julia
∧ ⊗ ⊘ ⊙ ⊚ ⊛ ⊠ ⊡ ⊓ ∙ ∤ ⅋ ≀ ⊼ ⋄ ⋆ ⋇ ⋉ ⋊ ⋋ ⋌ ⋏ ⋒ ⟑ ⦸ ⦼ ⦾ ⦿ ⧶ ⧷ ⨇ ⨰ ⨱ ⨲ ⨳ ⨴ ⨵ ⨶ ⨷ ⨸ ⨻ ⨼ ⨽ ⩀ ⩃ ⩄ ⩋ ⩍ ⩎ ⩑ ⩓ ⩕ ⩘ ⩚ ⩜ ⩞ ⩟ ⩠ ⫛
```
den Vorrang 12 wie Multiplikation/Division (und sind wie diese linksassoziativ)
und z.B.
have precedence 12 like multiplication/division (and are left-associative like these)
and for example
```julia
⊕ ⊖ ⊞ ⊟ |++| ⊔ ± ∓ ∔ ∸ ≏ ⊎ ⊻ ⊽ ⋎ ⋓ ⧺ ⧻ ⨈ ⨢ ⨣ ⨤ ⨥ ⨦ ⨧ ⨨ ⨩ ⨪ ⨫ ⨬ ⨭ ⨮ ⨹ ⨺ ⩁ ⩂ ⩅ ⩊ ⩌ ⩏ ⩐ ⩒ ⩔ ⩖ ⩗
⊕ ⊖ ⊞ ⊟ |++| ⊔ ± ∓ ∔ ∸ ≏ ⊎ ⊻ ⊽ ⋎ ⋓ ⧺ ⧻ ⨈ ⨢ ⨣ ⨤ ⨥ ⨦ ⨧ ⨨ ⨩ ⨪ ⨫ ⨬ ⨭ ⨮ ⨹ ⨺ ⩁ ⩂ ⩅ ⩊ ⩌ ⩏ ⩐ ⩒ ⩔ ⩖ ⩗
```
haben den Vorrang 11 wie Addition/Subtraktion.
have precedence 11 like addition/subtraction.

View File

@@ -9,48 +9,49 @@ engine: julia
using InteractiveUtils
```
# Erste Miniprogramme
# First Small Programs
## Was sollte man zum Programmieren können?
## What Skills Are Needed for Programming?
- **Denken in Algorithmen:**
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?
- **Umsetzung des Algorithmus in ein Programm:**
Welche Datenstrukturen, Konstrukte, Funktionen... stellt die Programmiersprache bereit?
- **Formale Syntax:**
Menschen verstehen 'broken English'; Computer verstehen kein 'broken C++' oder 'broken Julia'. Die Syntax muss beherrscht werden.
- **„Ökosystem“ der Sprache:**
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?
- **die Kunst des Debugging:**
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.
- **Gefühl für die Effizienz und Komplexität von Algorithmen**
- **Besonderheiten der Computerarithmetik**, insbesondere der Gleitkommazahlen
- **Thinking in algorithms:**
What steps are required to solve the problem? What data must be stored, what data structures must be created? What cases can occur and must be recognized and handled?
- **Implementation of the algorithm into a program:**
What data structures, constructs, functions... does the programming language provide?
- **Formal syntax:**
Humans understand 'broken English'; computers don't understand 'broken C++' or 'broken Julia'. The syntax must be mastered.
- **The "ecosystem" of the language:**
How do I run my code? How do the development environments work? What options does the compiler understand? How do I install additional libraries? How do I read error messages? Where can I get information?
- **The art of debugging:**
Programming beginners are often happy when they have eliminated all syntax errors and the program finally 'runs'. For more complex programs, the work only just begins, as testing and finding and fixing errors in the algorithm must now be done.
- **Sense of the efficiency and complexity of algorithms**
- **Specifics of computer arithmetic**, especially floating point numbers
Das erschließt sich nicht alles auf einmal. Haben Sie Geduld mit sich und 'spielen' Sie mit der Sprache.
These cannot all be mastered at once. Be patient with yourself and 'play' with the language.
The following examples should serve as inspiration.
Das Folgende soll eine kleine Anregung dazu sein.
## Project Euler
Eine hübsche Quelle für Programmieraufgaben mit mathematischem Charakter und sehr unterschiedlichen Schwierigkeitsgraden ist [Project Euler](https://projecteuler.net/).
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.
A nice source for programming tasks with mathematical character and very different levels of difficulty is [Project Euler](https://projecteuler.net/).
The tasks are designed so that no inputs are necessary and the desired result is a single number. This allows you to fully concentrate on programming the algorithm.
---------
### Beispiel 1
### Example 1
::::::{.content-hidden unless-format="xxx"}
::::::::{.content-hidden unless-format="xxx"}
https://github.com/luckytoilet/projecteuler-solutions/blob/master/Solutions.md
https://math.stackexchange.com/questions/3370978/iterating-sum-of-squares-of-decimal-digits-of-an-integer-how-big-can-it-grow
aufg. 92
Aufg. 92
:::
::: {.callout-note icon=false .titlenormal}
## Project Euler Problem No 1
## Project Euler Problem No. 1
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.
@@ -58,36 +59,36 @@ Find the sum of all the multiples of 3 or 5 below 1000.
:::
1. Algorithmus:
- Teste alle natürlichen Zahlen <1000 auf Teilbarkeit durch 3 oder durch 5 und
- summiere die teilbaren Zahlen auf.
1. Algorithm:
- Test all natural numbers <1000 for divisibility by 3 or 5 and
- sum the divisible numbers.
2. Umsetzung:
2. Implementation:
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`.
Wie testet man eine Reihe von Werten durch und summiert auf? Da gibt es ein Standardmuster: `for`-Schleife und Akkumulatorvariable:
How does Julia provide the remainder of integer division? Functions like this are typically called `rem()` (for *remainder*) or `mod()`. You can look it up in the documentation or try `?rem` and `?mod` in the Julia REPL. Both functions exist; the difference lies in the treatment of negative integers. For natural numbers `n,m`, `mod(n,m)` and `rem(n,m)` give the same result, and the latter also has the infix form `n % m`.
How does one test a sequence of values and sum them up? There is a standard pattern: `for` loop and accumulator variable:
:::{.callout-caution icon="false" collapse="true" .titlenormal}
## Eine Lösungsvariante:
## One possible solution:
```{julia}
s = 0 # Akkumulatorvariable initialisieren
for i in 1:999 # Schleife
if i % 3 == 0 || i % 5 == 0 # Test
s += i # Zu Akkumulator addieren
end # Ende Test
end # Ende Schleife
println(" Die Antwort ist: $s") # Ausgabe des Ergebnisses
s = 0 # initialize accumulator variable
for i in 1:999 # loop
if i % 3 == 0 || i % 5 == 0 # test
s += i # add to accumulator
end # end test
end # end loop
println(" The answer is: $s") # output result
```
:::
Natürlich geht das auch etwas kürzer:
Of course, this can also be done a bit shorter:
:::{.callout-caution icon="false" collapse="true" .titlenormal}
## Noch eine Lösungsvariante:
## Another solution:
```{julia}
sum([i for i in 1:999 if i%3==0||i%5==0])
@@ -98,11 +99,11 @@ sum([i for i in 1:999 if i%3==0||i%5==0])
-----------
### Beispiel 2
### Example 2
::: {.callout-note icon=false .titlenormal}
## Project Euler Problem No 92
## Project Euler Problem No. 92
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.
For example,
@@ -115,41 +116,41 @@ Therefore any chain that arrives at 1 or 89 will become stuck in an endless loop
How many starting numbers below ten million will arrive at 89?
:::
Programme kann man [*top-down* und *bottom-up*](https://de.wikipedia.org/wiki/Top-Down-_und_Bottom-Up-Design) entwickeln.
*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.)
Programs can be developed [*top-down* and *bottom-up*](https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design).
*Top-down* would probably mean here: "We start with a loop `for i = 1:9999999`." The other way leads over individually testable components and is often more effective. (And with a certain project size, one approaches the goal from both 'top' and 'bottom' simultaneously.)
##### Funktion Nr. 1
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.
##### Function No. 1
It should be investigated how numbers behave under repeated calculation of the 'square digit sum' (sum of squares of digits). Therefore, one should write and test a function that calculates this 'square digit sum'.
:::{.callout-caution icon="false" collapse="true" .titlenormal}
## `q2sum(n)` berechnet die Summe der Quadrate der Ziffern von n im Dezimalsystem:
## `q2sum(n)` calculates the sum of the squares of the digits of n in the decimal system:
```{julia}
#| output: false
function q2sum(n)
s = 0 # Akkumulator für die Summe
while n > 9 # solange noch mehrstellig...
q, r = divrem(n, 10) # berechne Ganzzahlquotient und Rest bei Division durch 10
s += r^2 # addiere quadrierte Ziffer zum Akkumulator
n = q # mache weiter mit der durch 10 geteilten Zahl
s = 0 # accumulator for the sum
while n > 9 # as long as still multi-digit...
q, r = divrem(n, 10) # calculate integer quotient and remainder of division by 10
s += r^2 # add squared digit to accumulator
n = q # continue with the number divided by 10
end
s += n^2 # addiere das Quadrat der letzten Ziffer
s += n^2 # add the square of the last digit
return s
end
```
:::
... und das testen wir jetzt natürlich:
... and let's test it now:
```{julia}
for i in [1, 7, 33, 111, 321, 1000, 73201]
j = q2sum(i)
println("Quadratquersumme von $i = $j")
println("Square digit sum of $i = $j")
end
```
Im Sinne der Aufgabe wenden wir die Funktion wiederholt an:
In the spirit of the task, we apply the function repeatedly:
```{julia}
n = 129956799
@@ -158,48 +159,48 @@ for i in 1:14
println(n)
end
```
... und haben hier einen der '89er Zyklen' getroffen.
... and we have here hit one of the '89-cycles'.
#### Funktion Nr. 2
#### Function No. 2
Wir müssen testen, ob die wiederholte Anwendung der Funktion `q2sum()` schließlich zu **1** führt oder in diesem **89er**-Zyklus endet.
We need to test whether repeated application of the function `q2sum()` finally leads to **1** or ends in this **89**-cycle.
:::{.callout-caution icon="false" collapse="true" .titlenormal}
## `q2test(n)` ermittelt, ob wiederholte Quadratquersummenbildung in den 89er-Zyklus führt:
## `q2test(n)` determines whether repeated square digit sum calculation leads to the 89-cycle:
```{julia}
#| output: false
function q2test(n)
while n !=1 && n != 89 # solange wir nicht bei 1 oder 89 angekommen sind....
n = q2sum(n) # wiederholen
while n !=1 && n != 89 # as long as we have not reached 1 or 89....
n = q2sum(n) # repeat
end
if n==1 return false end # keine 89er-Zahl
return true # 89er-Zahl gefunden
if n==1 return false end # not an 89-number
return true # 89-number found
end
```
:::
... und damit können wir die Aufgabe lösen:
... and with this, we can solve the task:
```{julia}
c = 0 # mal wieder ein Akkumulator
for i = 1 : 10_000_000 - 1 # so kann man in Julia Tausenderblöcke zur besseren Lesbarkeit abtrennen
if q2test(i) # q2test() gibt einen Boolean zurück, kein weiterer Test nötig
c += 1 # 'if x == true' ist redundant, 'if x' reicht völlig
c = 0 # once again an accumulator
for i = 1 : 10_000_000 - 1 # this is how you can separate thousands for better readability in Julia
if q2test(i) # q2test() returns a boolean, no further test needed
c += 1 # 'if x == true' is redundant, 'if x' is perfectly sufficient
end
end
println("$c numbers below ten million arrive at 89.")
```
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.
Numbers for which the iterative square digit sum calculation ends at 1 are called [happy numbers](https://en.wikipedia.org/wiki/Happy_number); all other numbers eventually reach the 89-cycle.
Hier nochmal das vollständige Programm:
Here is the complete program again:
:::{.callout-caution icon="false" collapse="true" .titlenormal}
## unsere Lösung von Project Euler No 92:
## our solution to Project Euler No 92:
```{julia}
function q2sum(n)

View File

@@ -9,72 +9,68 @@ engine: julia
using InteractiveUtils
```
```{julia}
#| error: false
#| echo: false
#| output: false
flush(stdout)
```
# Ein Beispiel zur Stabilität von Gleitkommaarithmetik
# A Case Study in Floating-Point Arithmetic Stability
## Calculation of $\pi$ According to Archimedes
## Berechnung von $\pi$ nach Archimedes
Eine untere Schranke für $2\pi$, den Umfang des Einheitskreises, erhält man durch die
Summe der Seitenlängen eines dem Einheitskreis eingeschriebenen regelmäßigen $n$-Ecks.
Die Abbildung links zeigt, wie man beginnend mit einem Viereck der Seitenlänge $s_4=\sqrt{2}$ die Eckenzahl iterativ verdoppelt.
A lower bound for $2\pi$—the circumference of the unit circle—is obtained by summing
the side lengths of a regular $n$-gon inscribed in the unit circle.
The figure on the left shows how one can iteratively double the number of vertices starting from a square with side length $$s_4=\sqrt{2}$$.
:::{.narrow}
| Abb. 1 | Abb.2 |
| Fig. 1 | Fig. 2 |
| :-: | :-: |
| ![](../images/pi1.png) | ![](../images/pi2.png) |
: {tbl-colwidths="[57,43]"}
:::
The second figure shows the geometry of the vertex doubling.
Die zweite Abbildung zeigt die Geometrie der Eckenverdoppelung.
Mit
$|\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
$NBA$ jeweils
With
$|\overline{AC}|= s_{n},\quad |\overline{AB}|= |\overline{BC}|= s_{2n},\quad |\overline{MN}| =a, \quad |\overline{NB}| =1-a,$ the Pythagorean theorem applied to triangles $MNA$ and
$NBA$ respectively yields
$$
a^2 + \left(\frac{s_{n}}{2}\right)^2 = 1\qquad\text{bzw.} \qquad
a^2 + \left(\frac{s_{n}}{2}\right)^2 = 1\qquad\text{resp.} \qquad
(1-a)^2 + \left(\frac{s_{n}}{2}\right)^2 = s_{2n}^2
$$
Elimination von $a$ liefert die Rekursion
Elimination of $a$ gives the recursion
$$
s_{2n} = \sqrt{2-\sqrt{4-s_n^2}} \qquad\text{mit Startwert}\qquad
s_4=\sqrt{2}
s_{2n} = \sqrt{2-\sqrt{4-s_n^2}} \qquad\text{with initial value}\qquad
s_4=\sqrt{2}
$$
für die Länge $s_n$ **einer** Seite des eingeschriebenen regelmäßigen
$n$-Ecks.
for the length $s_n$ of one side of the inscribed regular
$n$-gon.
Die Folge $(n\cdot s_n)$
konvergiert monoton von unten gegen den
Grenzwert $2\pi$:
The sequence $(n\cdot s_n)$ converges monotonically from below to the limit $2\pi$:
$$
n\, s_n \rightarrow 2\pi % \qquad\text{und} \qquad {n c_n}\downarrow 2\pi
n\, s_n \rightarrow 2\pi % \qquad\text{and} \qquad {n c_n}\downarrow 2\pi
$$
Der relative Fehler der Approximation von 2π durch ein $n$-Eck ist:
The relative error of approximating $2\pi$ by an $n$-gon is:
$$
\epsilon_n = \left| \frac{n\, s_n-2 \pi}{2\pi} \right|
$$
## Zwei Iterationsvorschriften^[nach: Christoph Überhuber, „Computer-Numerik“ Bd. 1, Springer 1995, Kap. 2.3]
Die Gleichung
## Two Iteration Formulas^[by Christoph Überhuber, "Computer-Numerik" Vol. 1, Springer 1995, Chap. 2.3]. The equation
$$
s_{2n} = \sqrt{2-\sqrt{4-s_n^2}}\qquad \qquad \textrm{(Iteration A)}
s_{2n} = \sqrt{2-\sqrt{4-s_n^2}}\qquad \qquad \text{(Iteration A)}
$$
ist mathematisch äquivalent zu
is mathematically equivalent to:
$$
s_{2n} = \frac{s_n}{\sqrt{2+\sqrt{4-s_n^2}}} \qquad \qquad \textrm{(Iteration B)}
s_{2n} = \frac{s_n}{\sqrt{2+\sqrt{4-s_n^2}}} \qquad \qquad \text{(Iteration B)}
$$
(Bitte nachrechnen!)
(Please verify!)
Allerdings ist Iteration A schlecht konditioniert und numerisch instabil, wie der folgende Code zeigt. Ausgegeben wird die jeweils berechnete Näherung für π.
However, Iteration A is ill-conditioned and numerically unstable, as the following code demonstrates. The output shows the respective approximation for $\pi$.
```{julia}
using Printf
@@ -82,19 +78,19 @@ using Printf
iterationA(s) = sqrt(2 - sqrt(4 - s^2))
iterationB(s) = s / sqrt(2 + sqrt(4 - s^2))
s_B = s_A = sqrt(2) # Startwert
s_B = s_A = sqrt(2) # initial value
ϵ(x) = abs(x - 2π)/2π # rel. Fehler
ϵ(x) = abs(x - 2π)/2π # relative error
ϵ_A = Float64[] # Vektoren für den Plot
ϵ_A = Float64[] # vectors for the plot
ϵ_B = Float64[]
is = Float64[]
is = Float64[]
@printf """ approx. Wert von π
n-Eck Iteration A Iteration B
@printf """Approx. value of π
$n$-gon Iteration A Iteration B
"""
for i in 3:35
for $i$ in $3:35$
push!(is, i)
s_A = iterationA(s_A)
s_B = iterationB(s_B)
@@ -102,77 +98,66 @@ for i in 3:35
doublePi_B = 2^i * s_B
push!(ϵ_A, ϵ(doublePi_A))
push!(ϵ_B, ϵ(doublePi_B))
@printf "%14i %20.15f %20.15f\n" 2^i doublePi_A/2 doublePi_B/2
@printf "%14i %20.15f %20.15f\n" 2^i doublePi_A/2 doublePi_B/2
end
```
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:
While Iteration B stabilizes at a value correct within machine precision, Iteration A becomes unstable. A plot of the relative errors $\epsilon_i$ confirms this:
```{julia}
using PlotlyJS
layout = Layout(xaxis_title="Iterationsschritte", yaxis_title="rel. Fehler",
layout = Layout(xaxis_title="Iteration steps", yaxis_title="Relative error",
yaxis_type="log", yaxis_exponentformat="power",
xaxis_tick0=2, xaxis_dtick=2)
plot([scatter(x=is, y=ϵ_A, mode="markers+lines", name="Iteration A", yscale=:log10),
plot([scatter(x=is, y=ϵ_A, mode="markers+lines", name="Iteration A", yscale=:log10),
scatter(x=is, y=ϵ_B, mode="markers+lines", name="Iteration B", yscale=:log10)],
layout)
```
```
## Stability and Cancellation
## Stabilität und Auslöschung
Bei $i=26$ erreicht Iteration B einen relativen Fehler in der Größe des Maschinenepsilons:
At $i=26$, Iteration B reaches a relative error on the order of machine epsilon:
```{julia}
ϵ_B[22:28]
```
Weitere Iterationen verbessern das Ergebnis nicht mehr. Sie stabilisieren sich bei einem relativen Fehler von etwa 2.5 Maschinenepsilon:
Further iterations do not improve the result; it stabilizes at a relative error of approximately 2.5 machine epsilons.
```{julia}
ϵ_B[end]/eps(Float64)
```
Iteration A is unstable; already at $i=16$, the relative error begins to grow again.
Die Form Iteration A ist instabil. Bereits bei $i=16$ beginnt der relative Fehler wieder zu wachsen.
Ursache ist eine typische Auslöschung. Die Seitenlängen $s_n$ werden sehr schnell klein. Damit ist
$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.
The cause is a typical cancellation effect. The side lengths $s_n$ become very small, very quickly. Thus
$a_n=\sqrt{4-s_n^2}$ is only slightly smaller than 2, and when computing $s_{2n}=\sqrt{2-a_n}$, a typical cancellation effect occurs.
```{julia}
setprecision(80) # precision für BigFloat
setprecision(80) # precision for BigFloat
s = sqrt(BigFloat(2))
@printf " a = √(4-s^2) als BigFloat und als Float64\n\n"
@printf " a = √(4-s^2) as BigFloat and as Float64\n\n"
for i = 3:44
for $$i=$ 3:44$
s = iterationA(s)
x = sqrt(4-s^2)
if i > 20
@printf "%i %30.26f %20.16f \n" i x Float64(x)
end
end
```
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.
One sees the decrease in the number of significant digits. One also sees that using `BigFloat` with a mantissa length of 80 bits only slightly delays the onset of the cancellation effect.
**Gegen instabile Algorithmen helfen in der Regel nur bessere, stabile Algorithmen und nicht genauere Maschinenzahlen!**
**Countermeasures against unstable algorithms typically require better, stable algorithms, not more precise machine numbers.**
:::{.content-hidden unless-format="xxx"}
Offensichtlich tritt bei der Berechnung von $2-a_n$ bereits relativ früh
eine Abnahme der Anzahl der signifikanten Ziffern (Auslöschung) auf,
bevor schließlich bei der Berechnung von $a_n=\sqrt{4-s_n^2}$
selbst schon Auslöschung zu einem unbrauchbaren Ergebnis führt.
Clearly, the computation of $2-a_n$ already shows a decrease in the number of significant digits (cancellation) relatively early
before the computation of $a_n=\sqrt{4-s_n^2}$ itself leads to an unusable result due to cancellation.
:::
:::

View File

@@ -1,74 +1,72 @@
# Entwicklungsumgebungen
# Development Environments
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.
For this course, we will use the web-based development environment [Jupyterhub](https://en.wikipedia.org/wiki/Project_Jupyter). It is available to all participants for the duration of the course.
Für langfristiges Arbeiten empfiehlt sich eine eigene Installation.
For long-term work, a personal installation is recommended.
## Installation auf eigenem Rechner (Linux/MacOS/MS Windows)
## Installation on Personal Computer (Linux/MacOS/MS Windows)
1. Julia mit dem Installations- und Update-Manager **juliaup** installieren: <https://github.com/JuliaLang/juliaup/>
2. als Editor/IDE **Visual Studio Code** installieren: <https://code.visualstudio.com/>
3. im VS Code Editor die **Julia language extension** installieren: <https://www.julia-vscode.org/docs/stable/gettingstarted/>
1. Install Julia with the installation and update manager **juliaup**: <https://github.com/JuliaLang/juliaup/>
2. Install **Visual Studio Code** as editor/IDE: <https://code.visualstudio.com/>
3. Install the **Julia language extension** in VS Code: <https://www.julia-vscode.org/docs/stable/gettingStarted/>
Einstieg:
Entry point:
- In VS Code eine neue Datei mit der Endung `.jl` anlegen
- Julia-Code schreiben
- `Shift-Enter` oder `Ctrl-Enter` am Ende einer Anweisung oder eines Blocks startet eine Julia-REPL, Code wird in die REPL kopiert und ausgeführt
- [Tastenbelegungen für VS Code](https://code.visualstudio.com/docs/getstarted/keybindings#_keyboard-shortcuts-reference)
und [für Julia in VS Code](https://www.julia-vscode.org/docs/stable/userguide/keybindings/)
- Create a new file with the extension `.jl` in VS Code
- Write Julia code
- `Shift-Enter` or `Ctrl-Enter` at the end of a statement or block starts a Julia-REPL, code is copied to the REPL and executed
- [Key bindings for VS Code](https://code.visualstudio.com/docs/getstarted/keybindings#_keyboard-shortcuts-reference)
and [for Julia in VS Code](https://www.julia-vscode.org/docs/stable/userguide/keybindings/)
### Die Julia-REPL
### The Julia-REPL
Wenn man Julia direkt startet, wird die [Julia-REPL](https://docs.julialang.org/en/v1/stdlib/REPL/) (*read-eval-print* Schleife) gestartet, in der man interaktiv mit Julia arbeiten kann.
When Julia is started directly, the [Julia-REPL](https://docs.julialang.org/en/v1/stdlib/REPL/) (*read-eval-print* loop) starts, where one can work interactively with Julia.
```default
$ julia
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.11.4 (2025-03-10)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.11.4 (2025-03-10)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia>
```
## Arbeiten auf dem [Jupyterhub-Webserver](https://misun103.mathematik.uni-leipzig.de/)
## Working on the [Jupyterhub Webserver](https://misun103.mathematik.uni-leipzig.de/)
### Jupyterhub & Jupyter
- [Jupyterhub](https://de.wikipedia.org/wiki/Project_Jupyter) ist ein Multi-User-Server für Jupyter.
- Jupyter ist eine web-basierte interaktive Programmierumgebung, die
- ursprünglich in und für Python geschrieben, inzwischen eine
Vielzahl von Programmiersprachen nutzen kann.
- In Jupyter bearbeitet man sogenannte *notebooks*. Das sind strukturiere Textdateien (JSON), erkennbar an der Dateiendung
`*.ipynb`.
- [JupyterHub](https://de.wikipedia.org/wiki/Project_Jupyter) is a multi-user server for Jupyter notebooks.
- Jupyter is a web-based interactive programming environment that
- was originally written for and in Python, but now supports many programming languages
- In Jupyter, one works with so-called *notebooks*. These are structured text files (JSON), recognizable by the file extension `*.ipynb`.
Unser Jupyterhub-Server: <https://misun103.mathematik.uni-leipzig.de/>
Our Jupyterhub server: <https://misun103.mathematik.uni-leipzig.de/>
Nach dem Einloggen in Jupyterhub erscheint ein Dateimanager:
After logging into Jupyterhub, a file manager appears:
::: {.content-visible when-format="html"}
![](../images/notebook001.png)
:::
::: {.content-visible when-format="pdf"}
![Jupyterhub Dateimanager](../images/notebook001.png){width=50%}
![Jupyterhub file manager](../images/notebook001.png){width=50%}
:::
Mit diesem kann man:
This can be used to:
- vorhandene *notebooks* öffnen,
- neue *notebooks* anlegen,
- Dateien, z.B. *notebooks*, vom lokalen Rechner hochladen,
- die Sitzung mit `Logout` beenden (bitte nicht vergessen!).
- open existing *notebooks*,
- create new *notebooks*,
- upload files, e.g., notebooks, from a local computer,
- end the session with `Logout` (please don't forget!).
### Jupyter notebooks
@@ -82,29 +80,29 @@ Mit diesem kann man:
:::
*Notebooks* bestehen aus Zellen. Zellen können
*Notebooks* consist of cells. Cells can contain
- Code oder
- Text/Dokumentation (Markdown)
- code or
- text/documentation (Markdown)
enthalten. In Textzellen kann die Auszeichnungssprache [Markdown](https://de.wikipedia.org/wiki/Markdown) zur Formatierung und LaTeX für mathematische Gleichungen verwendet werden.
In text cells, the markup language [Markdown](https://en.wikipedia.org/wiki/Markdown) can be used for formatting and LaTeX for mathematical equations.
::: {.callout-tip }
Bitte die Punkte `User Interface Tour` und `Keyboard Shortcuts` im `Help`-Menü anschauen!
Please check the `User Interface Tour` and `Keyboard Shortcuts` points in the `Help` menu!
:::
Die Zelle, die man gerade bearbeitet, kann im `command mode` oder `edit mode` sein.
The cell currently being worked on can be in `command mode` or `edit mode`.
:::{.narrow}
| | *Command mode* | *Edit mode* |
|:-------|:---------------:|:-----------:|
| Mode aktivieren | `ESC` | Doppelklick oder `Enter` in Zelle |
| neue Zelle | `b` | `Alt-Enter` |
| Zelle löschen | `dd` | |
| Notebook speichern | `s` | `Ctrl-s` |
| Notebook umbenennen | `Menu -> File -> Rename` | `Menu -> File -> Rename` |
| Notebook schließen | `Menu -> File -> Close & Halt` | `Menu -> File -> Close & Halt` |
| Activate mode | `ESC` | Double-click or `Enter` in cell |
| New cell | `b` | `Alt-Enter` |
| Delete cell | `dd` | |
| Save notebook | `s` | `Ctrl-s` |
| Rename notebook | `Menu -> File -> Rename` | `Menu -> File -> Rename` |
| Close notebook | `Menu -> File -> Close & Halt` | `Menu -> File -> Close & Halt` |
| *run cell* | `Ctrl-Enter` | `Ctrl-Enter` |
| *run cell, move to next cell* | `Shift-Enter` | `Shift-Enter` |
| *run cell, insert new cell below* | `Alt-Enter` | `Alt-Enter` |
@@ -118,29 +116,27 @@ Die Zelle, die man gerade bearbeitet, kann im `command mode` oder `edit mode` se
:::
::: {.content-visible when-format="pdf"}
![Julia arbeitet...](../images/notebook002.png){width=50%}
![Julia working...](../images/notebook002.png){width=50%}
:::
When a cell is working, its cell number becomes a `*` and
the `kernel busy` indicator (solid black dot at the top right next to the
Julia version) appears. If this takes too long (an *infinite loop*
is quickly programmed), then
Wenn eine Zelle \"arbeitet\", wird ihre Zellen-Nummer zu einem `*` und
die `kernel busy`-Anzeige (Voller schwarzer Punkt oben rechts neben der
Julia-Version) erscheint. Falls das zu lange dauert (ein *infinite loop*
ist schnell programmiert), dann
- `Menu -> Kernel -> Interrupt` anklicken; falls das wirkungslos ist,
- `Menu -> Kernel -> Restart` anklicken.
- click `Menu -> Kernel -> Interrupt`; if this is ineffective,
- click `Menu -> Kernel -> Restart`.
::: {.callout-important }
Nach einem `kernel restart` müssen alle Zellen, die weiterhin benötigte Definitionen,
`using`-Anweisungen etc enthalten, wieder ausgeführt werden.
After a `kernel restart`, all cells containing the required definitions,
`using` statements, etc. must be executed again.
**Am Ende der Arbeit bitte immer:**
**At the end of work, please always:**
- `Menu -> File -> Save & Checkpoint`
- `Menu -> File -> Close & Halt`
- `Logout`
- `Menu -> File -> Save & Checkpoint`
- `Menu -> File -> Close & Halt`
- `Logout`
:::

View File

@@ -11,10 +11,10 @@ using InteractiveUtils
# First Contact
Dieses Kapitel soll beim 'Loslegen' helfen. Es läßt viele Details weg und die Codebeispiele sind oft eher suboptimal.
This chapter helps you get started. It omits many details, and the code examples are often rather suboptimal.
## Julia als Taschenrechner
## Julia as a Calculator
```{julia}
#| eval: true
@@ -36,28 +36,28 @@ function Tab(s)
return # return nothing, since broadcast println produces empty vector
end
= |>
= |>
# IJulia.set_verbose(true)
```
Berechne $\qquad 12^{1/3} + \frac{3\sqrt{2}}{\sin(0.5)-\cos(\frac{\pi}{4})\log(3)}+ e^5$
Compute: $\qquad 12^{1/3} + \frac{3\sqrt{2}}{\sin(0.5)-\cos(\frac{\pi}{4})\log(3)}+ e^5$
```{julia}
12^(1/3) + 3sqrt(2) / (sin(.5) - cos(pi/4)*log(3)) + exp(5)
```
Man beachte:
Note that:
- Potenzen schreibt man `a^b`.
- Die Konstante `pi` ist vordefiniert.
- `log()` ist der natürliche Logarithmus.
- Das Multiplikationszeichen `a*b` kann nach einer Zahl weggelassen werden, wenn eine Variable, Funktion oder Klammer folgt.
- Powers are written as `a^b`.
- The constant `π` is predefined.
- `log()` is the natural logarithm.
- The multiplication sign `a*b` can be omitted after a number if it is followed by a variable, function, or parenthesis.
## Die wichtigsten Tasten: `Tab` und `?` {#sec-tab}
## The most important keys: `Tab` and `?` {#sec-tab}
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:
When programming, repeatedly press the Tab key as soon as 23 letters of a word have been typed. Potential completions are then displayed or completed if the completion is unique. This saves time and is extremely helpful.
```{julia}
lo = "lo" #| hide_line
@@ -69,7 +69,7 @@ pri = "pri" #| hide_line
pri ▷ Tab
```
Die eingebaute Julia-Hilfe `?name` zu allen Funktionen und Konstrukten ist sehr umfassend. Hier ein eher kurzes Beispiel:
The built-in Julia help `?name` for all functions and constructs is very comprehensive. Here is a rather brief example:
```{julia}
?for
@@ -78,7 +78,7 @@ Die eingebaute Julia-Hilfe `?name` zu allen Funktionen und Konstrukten ist sehr
:::{.content-hidden unless-format="xxx"}
::: {.cell }
``` {.julia .cell-code}
```{.julia .cell-code}
?for
```
@@ -103,101 +103,101 @@ julia> for i in [1, 4, 0]
:::
## Variablen und Zuweisungen
## Variables and Assignments
Variablen entstehen durch Zuweisung *(assignment)* mit dem Zuweisungsoperator `=` . Danach können sie in weiteren Anweisungen verwendet werden.
Variables are created through assignment with the assignment operator `=`. Afterwards, they can be used in further statements.
```{julia}
x = 1 + sqrt(5)
y = x / 2
```
Im interaktiven Betrieb zeigt Julia das Ergebnis der letzten Operation an.
In interactive mode, Julia displays the result of the last statement.
:::{.callout-note .titlenormal}
Zuweisungen sind keine mathematischen Gleichungen. Die Semantik des Zuweisungsoperators (Gleichheitszeichens) ist:
Assignments are not mathematical equations. The semantics of the assignment operator (the equals sign) is:
- berechne die rechte Seite und
- weise das Ergebnis der linken Seite zu.
- Compute the right side and
- Assign the result to the left side.
Ausdrücke wie `x + y = sin(2)` sind daher unzulässig. Links darf nur ein Variablenname stehen.
Expressions like `x + y = sin(2)` are therefore invalid. Only a variable name may appear on the left side.
:::
## Datentypen
## Data types
Julia ist eine [stark typisierte](https://de.wikipedia.org/wiki/Starke_Typisierung) Sprache. Alle Objekte haben einen Typ.
So gibt es unter anderem die Basistypen
Julia is a [strongly typed](https://en.wikipedia.org/wiki/Strong_and_weak_typing) language. All objects have a type.
Among other things, there are the basic types
- Ganze Zahlen *(integers)*,
- Gleitkommazahlen *(floating point numbers)*,
- Zeichenketten *(strings)* und
- Wahrheitswerte *(booleans)*.
- Integers,
- Floating-point numbers,
- Strings and
- Booleans.
Den Typ einer Variablen kann man mit der Funktion `typeof()` ermitteln.
The type of a variable can be determined using the `typeof()` function.
```{julia}
#| warning: true
#| error: true
for x ∈ (42, 12.0, 3.3e4, "Hallo!", true)
println("x = ", x, " ..... Typ: ", typeof(x))
for x ∈ (42, 12.0, 3.3e4, "Hello!", true)
println("x = ", x, " ..... Type: ", typeof(x))
end
```
Die Standard-Gleitkommazahl hat eine Länge von 64 Bit, entspricht also einer `double` in C/C++/Java.
The standard floating-point number has a size of 64 bits, which corresponds to a `double` in C/C++/Java.
Julia ist eine [dynamisch typisierte](https://de.wikipedia.org/wiki/Dynamische_Typisierung) Sprache.
Variablen haben keinen Typ. Sie sind typlose Referenzen (Zeiger) auf Objekte.
Wenn man vom „Typ einer Variablen“ spricht, meint man den Typ des Objektes, das der Variablen gerade zugewiesen ist.
Julia is a [dynamically typed](https://en.wikipedia.org/wiki/Dynamic_typing) language.
Variables have no type; they are typeless references (pointers) to objects.
When people speak of the "type of a variable", they mean the type of the object currently assigned to the variable.
```{julia}
x = sqrt(2)
println( typeof(x), " - Wert von x = $x" )
println( typeof(x), " - Value of x = $x" )
x = "Jetzt bin ich keine Gleitkommazahl mehr!"
x = "Now I'm no longer a floating-point number!"
println( typeof(x), " - Wert von x = $x" )
println( typeof(x), " - Value of x = $x" )
```
## Druckanweisungen
Die Funktion `println()` unterscheidet sich von `print()` dadurch, dass sie am Ende einen Zeilenvorschub ausgibt.
## Print statements
The `println()` function differs from `print()` in that it outputs a line break at the end.
```{julia}
print(y)
print("...die Zeile geht weiter...")
print("immernoch...")
print("...the line continues...")
print("still...")
println(y)
println("Neue Zeile")
println("Neue Zeile")
println("New line")
println("New line")
```
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)*.
Both functions can accept a list of *strings* and variables as arguments. Variables can also be embedded in *strings* by prefixing the variable name with a dollar sign *(string interpolation)*.
```{julia}
x = 23
y = 3x + 5
zz = "Fertig!"
println("x= ", x, " ...und y= ", y, "...", zz) # 1. Variante
println("x= $x ...und y= $y...$zz") # Variante mit string interpolation
zz = "Done!"
println("x= ", x, " ...and y= ", y, "...", zz) # 1. variant
println("x= $x ...and y= $y...$zz") # variant with string interpolation
```
:::{.callout-note .titlenormal collapse=true icon=false }
## Wenn man ein Dollarzeichen drucken will...
## If you want to print a dollar sign...
muss man einen *backslash* voranstellen. Wenn man einen *backslash* drucken will, muss man ihn verdoppeln.
you must prepend a *backslash*. If you want to print a *backslash*, you must double it.
```{julia}
println("Ein Dollar: 1\$ und drei backslashs: \\\\\\ ")
println("One dollar: 1\$ and three backslashes: \\\\\\ ")
```
:::
## Funktionen
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.
## Functions
Function definitions begin with the keyword `function` and end with the keyword `end`. Typically, they have one or more arguments and return a computed result via the `return` statement.
```{julia}
function hypotenuse(a, b) # heute besonders umständlich
function hypotenuse(a, b) # particularly cumbersome today
c2 = a^2 + b^2
c = sqrt(c2)
return c
end
```
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.
After their definition, the function can be used (called). The variables `a,b,c,c2` used in the definition are local variables and are not available outside the function definition.
```{julia}
#| error: true
x = 3
@@ -206,72 +206,72 @@ println("z = $z")
println("c = $c")
```
Sehr einfache Funktionen können auch als Einzeiler definiert werden.
Very simple functions can also be defined as single-line functions.
```{julia}
hypotenuse(a, b) = sqrt(a^2+b^2)
```
## Tests
Tests liefern einen Wahrheitswert zurück.
Tests return a Boolean value.
```{julia}
x = 3^2
x < 2^3
```
Neben den üblichen arithmetischen Vergleichen `==, !=, <, <= ,> ,>=`
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.
In addition to the usual arithmetic comparisons `==, !=, <, <= ,> ,>=`
there are many other tests. Of course, the result of a test can also be assigned to a variable, which is then of type `Bool`. The logical operators `&&`, `||` and negation `!` can be used in tests.
```{julia}
test1 = "Auto" in ["Fahrrad", "Auto", "Bahn"]
test1 = "Car" in ["Bicycle", "Car", "Train"]
test2 = x == 100 || !(x <= 30 && x > 8)
test3 = startswith("Lampenschirm", "Lamp")
test3 = startswith("lampshade", "Lamp")
println("$test1 $test2 $test3")
```
## Verzweigungen
Verzweigungen (bedingte Anweisungen) haben die Form
## Branches
Branches (conditional statements) have the form
```default
if <Test>
<Anweisung1>
<Anweisung2>
if <test>
<statement1>
<statement2>
...
end
```
Ein `else`-Zweig und `elseif`-Zweige sind möglich.
An `else` branch and `elseif` branches are possible.
```{julia}
x = sqrt(100)
if x > 20
println("Seltsam!")
println("Strange!")
else
println("OK")
y = x + 3
end
```
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:
Indentation improves readability but is optional. Line breaks separate statements, and this can also be done with semicolons. The above code block is identical to the following line in Julia:
```{julia}
# Bitte nicht so programmieren! Sie werden es bereuen!
x=sqrt(100); if x > 20 println("Seltsam!") else println("OK"); y = x + 3 end
# Please don't program like this! You will regret it!
x=sqrt(100); if x > 20 println("Strange!") else println("OK"); y = x + 3 end
```
Es wird dringend empfohlen, von Anfang an den eigenen Code übersichtlich mit sauberen Einrückungen zu formatieren!
It is strongly recommended to format your own code from the beginning with clear indentation!
## Einfache `for`-Schleifen
## Simple `for` loops
zum wiederholten Abarbeiten von Anweisungen haben die Form
`for` loops for repeated execution of statements have the form
```default
for <Zähler> = Start:Ende
<Anweisung1>
<Anweisung2>
for <counter> = start:end
<statement1>
<statement2>
...
end
```
Beispiel:
Example:
```{julia}
sum = 0
@@ -281,9 +281,10 @@ end
sum
```
## Arrays
1-dimensionale Arrays (Vektoren) sind eine einfache Form von Containern. Man kann sie mit echigen Klammern anlegen
und auf die Elemente per Index zugreifen. Die Indizierung beginnt mit 1.
1-dimensional arrays (vectors) are a simple form of containers. They can be created with square brackets
and accessed by index. Indexing starts at 1.
```{julia}
v = [12, 33.2, 17, 19, 22]
@@ -298,17 +299,18 @@ v[1] = v[4] + 10
v
```
Man kann leere Vektoren anlegen und sie verlängern.
Empty vectors can be created and extended with `push!()`.
```{julia}
v = [] # leerer Vektor
v = [] # empty vector
push!(v, 42)
push!(v, 13)
v
```
:::{.callout-note icon="false" .titlenormal collapse="true" font-variant-ligatures="no-contextual" }
## Nachtrag: wie die Wirkung der Tab-Taste auf dieser Seite simuliert wurde...
## Postscript: how the effect of the Tab key was simulated on this page
```{julia}
using REPL

View File

@@ -2,7 +2,18 @@
engine: julia
---
# Maschinenzahlen
```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
import QuartoNotebookWorker
Base.stdout = QuartoNotebookWorker.with_context(stdout)
myactive_module() = Main.Notebook
Base.active_module() = myactive_module()
```
# Machine Numbers
```{julia}
#| error: false
@@ -18,24 +29,24 @@ for x ∈ ( 3, 3.3e4, Int16(20), Float32(3.3e4), UInt16(9) )
end
```
## Ganze Zahlen *(integers)*
## Integer Numbers *(integers)*
Ganze Zahlen werden grundsätzlich als Bitmuster fester Länge gespeichert. Damit ist der Wertebereich endlich.
**Innerhalb dieses Wertebereichs** sind Addition, Subtraktion, Multiplikation und die Ganzzahldivision mit Rest
exakte Operationen ohne Rundungsfehler.
Integer numbers are fundamentally stored as bit patterns of fixed length. Therefore, the value range is finite.
**Within this value range** addition, subtraction, multiplication, and integer division with remainder
are exact operations without rounding errors.
Ganze Zahlen gibt es in den zwei Sorten `Signed` (mit Vorzeichen) und `Unsigned`, die man als Maschinenmodelle für bzw. auffassen kann.
Integer numbers come in two types: `Signed` (with sign) and `Unsigned`, which can be viewed as machine models for and respectively.
### *Unsigned integers*
```{julia}
subtypes(Unsigned)
```
UInts sind Binärzahlen mit n=8, 16, 32, 64 oder 128 Bits Länge und einem entsprechenden Wertebereich von
UInts are binary numbers with n=8, 16, 32, 64, or 128 bits length and the corresponding value range of
$$
0 \le x < 2^n
$$
Sie werden im *scientific computing* eher selten verwendet. Bei hardwarenaher Programmierung dienen sie z.B. dem Umgang mit Binärdaten und Speicheradressen. Deshalb werden sie von Julia standardmäßig auch als Hexadezimalzahlen (mit Präfix `0x` und Ziffern `0-9a-f`) dargestellt.
They are used relatively rarely in *scientific computing*. In hardware-proximate programming, they are e.g. used for handling binary data and memory addresses. Therefore, Julia displays them by default as hexadecimal numbers (with prefix `0x` and digits `0-9a-f`).
```{julia}
x = 0x0033efef
@@ -50,51 +61,51 @@ z = UInt(32)
```{julia}
subtypes(Signed)
```
*Integers* haben den Wertebereich
*Integers* have the value range
$$
-2^{n-1} \le x < 2^{n-1}
$$
In Julia sind ganze Zahlen standardmäßig 64 Bit groß:
In Julia, integer numbers are 64-bit by default:
```{julia}
x = 42
typeof(x)
```
Sie haben daher den Wertebereich:
Therefore, they have the value range:
$$
-9.223.372.036.854.775.808 \le x \le 9.223.372.036.854.775.807
$$
32-Bit-Integers haben den Wertebereich
32-bit integers have the value range
$$
-2.147.483.648 \le x \le 2.147.483.647
$$
Der Maximalwert $2^{31}-1$ is zufällig gerade eine Mersenne-Primzahl:
The maximum value $2^{31}-1$ is conveniently a Mersenne prime:
```{julia}
using Primes
isprime(2^31-1)
```
Negative Zahlen werden im Zweierkomplement dargestellt:
Negative numbers are represented in two's complement:
$x \Rightarrow -x$ entspricht: _flip all bits, then add 1_
$x \Rightarrow -x$ corresponds to: _flip all bits, then add 1_
Das sieht so aus:
This looks like this:
::: {.content-visible when-format="html"}
![Eine Darstellung des fiktiven Datentyps `Int4`](../images/Int4.png){width=50%}
![A representation of the fictional data type `Int4`](../images/Int4.png){width=50%}
:::
::: {.content-visible when-format="pdf"}
![Eine Darstellung des fiktiven Datentyps `Int4`](../images/Int4.png){width=50%}
![A representation of the fictional data type `Int4`](../images/Int4.png){width=50%}
:::
Das höchstwertige Bit zeigt das Vorzeichen an. Sein „Umkippen“ entspricht allerdings nicht der Operation `x → -x`.
The most significant bit indicates the sign. However, its "flipping" does not correspond to the operation `x → -x`.
:::{.callout-important}
Die gesamte Ganzzahlarithmetik ist eine __Arithmetik modulo $2^n$__
All integer arithmetic is __arithmetic modulo $2^n$__
```{julia}
x = 2^62 - 10 + 2^62
@@ -102,11 +113,11 @@ x = 2^62 - 10 + 2^62
```{julia}
x + 20
```
Keine Fehlermeldung, keine Warnung! Ganzzahlen fester Länge liegen nicht auf einer Geraden, sondern auf einem Kreis!
No error message, no warning! Fixed-length integers do not lie on a line, but on a circle!
:::
Schauen wir uns ein paar *Integers* an:
Let's look at a few *integers*:
```{julia}
@@ -119,7 +130,7 @@ for i in (1, 2, 7, -7, 2^50, -1, Int16(7), Int8(7))
end
```
Julia hat Funktionen, die über die Datentypen informieren (*introspection*):
Julia has functions that provide type information (*introspection*):
```{julia}
@@ -134,36 +145,36 @@ typemin(UInt64), typemax(UInt64), BigInt(typemax(UInt64))
typemin(Int8), typemax(Int8)
```
## Arithmetik ganzer Zahlen
## Integer Arithmetic
#### Addition, Multiplikation
Die Operationen `+`,`-`,`*` haben die übliche exakte Arithmetik **modulo $2^{64}$**.
#### Addition, Multiplication
The operations `+`,`-`,`*` have the usual exact arithmetic **modulo $2^{64}$**.
#### Potenzen `a^b`
#### Powers `a^b`
- Potenzen `a^n` werden für natürliche Exponenten `n` ebenfalls modulo $2^{64}$ exakt berechnet.
- Für negative Exponenten ist das Ergebnis eine Gleitkommazahl.
- `0^0` ist [selbstverständlich](https://en.wikipedia.org/wiki/Zero_to_the_power_of_zero#cite_note-T4n3B-4) gleich 1.
- Powers `a^n` are computed exactly modulo $2^{64}$ for natural exponents `n`.
- For negative exponents, the result is a floating-point number.
- `0^0` is [naturally](https://en.wikipedia.org/wiki/Zero_to_the_power_of_zero#cite_note-T4n3B-4) equal to 1.
```{julia}
(-2)^63, 2^64, 3^(-3), 0^0
```
- Für natürliche Exponenten wird [*exponentiation by squaring*](https://de.wikipedia.org/wiki/Bin%C3%A4re_Exponentiation) verwendet, so dass z.B. `x^23` nur 7 Multiplikationen benötigt:
- For natural exponents, [*exponentiation by squaring*](https://de.wikipedia.org/wiki/Bin%C3%A4re_Exponentiation) is used, so for example `x^23` requires only 7 multiplications:
$$
x^{23} = \left( \left( (x^2)^2 \cdot x \right)^2 \cdot x \right)^2 \cdot x
$$
#### Division
- Division `/` erzeugt eine Gleitkommazahl.
- Division `/` produces a floating-point number.
```{julia}
x = 40/5
```
#### Ganzzahldivision und Rest
#### Integer Division and Remainder
- Die Funktionen `div(a,b)`, `rem(a,b)` und `divrem(a,b)` berechnen den Quotient der Ganzzahldivision, den dazugehörigen Rest *(remainder)* bzw. beides als Tupel.
- Für `div(a,b)` gibt es die Operatorform `a ÷ b` (Eingabe: `\div<TAB>`) und für `rem(a,b)` die Operatorform `a % b`.
- Standardmäßig wird bei der Division „zur Null hin gerundet“, wodurch der dazugehörige Rest dasselbe Vorzeichen wie der Dividend `a` trägt:
- The functions `div(a,b)`, `rem(a,b)`, and `divrem(a,b)` compute the quotient of integer division, the corresponding remainder, or both as a tuple.
- For `div(a,b)` there is the operator form `a ÷ b` (input: `\div<TAB>`), and for `rem(a,b)` the operator form `a % b`.
- By default, division is "rounded toward zero", so the corresponding remainder has the same sign as the dividend `a`:
```{julia}
@show divrem( 27, 4)
@@ -172,9 +183,9 @@ x = 40/5
@show ( 27 ÷ -4, 27 % -4);
```
- Eine von `RoundToZero` abweichende Rundungsregel kann bei den Funktionen als optionales 3. Argument angegeben werden.
- `?RoundingMode` zeigt die möglichen Rundungsregeln an.
- Für die Rundungsregel `RoundDown` („in Richtung minus unendlich"), wodurch der dazugehörige Rest dasselbe Vorzeichen wie der Divisor `b` bekommt, gibt es auch die Funktionen `fld(a,b)` *(floored division)* und `mod(a,b)`:
- A rounding rule other than `RoundToZero` can be specified as the third optional argument for the functions.
- `?RoundingMode` shows the possible rounding modes.
- For the rounding rule `RoundDown` ("toward minus infinity"), so that the corresponding remainder has the same sign as the divisor `b`, there are also the functions `fld(a,b)` *(floored division)* and `mod(a,b)`:
```{julia}
@show divrem(-27, 4, RoundDown)
@@ -182,47 +193,47 @@ x = 40/5
@show (fld( 27, -4), mod( 27, -4));
```
Für alle Rundungsregeln gilt:
For all rounding modes holds:
```
div(a, b, RoundingMode) * b + rem(a, b, RoundingMode) = a
```
#### Der Datentyp `BigInt`
#### The `BigInt` Type
Der Datentyp `BigInt` ermöglicht Ganzzahlen beliebiger Länge. Der benötigte Speicher wird dynamisch allokiert.
The `BigInt` type allows arbitrary-length integers. The required memory is dynamically allocated.
Numerische Konstanten haben automatisch einen ausreichend großen Typ:
Numeric constants automatically have a sufficiently large type:
```{julia}
z = 10
@show typeof(z)
z = 10_000_000_000_000_000 # 10 Billiarden
z = 10_000_000_000_000_000 # 10 quadrillion
@show typeof(z)
z = 10_000_000_000_000_000_000 # 10 Trillionen
z = 10_000_000_000_000_000_000 # 10 quintillion
@show typeof(z)
z = 10_000_000_000_000_000_000_000_000_000_000_000_000_000 # 10 Sextilliarden
z = 10_000_000_000_000_000_000_000_000_000_000_000_000_000 # 10 sextillion
@show typeof(z);
```
Meist wird man allerdings den Datentyp `BigInt` explizit anfordern müssen, damit nicht modulo $2^{64}$ gerechnet wird:
Usually, one must explicitly request the `BigInt` type to avoid modulo $2^{64}$ arithmetic:
```{julia}
@show 3^300 BigInt(3)^300;
```
*Arbitrary precision arithmetic* kostet einiges an Speicherplatz und Rechenzeit.
*Arbitrary precision arithmetic* comes at a cost of significant memory and computation time.
Wir vergleichen den Zeit- und Speicherbedarf bei der Aufsummation von 10 Millionen Ganzzahlen als `Int64` und als `BigInt`.
We compare the time and memory requirements for summing 10 million integers as `Int64` and as `BigInt`.
```{julia}
# 10^7 Zufallszahlen, gleichverteilt zwischen -10^7 und 10^7
# 10^7 random numbers, uniformly distributed between -10^7 and 10^7
vec_int = rand(-10^7:10^7, 10^7)
# Dieselben Zahlen als BigInts
# The same numbers as BigInts
vec_bigint = BigInt.(vec_int)
```
Einen ersten Eindruck vom Zeit- und Speicherbedarf gibt das `@time`-Macro:
An initial impression of the time and memory requirements is provided by the `@time` macro:
```{julia}
@time x = sum(vec_int)
@@ -233,7 +244,7 @@ Einen ersten Eindruck vom Zeit- und Speicherbedarf gibt das `@time`-Macro:
@show x typeof(x);
```
Durch die Just-in-Time-Compilation von Julia ist die einmalige Ausführung einer Funktion wenig aussagekräftig. Das Paket `BenchmarkTools` stellt u.a. das Macro `@benchmark` bereit, das eine Funktion mehrfach aufruft und die Ausführungszeiten als Histogramm darstellt.
Due to Julia's just-in-time compilation, a single execution of a function is not very informative. The `BenchmarkTools` package provides the `@benchmark` macro, which calls a function multiple times and displays the execution times as a histogram.
:::{.ansitight}
```{julia}
@@ -247,13 +258,11 @@ using BenchmarkTools
@benchmark sum($vec_bigint)
```
:::
Die `BigInt`-Addition ist mehr als 30 mal langsamer.
The `BigInt` addition is more than 30 times slower.
:::{.content-hidden unless-format="xxx"}
Die folgende Funktion soll die Summe aller Zahlen von 1 bis n mit der Arithmetik des Datentyps T berechnen.
Auf Grund der *type promotion rules* reicht es für `T ≥ Int64` dazu aus, die Akkumulatorvariable mit einer Zahl vom Typ T zu initialisieren.
The following function should compute the sum of all numbers from 1 to n using arithmetic of type T.
Due to the *type promotion rules*, it is sufficient for `T ≥ Int64` to initialize the accumulator variable with a number of type T.
```{julia}
function mysum(n, T)
s = T(0)
@@ -264,7 +273,7 @@ function mysum(n, T)
end
```
Einen ersten Eindruck vom Zeit- und Speicherbedarf gibt das `@time`-Macro:
An initial impression of the time and memory requirements is provided by the `@time` macro:
```{julia}
@time x = mysum(10_000_000, Int64)
@@ -276,7 +285,7 @@ Einen ersten Eindruck vom Zeit- und Speicherbedarf gibt das `@time`-Macro:
@show x typeof(x);
```
Durch die Just-in-Time-Compilation von Julia ist die einmalige Ausführung einer Funktion wenig aussagekräftig. Das Paket `BenchmarkTools` stellt u.a. das Macro `@benchmark` bereit, das eine Funktion mehrfach aufruft und die Ausführungszeiten als Histogramm darstellt.
Due to Julia's just-in-time compilation, a single execution of a function is not very informative. The `BenchmarkTools` package provides the `@benchmark` macro, which calls a function multiple times and displays the execution times as a histogram.
:::{.ansitight}
```{julia}
@@ -292,85 +301,84 @@ using BenchmarkTools
```
Die Berechnung von $\sum_{n=1}^{10000000} n$ dauert auf meinem PC mit den Standard-64bit-Integern im Schnitt 2 Nanosekunden, in *arbitrary precision arithmetic* über eine Sekunde, wobei auch noch fast 500MB Speicher allokiert werden.
The computation of $\sum_{n=1}^{10000000} n$ takes on my PC an average of 2 nanoseconds with standard 64-bit integers and over one second in *arbitrary precision arithmetic*, during which nearly 500MB of memory is also allocated.
:::
:::
## Gleitkommazahlen
## Floating-Point Numbers
Aus _floating point numbers_ kann man im Deutschen **[Gleit|Fließ]--[Komma|Punkt]--Zahlen** machen
und tatsächlich kommen alle 4 Varianten in der Literatur vor.
From _floating point numbers_, one can form German **[Gleit|Fließ]--[Komma|Punkt]--Zahlen**, and indeed all 4 variants appear in the literature.
In der Numerischen Mathematik spricht man auch gerne von **Maschinenzahlen**.
In numerical mathematics, one also often speaks of **machine numbers**.
### Grundidee
### Basic Idea
- Eine „feste Anzahl von Vor- und Nachkommastellen“ ist für viele Probleme ungeeignet.
- Eine Trennung zwischen „gültigen Ziffern“ und Größenordnung (Mantisse und Exponent) wie in der wissenschaftlichen Notation ist wesentlich flexibler.
- A "fixed number of digits before and after the decimal point" is unsuitable for many problems.
- A separation between "significant digits" and magnitude (mantissa and exponent), as in scientific notation, is much more flexible.
$$ 345.2467 \times 10^3\qquad 34.52467\times 10^4\qquad \underline{3.452467\times 10^5}\qquad 0.3452467\times 10^6\qquad 0.03452467\times 10^7$$
- Zur Eindeutigkeit muss man eine dieser Formen auswählen. In der mathematischen Analyse von Maschinenzahlen wählt man oft die Form, bei der die erste Nachkommastelle ungleich Null ist. Damit gilt für die Mantisse $m$:
- For uniqueness, one must choose one of these forms. In the mathematical analysis of machine numbers, one often chooses the form where the first digit after the decimal point is nonzero. Thus, for the mantissa $m$:
$$
1 > m \ge (0.1)_b = b^{-1},
$$
wobei $b$ die gewählte Basis des Zahlensystems bezeichnet.
- Wir wählen im Folgenden die Form, die der tatsächlichen Implementation auf dem Computer entspricht und legen fest:
Die Darstellung mit genau einer Ziffer ungleich Null vor dem Komma ist die __Normalisierte Darstellung__. Damit gilt
where $b$ denotes the base of the number system.
- We choose the form that corresponds to the actual implementation on the computer and specify:
The representation with exactly one nonzero digit before the decimal point is the __normalized representation__. Thus,
$$
(10)_b = b> m \ge 1.
$$
- Bei Binärzahlen `1.01101` ist diese Ziffer immer gleich Eins und man kann auf das Abspeichern dieser Ziffer verzichten. Diese tatsächlich abgespeicherte (gekürzte) Mantisse bezeichnen wir mit $M$, so dass
- For binary numbers `1.01101`, this digit is always equal to one, and one can omit storing this digit. This actually stored (shortened) mantissa we denote by $M$, so that
$$m = 1 + M$$
gilt.
holds.
:::{.callout-note }
## Maschinenzahlen
## Machine Numbers
Die Menge der Maschinenzahlen $𝕄(b, p, e_{min}, e_{max})$ ist charakterisiert durch die verwendete Basis $b$, die Mantissenlänge $p$ und den Wertebereich des Exponenten $\{e_{min}, ... ,e_{max}\}$.
The set of machine numbers $𝕄(b, p, e_{min}, e_{max})$ is characterized by the base $b$ used, the mantissa length $p$, and the value range of the exponent $\{e_{min}, ... ,e_{max}\}$.
In unserer Konvention hat die Mantisse einer normalisierten Maschinenzahl eine Ziffer (der Basis $b$) ungleich Null vor dem Komma und $p-1$ Nachkommastellen.
In our convention, the mantissa of a normalized machine number has one digit (of base $b$) nonzero before the decimal point and $p-1$ digits after the decimal point.
Wenn $b=2$ ist, braucht man daher nur $p-1$ Bits zur Speicherung der Mantisse normalisierter Gleitkommazahlen.
If $b=2$, one needs only $p-1$ bits to store the mantissa of normalized floating-point numbers.
Der Standard IEEE 754, der von der Mahrzahl der modernen Prozessoren und Programmiersprachen implementiert wird, definiert
The IEEE 754 standard, implemented by most modern processors and programming languages, defines
- `Float32` als $𝕄(2, 24, -126, 127 )$ und
- `Float64` als $𝕄(2, 53, -1022, 1023 ).$
- `Float32` as $𝕄(2, 24, -126, 127 )$ and
- `Float64` as $𝕄(2, 53, -1022, 1023 ).$
:::
### Aufbau von `Float64` nach [Standard IEEE 754](https://de.wikipedia.org/wiki/IEEE_754)
### Structure of `Float64` according to [IEEE 754 standard](https://de.wikipedia.org/wiki/IEEE_754)
::: {.content-visible when-format="html"}
![Aufbau einer `Float64` (Quelle:^[Quelle: <a href="https://commons.wikimedia.org/wiki/File:IEEE_754_Double_Floating_Point_Format.svg">Codekaizen</a>, <a href="https://creativecommons.org/licenses/by-sa/4.0">CC BY-SA 4.0</a>, via Wikimedia Commons ])
![Structure of a `Float64` (source:^[Source: <a href="https://commons.wikimedia.org/wiki/File:IEEE_754_Double_Floating_Point_Format.svg">Codekaizen</a>, <a href="https://creativecommons.org/licenses/by-sa/4.0">CC BY-SA 4.0</a>, via Wikimedia Commons ])
](../images/1024px-IEEE_754_Double_Floating_Point_Format.png)
:::
::: {.content-visible when-format="pdf"}
![Aufbau einer `Float64` \mysmall{(Quelle: \href{https://commons.wikimedia.org/wiki/File:IEEE_754_Double_Floating_Point_Format.svg}{Codekaizen}, \href{https://creativecommons.org/licenses/by-sa/4.0}{CC BY-SA 4.0}, via Wikimedia Commons)}
![Structure of a `Float64` \mysmall{(Source: \href{https://commons.wikimedia.org/wiki/File:IEEE_754_Double_Floating_Point_Format.svg}{Codekaizen}, \href{https://creativecommons.org/licenses/by-sa/4.0}{CC BY-SA 4.0}, via Wikimedia Commons)}
](../images/1024px-IEEE_754_Double_Floating_Point_Format.png){width="70%"}
:::
- 1 Vorzeichenbit $S$
- 11 Bits für den Exponenten, also $0\le E \le 2047$
- die Werte $E=0$ und $E=(11111111111)_2=2047$ sind reserviert für die Codierung von Spezialwerten wie
$\pm0, \pm\infty$, NaN _(Not a Number)_ und denormalisierte Zahlen.
- 52 Bits für die (gekürzte) Mantisse $M,\quad 0\le M<1$, das entspricht etwa 16 Dezimalstellen
- Damit wird folgende Zahl dargestellt:
- 1 sign bit $S$
- 11 bits for the exponent, thus $0\le E \le 2047$
- The values $E=0$ and $E=(11111111111)_2=2047$ are reserved for encoding special values such as
$\pm0, \pm\infty$, NaN _(Not a Number)_ and subnormal numbers.
- 52 bits for the (shortened) mantissa $M,\quad 0\le M<1$, corresponding to approximately 16 decimal digits
- Thus, the following number is represented:
$$ x=(-1)^S \cdot(1+M)\cdot 2^{E-1023}$$
Ein Beispiel:
An example:
```{julia}
x = 27.56640625
bitstring(x)
```
Das geht auch schöner:
This can be done more nicely:
```{julia}
function printbitsf64(x::Float64)
@@ -383,7 +391,7 @@ end
printbitsf64(x)
```
und wir können S (in blau),E (grün) und M (rot) ablesen:
and we can read S (blue), E (green), and M (red):
$$
\begin{aligned}
S &= 0\\
@@ -394,15 +402,15 @@ x &=(-1)^S \cdot(1+M)\cdot 2^{E-1023}
$$
... und damit die Zahl rekonstruieren:
... and thus reconstruct the number:
```{julia}
x = (1 + 1/2 + 1/8 + 1/16 + 1/32 + 1/256 + 1/4096) * 2^4
```
- Die Maschinenzahlen 𝕄 bilden eine endliche, diskrete Untermenge von . Es gibt eine kleinste und eine größte Maschinenzahl und abgesehen davon haben alle x∈𝕄 einen Vorgänger und Nachfolger in 𝕄.
- Was ist der Nachfolger von x in 𝕄? Dazu setzen wir das kleinste Mantissenbit von 0 auf 1.
- Die Umwandlung eines Strings aus Nullen und Einsen in die entsprechende Maschinenzahl ist z.B. so möglich:
- The machine numbers 𝕄 form a finite, discrete subset of . There is a smallest and a largest machine number, and apart from these, all x∈𝕄 have a predecessor and successor in 𝕄.
- What is the successor of x in 𝕄? To do this, we set the smallest mantissa bit from 0 to 1.
- Converting a string of zeros and ones into the corresponding machine number is possible e.g. as follows:
```{julia}
@@ -410,13 +418,13 @@ ux = parse(UInt64, "010000000011101110010001000000000000000000000000000000000000
reinterpret(Float64, ux)
```
Das kann man in Julia allerdings auch einfacher haben:
However, Julia can do this more simply:
```{julia}
y = nextfloat(x)
```
Der Vorgänger von x ist:
The predecessor of x is:
```{julia}
z = prevfloat(x)
@@ -426,32 +434,30 @@ printbitsf64(z)
## Machine Epsilon
## Maschinenepsilon
- Den Abstand zwischen `1` und dem Nachfolger `nextfloat(1)` nennt man [**Maschinenepsilon**](https://en.wikipedia.org/wiki/Machine_epsilon).
- Für `Float64` mit einer Mantissenlänge von 52 Bit ist $\epsilon=2^{-52}$.
- The distance between `1` and its successor `nextfloat(1)` is called [**machine epsilon**](https://en.wikipedia.org/wiki/Machine_epsilon).
- For `Float64` with a mantissa length of 52 bits, $\epsilon=2^{-52}$.
```{julia}
@show nextfloat(1.) - 1 2^-52 eps(Float64);
```
- Das Maschinenepsilon ist ein Maß für den relativen Abstand zwischen den Maschinenzahlen und quantifiziert die Aussage: 64-Bit-Gleitkommazahlen haben eine Genauigkeit von etwa 16 Dezimalstellen.“
- Das Maschinenepsilon ist etwas völlig anderes als die kleinste positive Gleitkommazahl:
- Machine epsilon is a measure of the relative distance between machine numbers and quantifies the statement: "64-bit floating-point numbers have a precision of approximately 16 decimal digits."
- Machine epsilon is something completely different from the smallest positive floating-point number:
```{julia}
floatmin(Float64)
```
- Ein Teil der Literatur verwendet eine andere Definition des Maschinenepsilons, die halb so groß ist.
- Part of the literature uses a different definition of machine epsilon, which is half as large.
$$
\epsilon' = \frac{\epsilon}{2}\approx 1.1\times 10^{-16}
$$
ist der maximale relative Fehler, der beim Runden einer reellen Zahl auf die nächste Maschinenzahl entstehen kann.
- Da Zahlen aus dem Intervall $(1-\epsilon',1+\epsilon']$ auf die Maschinenzahl $1$ gerundet werden, kann man $\epsilon'$ auch definieren als: *die größte Zahl, für die in der Maschinenzahlarithmetik noch gilt: $1+\epsilon' = 1$.*
$$
is the maximum relative error that can occur when rounding a real number to the nearest machine number.
- Since numbers in the interval $(1-\epsilon',1+\epsilon']$ are rounded to the machine number $1$, one can also define $\epsilon'$ as: *the largest number for which in machine arithmetic still holds: $1+\epsilon' = 1$.*
Auf diese Weise kann man das Maschinenepsilon auch berechnen:
In this way, one can also compute machine epsilon:
:::{.ansitight}
@@ -464,7 +470,7 @@ end
Eps
```
oder als Bitmuster:
or as a bit pattern:
```{julia}
Eps=1
@@ -478,19 +484,19 @@ Eps
:::
:::{.callout-note}
## Die Menge der (normalisierten) Maschinenzahlen
## The Set of (normalized) Machine Numbers
- Im Intervall $[1,2)$ liegen $2^{52}$ äquidistante Maschinenzahlen.
- Danach erhöht sich der Exponent um 1 und die Mantisse $M$ wird auf 0 zurückgesetzt. Damit enthält das Intervall $[2,4)$ wiederum $2^{52}$ äquidistante Maschinenzahlen, ebenso das Intervall $[4,8)$ bis hin zu $[2^{1023}, 2^{1024})$.
- Ebenso liegen in den Intervallen $\ [\frac{1}{2},1), \ [\frac{1}{4},\frac{1}{2}),...$ je $2^{52}$ äquidistante Maschinenzahlen, bis hinunter zu $[2^{-1022}, 2^{-1021})$.
- Dies bildet die Menge $𝕄_+$ der positiven Maschinenzahlen und es ist
- In the interval $[1,2)$ there are $2^{52}$ equidistant machine numbers.
- After that, the exponent increases by 1 and the mantissa $M$ is reset to 0. Thus, the interval $[2,4)$ again contains $2^{52}$ equidistant machine numbers, as does the interval $[4,8)$ up to $[2^{1023}, 2^{1024})$.
- Likewise, in the intervals $\ [\frac{1}{2},1), \ [\frac{1}{4},\frac{1}{2}),...$ there are $2^{52}$ equidistant machine numbers each, down to $[2^{-1022}, 2^{-1021})$.
- This forms the set $𝕄_+$ of positive machine numbers, and it is
$$
𝕄 = -𝕄_+ \cup \{0\} \cup 𝕄_+
$$
:::
Die größte und die kleinste positive normalisiert darstellbare Gleitkommazahl eines Gleitkommatyps kann man abfragen:
The largest and smallest positive representable normalized floating-point numbers of a floating-point type can be queried:
```{julia}
@show floatmax(Float64)
@@ -502,37 +508,35 @@ printbitsf64(floatmin(Float64))
## Rounding to Machine Numbers
## Runden auf Maschinenzahlen
- Die Abbildung rd: $\rightarrow$ 𝕄 soll zur nächstgelegenen darstellbaren Zahl runden.
- Standardrundungsregel: _round to nearest, ties to even_
Wenn man genau die Mitte zwischen zwei Maschinenzahlen trifft *(tie)*, wählt man die, deren letztes Mantissenbit 0 ist.
- Begründung: damit wird statistisch in 50% der Fälle auf- und in 50% der Fälle abgerundet und so ein „statistischer Drift“ bei längeren Rechnungen vermieden.
- Es gilt:
- The mapping rd: $\rightarrow$ 𝕄 should round to the nearest representable number.
- Standard rounding mode: _round to nearest, ties to even_
If one lands exactly in the middle between two machine numbers *(tie)*, one chooses the one whose last mantissa bit is 0.
- Justification: this way, in 50% of the cases one rounds up and in 50% down, thus avoiding a "statistical drift" in longer calculations.
- It holds:
$$
\frac{|x-\text{rd}(x)|}{|x|} \le \frac{1}{2} \epsilon
$$
## Maschinenzahlarithmetik
## Machine Number Arithmetic
Die Maschinenzahlen sind als Untermenge von nicht algebraisch abgeschlossen. Schon die Summe zweier Maschinenzahlen wird in der Regel keine Maschinenzahl sein.
The machine numbers, as a subset of , are not algebraically closed. Even the sum of two machine numbers will generally not be a machine number.
:::{.callout-important}
Der Standard IEEE 754 fordert, dass die Maschinenzahlarithmetik das *gerundete exakte Ergebnis* liefert:
The IEEE 754 standard requires that machine number arithmetic produces the *rounded exact result*:
Das Resultat muss gleich demjenigen sein, das bei einer exakten Ausführung der entsprechenden Operation mit anschließender Rundung entsteht.
The result must be equal to the one that would result from an exact execution of the corresponding operation followed by rounding.
$$
a \oplus b = \text{rd}(a + b)
$$
Analoges muss für die Implemetierung der Standardfunktionen wie
wie `sqrt()`, `log()`, `sin()` ... gelten: Sie liefern ebenfalls die Maschinenzahl, die dem exakten Ergebnis am nächsten kommt.
The same must hold for the implementation of standard functions such as
`sqrt()`, `log()`, `sin()` ...: they also return the machine number closest to the exact result.
:::
Die Arithmetik ist *nicht assoziativ*:
Arithmetic is *not associative*:
```{julia}
1 + 10^-16 + 10^-16
@@ -542,7 +546,7 @@ Die Arithmetik ist *nicht assoziativ*:
1 + (10^-16 + 10^-16)
```
Im ersten Fall (ohne Klammern) wird von links nach rechts ausgewertet:
In the first case (without parentheses), evaluation proceeds from left to right:
$$
\begin{aligned}
1 \oplus 10^{-16} \oplus 10^{-16} &=
@@ -553,7 +557,7 @@ $$
\end{aligned}
$$
Im zweiten Fall erhält man:
In the second case, one obtains:
$$
\begin{aligned}
1 \oplus \left(10^{-16} \oplus 10^{-16}\right) &=
@@ -564,22 +568,21 @@ $$
$$
Es sei auch daran erinnert, dass sich selbst „einfache“ Dezimalbrüche häufig nicht exakt als Maschinenzahlen darstellen lassen:
One should also be reminded that even "simple" decimal fractions often cannot be represented exactly as machine numbers:
$$
\begin{aligned}
(0.1)_{10} &= (0.000110011001100110011001100...)_2 = (0.000\overline{1100})_2 \\
(0.3)_{10} &= (0.0100110011001100110011001100..)_2 = (0.0\overline{1001})_2
\end{aligned}
$$
\end{aligned}
$$
```{julia}
printbitsf64(0.1)
printbitsf64(0.3)
```
Folge:
Consequence:
```{julia}
0.1 + 0.1 == 0.2
@@ -593,7 +596,7 @@ Folge:
0.2 + 0.1
```
Bei der Ausgabe einer Maschinenzahl muss der Binärbruch in einen Dezimalbruch entwickelt werden. Man kann sich auch mehr Stellen dieser Dezimalbruchentwicklung anzeigen lassen:
When outputting a machine number, the binary fraction must be converted to a decimal fraction. One can also display more digits of this decimal fraction expansion:
```{julia}
using Printf
@printf("%.30f", 0.1)
@@ -602,12 +605,12 @@ using Printf
```{julia}
@printf("%.30f", 0.3)
```
Die Binärbruch-Mantisse einer Maschinenzahl kann eine lange oder sogar unendlich-periodische Dezimalbruchentwicklung haben. Dadurch
sollte man sich nicht eine „höheren Genauigkeit“ suggerieren lassen!
The binary fraction mantissa of a machine number can have a long or even infinitely periodic decimal expansion. Therefore,
one should not be misled into thinking there is "higher precision"!
:::{.callout-important}
Moral: wenn man `Float`s auf Gleichheit testen will, sollte man fast immer eine dem Problem angemessene realistische Genauigkeit `epsilon` festlegen und
darauf testen:
Moral: when testing `Float`s for equality, one should almost always define a realistic accuracy `epsilon` appropriate to the problem and
test:
```julia
epsilon = 1.e-10
@@ -618,23 +621,22 @@ end
```
:::
## Normalisierte und Denormalisierte Maschinenzahlen
## Normalized and Subnormal Machine Numbers
Die Lücke zwischen Null und der kleinsten normalisierten Maschinenzahl $2^{-1022} \approx 2.22\times 10^{-308}$
ist mit denormalisierten Maschinenzahlen besiedelt.
The gap between zero and the smallest normalized machine number $2^{-1022} \approx 2.22\times 10^{-308}$
is filled with subnormal machine numbers.
Zum Verständnis nehmen wir ein einfaches Modell:
For understanding, let's take a simple model:
- Sei 𝕄(10,4,±5) die Menge der Maschinenzahlen zur Basis 10 mit 4 Mantissenstellen (eine vor dem Komma, 3 Nachkommastellen) und dem Exponentenbereich -5 ≤ E ≤ 5.
- Dann ist die normalisierte Darstellung (Vorkommastelle ungleich 0)
von z.B. 1234.0 gleich 1.234e3 und von 0.00789 gleich 7.890e-3.
- Es ist wichtig, dass die Maschinenzahlen bei jedem Rechenschritt normalisiert gehalten werden. Nur so wird die Mantissenlänge voll ausgenutzt und die Genauigkeit ist maximal.
- Die kleinste positive normalisierte Zahl in unserem Modell ist `x = 1.000e-5`. Schon `x/2` müsste auf 0 gerundet werden.
- Hier erweist es sich für viele Anwendungen als günstiger, auch denormalisierte *(subnormal)* Zahlen zuzulassen und `x/2` als `0.500e-5` oder `x/20` als `0.050e-5` darzustellen.
- Dieser *gradual underflow* ist natürlich mit einem Verlust an gültigen Stellen und damit Genauigkeit verbunden.
- Let 𝕄(10,4,±5) be the set of machine numbers to base 10 with 4 mantissa digits (one before the decimal point, 3 after) and the exponent range -5 ≤ E ≤ 5.
- Then the normalized representation (nonzero leading digit)
of e.g. 1234.0 is 1.234e3 and of 0.00789 is 7.890e-3.
- It is important that machine numbers are kept normalized at every computation step. Only then is the mantissa length fully utilized and the accuracy is maximum.
- The smallest positive normalized number in our model is `x = 1.000e-5`. Already `x/2` would have to be rounded to 0.
- Here, for many applications, it is advantageous to allow also subnormal *(subnormal)* numbers and represent `x/2` as `0.500e-5` or `x/20` as `0.050e-5`.
- This *gradual underflow* is当然 associated with a loss of valid digits and thus accuracy.
Im `Float`-Datentyp werden solche *subnormal values* dargestellt durch ein Exponentenfeld, in dem alle Bits gleich Null sind:
In the `Float` data type, such *subnormal values* are represented by an exponent field in which all bits are equal to zero:
```{julia}
#| echo: false
@@ -647,7 +649,7 @@ flush(stdout)
```{julia}
using Printf
x = 2 * floatmin(Float64) # 2*kleinste normalisierte Gleitkommazahl > 0
x = 2 * floatmin(Float64) # 2*smallest normalized floating-point number > 0
while x != 0
x /= 2
@@ -657,9 +659,9 @@ end
```
:::
## Spezielle Werte
## Special Values
Die Gleitkommaarithmetik kennt einige spezielle Werte, z.B.
Floating-point arithmetic knows some special values, e.g.
```{julia}
nextfloat(floatmax(Float64))
```
@@ -671,23 +673,22 @@ for x ∈ (NaN, Inf, -Inf, -0.0)
end
```
- Ein Exponentenüberlauf *(overflow)* führt zum Ergebnis `Inf` oder `-Inf`.
- An exponent overflow *(overflow)* leads to the result `Inf` or `-Inf`.
```{julia}
2/0, -3/0, floatmax(Float64) * 1.01, exp(1300)
```
- Damit kann weitergerechnet werden:
- One can continue calculating with it:
```{julia}
-Inf + 20, Inf/30, 23/-Inf, sqrt(Inf), Inf * 0, Inf - Inf
```
- `NaN` *(Not a Number)* steht für das Resultat einer Operation, das undefiniert ist. Alle weiteren Operationen mit `NaN` ergeben ebenfalls `NaN`.
- `NaN` *(Not a Number)* stands for the result of an operation that is undefined. All further operations with `NaN` also result in `NaN`.
```{julia}
0/0, Inf - Inf, 2.3NaN, sqrt(NaN)
```
- Da `NaN` einen undefinierten Wert repräsentiert, ist es zu nichts gleich, nichtmal zu sich selbst. Das ist sinnvoll, denn wenn zwei Variablen `x` und `y` als `NaN` berechnet wurden, sollte man nicht schlußfolgern, dass sie gleich sind.
- Zum Testen auf `NaN` gibt es daher die boolsche Funktion `isnan()`.
- Since `NaN` represents an undefined value, it is not equal to anything, not even to itself. This is sensible, because if two variables `x` and `y` are computed as `NaN`, one should not conclude that they are equal.
- There is therefore a boolean function `isnan()` to test for `NaN`.
```{julia}
x = 0/0
@@ -695,18 +696,18 @@ y = Inf - Inf
@show x==y NaN==NaN isfinite(NaN) isinf(NaN) isnan(x) isnan(y);
```
- Es gibt eine „minus Null“. Sie signalisiert einen Exponentenunterlauf *(underflow)* einer betragsmäßig zu klein gewordenen *negativen* Größe.
- There is a "minus zero". It signals an exponent underflow *(underflow)* of a magnitude that has become too small *negative* quantity.
```{julia}
@show 23/-Inf -2/exp(1200) -0.0==0.0;
```
## Mathematische Funktionen
## Mathematical Functions
Julia verfügt über die [üblichen mathematischen Funktionen](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions)
Julia has the [usual mathematical functions](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions)
`sqrt, exp, log, log2, log10, sin, cos,..., asin, acos,..., sinh,..., gcd, lcm, factorial,...,abs, max, min,...`,
darunter z.B. die [Rundungsfunktionen](https://de.wikipedia.org/wiki/Abrundungsfunktion_und_Aufrundungsfunktion)
including e.g. the [rounding functions](https://de.wikipedia.org/wiki/Abrundungsfunktion_und_Aufrundungsfunktion)
- `floor(T,x)` = $\lfloor x \rfloor$
- `ceil(T,x)` = $\lceil x \rceil$
@@ -719,19 +720,19 @@ floor(3.4), floor(Int64, 3.5), floor(Int64, -3.5)
ceil(3.4), ceil(Int64, 3.5), ceil(Int64, -3.5)
```
Es sei noch hingewiesen auf `atan(y, x)`, den [Arkustangens mit 2 Argumenten](https://de.wikipedia.org/wiki/Arctan2), Er ist in anderen Programmiersprachen oft als Funktion mit eigenem Namen *atan2* implementiert.
Dieser löst das Problem der Umrechnung von kartesischen in Polarkoordinaten ohne lästige Fallunterscheidung.
Also worth noting is `atan(y, x)`, the [two-argument arctangent](https://de.wikipedia.org/wiki/Arctan2). In other programming languages, it is often implemented as a function with its own name *atan2*.
This solves the problem of converting from Cartesian to polar coordinates without awkward case distinctions.
- `atan(y,x)` ist Winkel der Polarkoordinaten von (x,y) im Intervall $(-\pi,\pi]$. Im 1. und 4. Quadranten ist er also gleich `atan(y/x)`
- `atan(y,x)` is the angle of the polar coordinates of (x,y) in the interval $(-\pi,\pi]$. In the 1st and 4th quadrants, it is therefore equal to `atan(y/x)`
```{julia}
atan(3, -2), atan(-3, 2), atan(-3/2)
```
## Umwandlung Strings $\Longleftrightarrow$ Zahlen
## Conversion Strings $\Longleftrightarrow$ Numbers
Die Umwandlung ist mit den Funktionen `parse()` und `string()` möglich.
Conversion is possible with the functions `parse()` and `string()`.
```{julia}
parse(Int64, "1101", base=2)
@@ -749,7 +750,7 @@ string(1/7)
string(77, base=16)
```
Zur Umwandlung der numerischen Typen ineinander kann man die Typnamen verwenden. Typenamen sind auch Konstruktoren:
For conversion of numerical types into each other, one can use the type names. Type names are also constructors:
```{julia}
@@ -768,7 +769,7 @@ y = Float64(z)
## Literatur
## Literature
- D. Goldberg, [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://www.validlab.com/goldberg/paper.pdf)
- C. Vuik, [Some Disasters caused by numerical errors](http://ta.twi.tudelft.nl/users/vuik/wi211/disasters.html)
- C. Vuik, [Some Disasters caused by numerical errors](http://ta.twi.tudelft.nl/users/vuik/wi211/disasters.html)

View File

@@ -2,7 +2,7 @@
engine: julia
---
# Ein Fallbeispiel: Der parametrisierte Datentyp PComplex
# A Case Study: The Parametric Data Type PComplex
```{julia}
#| error: false
@@ -18,14 +18,14 @@ Base.active_module() = myactive_module()
```
Wir wollen als neuen numerischen Typen **komplexe Zahlen in Polardarstellung $z=r e^{i\phi}=(r,ϕ)$** einführen.
We want to introduce a new numeric type **complex numbers in polar representation $z=r e^{i\phi}=(r,\phi)$**.
- Der Typ soll sich in die Typhierarchie einfügen als Subtyp von 'Number'.
- $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.)
- The type should integrate into the type hierarchy as a subtype of 'Number'.
- $r$ and $\phi$ should be floating point numbers. (Unlike complex numbers in 'Cartesian' coordinates, restricting to integer values of r or $\phi$ makes little mathematical sense.)
## Die Definition von `PComplex`
## The Definition of `PComplex`
Ein erster Versuch könnte so aussehen:
A first attempt could look like this:
```{julia}
struct PComplex1{T <: AbstractFloat} <: Number
@@ -40,25 +40,25 @@ z2 = PComplex1{Float32}(12, 13)
:::{.callout-warning collapse="true" .titlenormal}
##
Es ist nicht möglich, in einer Julia-Session eine einmal definierte `struct` später umzudefinieren. Daher verwende ich verschiedene Namen. Eine andere Möglichkeit ist z.B. die Verwendung von [`ProtoStructs.jl`](https://juliahub.com/ui/Packages/General/ProtoStructs).
It is not possible to redefine a `struct` once it has been defined in a Julia session. Therefore, I use different names. Another possibility is, for example, the use of [`ProtoStructs.jl`](https://juliahub.com/ui/Packages/General/ProtoStructs).
:::
Julia stellt automatisch *default constructors* zur Verfügung:
Julia automatically provides *default constructors*:
- den Konstruktor `PComplex1`, bei dem der Typ `T` von den übergebenen Argumenten abgeleitet wird und
- Konstruktoren `PComplex{Float64},...` mit expliziter Typangabe. Hier wird versucht, die Argumente in den angeforderten Typ zu konvertieren.
- the constructor `PComplex1`, where the type `T` is inferred from the passed arguments, and
- constructors `PComplex{Float64},...` with explicit type specification. Here, the arguments are attempted to be converted to the requested type.
------
Wir wollen nun, dass der Konstruktor noch mehr tut.
In der Polardarstellung soll $0\le r$ und $0\le \phi<2\pi$ gelten.
We now want the constructor to do even more.
In the polar representation, we want $0\le r$ and $0\le \phi<2\pi$ to hold.
Wenn die übergebenen Argumente das nicht erfüllen, sollten sie entsprechend umgerechnet werden.
If the passed arguments do not satisfy this, they should be recalculated accordingly.
Dazu definieren wir einen _inner constructor_, der den _default constructor_ ersetzt.
To this end, we define an _inner constructor_ that replaces the _default constructor_.
- Ein _inner constructor_ ist eine Funktion innerhalb der `struct`-Definition.
- In einem _inner constructor_ kann man die spezielle Funktion `new` verwenden, die wie der _default constructor_ wirkt.
- An _inner constructor_ is a function within the `struct` definition.
- In an _inner constructor_, one can use the special function `new`, which acts like the _default constructor_.
```{julia}
@@ -73,18 +73,17 @@ struct PComplex{T <: AbstractFloat} <: Number
end
if r==0 ϕ=0 end # normalize r=0 case to phi=0
ϕ = mod(ϕ, 2π) # map phi into interval [0,2pi)
new(r, ϕ) # new() ist special function,
new(r, ϕ) # new() is special function,
end # available only inside inner constructors
end
```
```{julia}
#| echo: false
#| output: false
#=
in den ganzen quarto-runs wollen wir hier noch das default-show benutzen
in the whole quarto-runs we want to use the default show here
=#
zz = @which Base.show(stdout, PComplex{Float64}(2.,3.))
if zz.module != Base
@@ -94,9 +93,9 @@ end
```{julia}
z1 = PComplex{Float64}(-3.3, 7π+1)
```
Für die explizite Angabe eines *inner constructors* müssen wir allerdings einen Preis zahlen: Die sonst von Julia bereitgestellten *default constructors* fehlen.
For explicitly specifying an *inner constructor*, we pay a price: Julia's *default constructors* are no longer available.
Den Konstruktor, der ohne explizite Typangabe in geschweiften Klammern auskommt und den Typ der Argumente übernimmt, wollen wir gerne auch haben:
The constructor without explicit type specification in curly braces, which takes over the type of the arguments, is also desired:
```{julia}
PComplex(r::T, ϕ::T) where {T<:AbstractFloat} = PComplex{T}(r,ϕ)
@@ -105,43 +104,43 @@ z2 = PComplex(2.0, 0.3)
```
## Eine neue Schreibweise
## A New Notation
Julia verwendet `//` als Infix-Konstruktor für den Typ `Rational`. Sowas Schickes wollen wir auch.
Julia uses `//` as an infix constructor for the type `Rational`. We want something equally nice.
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:
In electronics/electrical engineering, [AC quantities are described by complex numbers.](https://en.wikipedia.org/wiki/Phasor_analysis) A representation of complex numbers by "magnitude" and "phase" is common and is often represented in so-called [phasor form](https://en.wikipedia.org/wiki/Phasor):
$$
z= r\enclose{phasorangle}{\phi} = 3.4\;\enclose{phasorangle}{45^\circ}
z= r\enclose{phasorangle}{\phi} = 3.4\;\enclose{phasorangle}{45^\circ}
$$
wobei man in der Regel den Winkel in Grad notiert.
where the angle is usually noted in degrees.
:::{.callout-note .titlenormal collapse="true"}
## Mögliche Infix-Operatoren in Julia
## Possible Infix Operators in Julia
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)
In Julia, a large number of Unicode characters are reserved for use as operators. The definitive list is in the [parser source code.](https://github.com/JuliaLang/julia/blob/eaa2c58aeb12f27c1d8c116ab111773a4fc4495f/src/julia-parser.scm#L13-L31)
Auf Details werden wir in einem späteren Kapitel noch eingehen.
Details will be discussed in a later chapter.
:::
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.
The angle bracket symbol `∠` is not available as an operator symbol. We use `⋖` as an alternative. This can be entered in Julia as `\lessdot<tab>`.
```{julia}
⋖(r::Real, ϕ::Real) = PComplex(r, π*ϕ/180)
z3 = 2. ⋖ 90.
```
(Die Typ-Annotation -- `Real` statt `AbstractFloat` -- ist ein Vorgriff auf kommende weitere Konstruktoren. Im Moment funktioniert der Operator `⋖` erstmal nur mit `Float`s.)
(The type annotation -- `Real` instead of `AbstractFloat` -- is a preview of further constructors to come. For now, the operator `⋖` only works with `Float`s.)
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).
Of course, we also want the output to look nice. Details can be found in the [documentation](https://docs.julialang.org/en/v1/manual/types/#man-custom-pretty-printing).
```{julia}
using Printf
function Base.show(io::IO, z::PComplex)
# wir drucken die Phase in Grad, auf Zehntelgrad gerundet,
# we print the phase in degrees, rounded to tenths of a degree,
p = z.ϕ * 180/π
sp = @sprintf "%.1f" p
print(io, z.r, "⋖", sp, '°')
@@ -151,22 +150,22 @@ end
```
## Methoden für `PComplex`
## Methods for `PComplex`
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.
For our type to be a proper member of the family of types derived from `Number`, we need a whole lot more. Arithmetic, comparison operators, conversions, etc. must be defined.
Wir beschränken uns auf Multiplikation und Quadratwurzeln.
We limit ourselves to multiplication and square roots.
:::{.callout-note collapse="true"}
## Module
## Modules
- Um die `methods` der existierenden Funktionen und Operationen zu ergänzen, muss man diese mit ihrem 'vollen Namen' ansprechen.
- Alle Objekte gehören zu einem Namensraum oder `module`.
- Die meisten Basisfunktionen gehören zum Modul `Base`, welches standardmäßig immer ohne explizites `using ...` geladen wird.
- Solange man keine eigenen Module definiert, sind die eigenen Definitionen im Modul `Main`.
- Das Macro `@which`, angewendet auf einen Namen, zeigt an, in welchem Modul der Name definiert wurde.
- To add to the `methods` of existing functions and operations, one must address them with their 'full name'.
- All objects belong to a namespace or `module`.
- Most basic functions belong to the module `Base`, which is always loaded without explicit `using ...` by default.
- As long as one does not define own modules, own definitions are in the module `Main`.
- The macro `@which`, applied to a name, shows in which module the name is defined.
```{julia}
f(x) = 3x^3
@@ -176,7 +175,7 @@ f(x) = 3x^3
```{julia}
wp = @which +
ws = @which(sqrt)
println("Modul für Addition: $wp, Modul für sqrt: $ws")
println("Module for addition: $wp, Module for sqrt: $ws")
```
:::
@@ -190,7 +189,7 @@ qwurzel(z::PComplex) = PComplex(sqrt(z.r), z.ϕ / 2)
#| output: false
#=
damit das length(methods(sqrt)) klappt
to make length(methods(sqrt)) work
=#
if hasmethod(sqrt, (PComplex,))
zz = @which Base.sqrt(PComplex{Float64}(1.,1.))
@@ -198,12 +197,12 @@ if hasmethod(sqrt, (PComplex,))
end
```
Die Funktion `sqrt()` hat schon einige Methoden:
The function `sqrt()` already has some methods:
```{julia}
length(methods(sqrt))
```
Jetzt wird es eine Methode mehr:
Now it will have one more method:
```{julia}
Base.sqrt(z::PComplex) = qwurzel(z)
@@ -214,26 +213,26 @@ length(methods(sqrt))
sqrt(z2)
```
und nun zur Multiplikation:
and now for multiplication:
```{julia}
Base.:*(x::PComplex, y::PComplex) = PComplex(x.r * y.r, x.ϕ + y.ϕ)
@show z1 * z2;
```
(Da das Operatorsymbol kein normaler Name ist, muss der Doppelpunkt bei der Zusammensetzung mit `Base.` sein.)
(Since the operator symbol is not a normal name, the colon must be with `Base.` in the composition.)
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.
We can, however, not yet multiply with other numeric types. One could now define a large number of corresponding methods. Julia provides one more mechanism for *numeric types* that simplifies this somewhat.
## Typ-Promotion und Konversion
## Type Promotion and Conversion
In Julia kann man bekanntlich die verschiedensten numerischen Typen nebeneinander verwenden.
In Julia, one can naturally use the most diverse numeric types side by side.
```{julia}
1//3 + 5 + 5.2 + 0xff
```
Wenn man in die zahlreichen Methoden schaut, die z.B. für `+` und `*` definiert sind, findet man u.a. eine Art 'catch-all-Definition'
If one looks at the numerous methods defined, for example, for `+` and `*`, one finds among them a kind of 'catch-all definition'
```julia
+(x::Number, y::Number) = +(promote(x,y)...)
@@ -242,15 +241,15 @@ Wenn man in die zahlreichen Methoden schaut, die z.B. für `+` und `*` definiert
(Die 3 Punkte sind der splat-Operator, der das von promote() zurückgegebene Tupel wieder in seine Bestandteile zerlegt.)
(The 3 dots are the splat operator, which decomposes the tuple returned by promote() back into its components.)
Da die Methode mit den Typen `(Number, Number)` sehr allgemein ist, wird sie erst verwendet, wenn spezifischere Methoden nicht greifen.
Since the method with the types `(Number, Number)` is very general, it is only used when more specific methods do not apply.
Was passiert hier?
What happens here?
### Die Funktion `promote(x,y,...)`
### The Function `promote(x,y,...)`
Diese Funktion versucht, alle Argumente in einen gemeinsamen Typen umzuwandeln, der alle Werte (möglichst) exakt darstellen kann.
This function attempts to convert all arguments to a common type that can represent all values (as precisely as possible).
```{julia}
promote(12, 34.555, 77/99, 0xff)
@@ -261,15 +260,15 @@ z = promote(BigInt(33), 27)
@show z typeof(z);
```
Die Funktion `promote()` verwendet dazu zwei Helfer, die Funktionen
`promote_type(T1, T2)` und `convert(T, x)`
The function `promote()` uses two helpers, the functions
`promote_type(T1, T2)` and `convert(T, x)`
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/)
As usual in Julia, one can extend this mechanism with [custom *promotion rules* and `convert(T,x)` methods.](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/)
### Die Funktion `promote_type(T1, T2,...)`
### The Function `promote_type(T1, T2,...)`
Sie ermittelt, zu welchem Typ umgewandelt werden soll. Argumente sind Typen, nicht Werte.
It determines to which type conversion should take place. Arguments are types, not values.
```{julia}
@show promote_type(Rational{Int64}, ComplexF64, Float32);
@@ -277,10 +276,10 @@ Sie ermittelt, zu welchem Typ umgewandelt werden soll. Argumente sind Typen, nic
### Die Funktion `convert(T,x)`
### The Function `convert(T,x)`
Die Methoden von
`convert(T, x)` wandeln `x` in ein Objekt vom Typ `T` um. Dabei sollte eine solche Umwandlung verlustfrei möglich sein.
The methods of
`convert(T, x)` convert `x` into an object of type `T`. Such a conversion should be lossless.
```{julia}
z = convert(Float64, 3)
@@ -294,7 +293,7 @@ z = convert(Int64, 23.00)
z = convert(Int64, 2.3)
```
Die spezielle Rolle von `convert()` liegt darin, dass es an verschiedenen Stellen _implizit_ und automatisch eingesetzt wird:
The special role of `convert()` lies in the fact that it is used *implicitly* and automatically at various points:
> [The following language constructs call convert](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/#When-is-convert-called?):
>
@@ -304,24 +303,24 @@ Die spezielle Rolle von `convert()` liegt darin, dass es an verschiedenen Stelle
- Assigning to a variable with a declared type (e.g. local x::T) converts to that type.
- A function with a declared return type converts its return value to that type.
-- und natürlich in `promote()`
-- and of course in `promote()`
Für selbstdefinierte Datentypen kann man convert() um weitere Methoden ergänzen.
For self-defined data types, one can extend convert() with further methods.
Für Datentypen innerhalb der Number-Hierarchie gibt es wieder eine 'catch-all-Definition'
For data types within the Number hierarchy, there is again a 'catch-all definition'
```julia
convert(::Type{T}, x::Number) where {T<:Number} = T(x)
```
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.)
So: If for a type `T` from the hierarchy `T<:Number` there exists a constructor `T(x)` with a numeric argument `x`, then this constructor `T(x)` is automatically used for conversions. (Of course, more specific methods for `convert()` can also be defined, which then have priority.)
### Weitere Konstruktoren für `PComplex`
### Further Constructors for `PComplex`
```{julia}
## (a) r, ϕ beliebige Reals, z.B. Integers, Rationals
## (a) r, ϕ arbitrary reals, e.g. Integers, Rationals
PComplex{T}(r::T1, ϕ::T2) where {T<:AbstractFloat, T1<:Real, T2<: Real} =
PComplex{T}(convert(T, r), convert(T, ϕ))
@@ -329,8 +328,8 @@ PComplex{T}(r::T1, ϕ::T2) where {T<:AbstractFloat, T1<:Real, T2<: Real} =
PComplex(r::T1, ϕ::T2) where {T1<:Real, T2<: Real} =
PComplex{promote_type(Float64, T1, T2)}(r, ϕ)
## (b) Zur Umwandlung von Reals: Konstruktor mit
## nur einem Argument r
## (b) For conversion from reals: constructor with
## only one argument r
PComplex{T}(r::S) where {T<:AbstractFloat, S<:Real} =
PComplex{T}(convert(T, r), convert(T, 0))
@@ -338,7 +337,7 @@ PComplex{T}(r::S) where {T<:AbstractFloat, S<:Real} =
PComplex(r::S) where {S<:Real} =
PComplex{promote_type(Float64, S)}(r, 0.0)
## (c) Umwandlung Complex -> PComplex
## (c) Conversion Complex -> PComplex
PComplex{T}(z::Complex{S}) where {T<:AbstractFloat, S<:Real} =
PComplex{T}(abs(z), angle(z))
@@ -349,8 +348,7 @@ PComplex(z::Complex{S}) where {S<:Real} =
```
Ein Test der neuen Konstruktoren:
A test of the new constructors:
```{julia}
@@ -359,9 +357,9 @@ Ein Test der neuen Konstruktoren:
```
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.
We now still need *promotion rules* that determine which type should result from `promote(x::T1, y::T2)`. This internally extends `promote_type()` with the necessary further methods.
### *Promotion rules* für `PComplex`
### *Promotion rules* for `PComplex`
```{julia}
@@ -371,15 +369,16 @@ Base.promote_rule(::Type{PComplex{T}}, ::Type{S}) where {T<:AbstractFloat,S<:Rea
Base.promote_rule(::Type{PComplex{T}}, ::Type{Complex{S}}) where
{T<:AbstractFloat,S<:Real} = PComplex{promote_type(T,S)}
```
1. Regel:
: 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.
1. Rule:
: If a `PComplex{T}` and an `S<:Real` meet, then both should be converted to `PComplex{U}`, where `U` is the type to which `S` and `T` can both be converted (_promoted_).
2. Regel
: 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.
2. Rule
: If a `PComplex{T}` and a `Complex{S}` meet, then both should be converted to `PComplex{U}`, where `U` is the type to which `S` and `T` can be converted.
Damit klappt nun die Multiplikation mit beliebigen numerischen Typen.
Now multiplication with arbitrary numeric types works.
```{julia}
z3, 3z3
@@ -391,9 +390,10 @@ z3, 3z3
:::{.callout-caution icon="false" collapse="true" .titlenormal}
## Zusammenfassung: unser Typ `PComplex`
## Summary: our type `PComplex`
```julia
struct PComplex{T <: AbstractFloat} <: Number
@@ -407,7 +407,7 @@ struct PComplex{T <: AbstractFloat} <: Number
end
if r==0 ϕ=0 end # normalize r=0 case to phi=0
ϕ = mod(ϕ, 2π) # map phi into interval [0,2pi)
new(r, ϕ) # new() ist special function,
new(r, ϕ) # new() is special function,
end # available only inside inner constructors
end
@@ -443,7 +443,7 @@ PComplex(z::Complex{S}) where {S<:Real} =
using Printf
function Base.show(io::IO, z::PComplex)
# wir drucken die Phase in Grad, auf Zehntelgrad gerundet,
# we print the phase in degrees, rounded to tenths of a degree,
p = z.ϕ * 180/π
sp = @sprintf "%.1f" p
print(io, z.r, "⋖", sp, '°')
@@ -465,7 +465,7 @@ Base.promote_rule(::Type{PComplex{T}}, ::Type{Complex{S}}) where
:::{.content-hidden unless-format="xxx"}
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.
Now something like `PComplex(1, 0)` does not work yet. We also want to allow other real types for `r` and `ϕ`. For simplicity, we convert everything to `Float64` here. We proceed analogously if only one real or complex argument is used.
```julia
PComplex(r::Real, ϕ::Real) = PComplex(Float64(r), Float64(ϕ))

View File

@@ -9,67 +9,68 @@ engine: julia
using InteractiveUtils
```
# Grundlagen der Syntax
# Fundamentals of Syntax
## Namen von Variablen, Funktionen, Typen etc.
## Names of Variables, Functions, Types, etc.
- Namen können Buchstaben, Ziffern, den Unterstrich `_` und das Ausrufezeichen `!` enthalten.
- Das erste Zeichen muss ein Buchstabe oder ein Unterstrich sein.
- Groß- und Kleinbuchstaben werden unterschieden: `Nmax` und `NMAX` sind verschiedene Variablen.
- Als Zeichensatz wird [Unicode](https://home.unicode.org/) verwendet. Damit stehen über 150 Schriften und zahlreiche Symbole zur Verfügung.
- Es gibt eine kurze [Liste reservierter Schlüsselwörter](https://docs.julialang.org/en/v1/base/base/#Keywords): `if, then, function, true, false,...`
- Names may contain letters, digits, underscores `_`, and exclamation marks `!`.
- The first character must be a letter or an underscore.
- Case is significant: `Nmax` and `NMAX` are different variables.
- The character set used is [Unicode](https://home.unicode.org/), which provides access to over 150 scripts and numerous symbols.
- There is a short [list of reserved keywords](https://docs.julialang.org/en/v1/base/base/#Keywords): `if, then, function, true, false,...`
:::{.callout-tip}
## Beispiel
## Example
zulässig: `i, x, Ω, x2, DieUnbekannteZahl, neuer_Wert, 🎷, Zähler, лічильник, einself!!!!,...`
Permissible: `i, x, Ω, x2, DieUnbekannteZahl, neuer_Wert, 🎷, Zähler, лічильник, einself!!!!,...`
unzulässig: `Uwe's_Funktion, 3achsen, A#B, $this_is_not_Perl, true,...`
Impermissible: `Uwe's_Funktion, 3achsen, A#B, $this_is_not_Perl, true,...`
:::
----
:::{.callout-note }
## Anmerkung
## Note:
Neben den *reserved keywords* der Kernsprache sind zahlreiche weitere Funktionen und Objekte vordefiniert, wie z.B. die mathematischen Funktionen `sqrt(), log(), sin()`.
Diese Definitionen finden sich in dem Modul `Base`, welches Julia beim Start automatisch lädt.
Namen aus `Base` können umdefiniert werden, solange sie noch nicht verwendet wurden:
In addition to the *reserved keywords* of the core language, numerous additional functions and objects are predefined, such as the mathematical functions `sqrt(), log(), sin()`.
These definitions are found in the module `Base`, which Julia loads automatically at startup.
Names from `Base` can be redefined as long as they have not yet been used:
```{julia}
#| error: true
log = 3
1 + log
```
Jetzt ist natürlich der Logarithmus kaputt:
Now, of course, the logarithm is broken:
```{julia}
#| error: true
x = log(10)
```
(siehe auch <https://stackoverflow.com/questions/65902105/how-to-reset-any-function-in-julia-to-its-original-state>)
(see also <https://stackoverflow.com/questions/65902105/how-to-reset-any-function-in-julia-to-its-original-state>)
:::
## Anweisungen
## Statements
- Im Normalfall enthält eine Zeile eine Anweisung.
- Wenn eine Anweisung am Zeilenende als unvollständig erkennbar ist durch
- offene Klammern
- Operationszeichen,
- In normal circumstances, each line contains one statement.
- If a statement is recognizable as incomplete at the end of a line through
- open parentheses
- operators,
dann wird die nächste Zeile als Fortsetzung aufgefasst.
- Mehrere Anweisungen pro Zeile können durch Semikolon getrennt werden.
- Im interaktiven Betrieb (REPL oder Notebook) unterdrückt ein Semikolon nach der letzten Anweisung die Ausgabe des Ergebnisses dieser Anweisung.
then the next line is regarded as a continuation.
- Multiple statements per line can be separated by semicolons.
- In interactive mode (REPL or notebook), a semicolon after the last statement suppresses the output of the result of that statement.
:::{.callout-tip}
## Beispiel
## Example:
Im interaktiven Betrieb wird der Wert der letzten Anweisung auch ohne explizites `print()` ausgegeben:
In interactive mode, the value of the last statement is also displayed without explicit `print()`:
```{julia}
println("Hallo 🌍!")
x = sum([i^2 for i=1:10])
```
Das Semikolon unterdrückt das:
The semicolon suppresses this:
```{julia}
println("Hallo 🌍!")
x = sum([i^2 for i=1:10]);
@@ -81,14 +82,14 @@ x = sum([i^2 for i=1:10]);
:::{.callout-warning }
Bei mehrzeiligen Anweisungen muss die fortzusetzende Zeile mit einer offenen Operation oder Klammer enden:
For multi-line statements, the line to be continued must end with an open operator or parenthesis.
```{julia}
x = sin(π/2) +
3 * cos(0)
```
Also geht das Folgende schief, aber leider **ohne eine Fehlermeldung**!
Therefore, the following goes wrong, but—unfortunately—**without an error message**!
```{julia}
#| error: true
#| warning: true
@@ -96,9 +97,9 @@ x = sin(π/2)
+ 3 * cos(0)
println(x)
```
Hier wird das `+` in der zweiten Zeile als Präfix-Operator (Vorzeichen) interpretiert. Damit sind 1. und 2. Zeile jeweils für sich vollständige, korrekte Ausdrücke (auch wenn die 2. Zeile natürlich völlig nutzlos ist) und werden auch so abgearbeitet.
Here, the `+` in the second line is interpreted as a prefix operator (sign). Thus, lines 1 and 2 are each complete, correct expressions on their own (even though line 2 is of course completely useless) and are processed as such.
Moral: Wenn man längere Ausdrücke auf mehrere Zeilen aufteilen will, sollte man immer eine Klammer aufmachen. Dann ist egal, wo der Zeilenumbruch ist:
**Moral:** If you want to split longer expressions across multiple lines, you should always open a parenthesis. Then it doesn't matter where the line break occurs.
```{julia}
x = ( sin(π/2)
+ 3 * cos(0) )
@@ -107,26 +108,24 @@ println(x)
:::
## Kommentare
## Comments
Julia kennt 2 Arten von Kommentaren im Programmtext:
Julia knows two types of comments in program text:
```{julia}
# Einzeilige Kommentare beginnen mit einem Doppelkreuz.
# Single-line comments begin with a hash symbol.
x = 2 # alles vom '#' bis zum Zeilenende ist ein Kommentar und wird ignoriert. x = 3
x = 2 # everything from '#' to the end of the line is a comment and is ignored. x = 3
```
```{julia}
#=
Ein- und mehrzeilige Kommentare können zwischen #= ... =# eingeschlossen werden.
Dabei sind verschachtelte Kommentare möglich.
#=
d.h., anders als in C/C++/Java endet der Kommentar nicht mit dem ersten
Kommentar-Endezeichen, sondern die #=...=# - Paare wirken wie Klammern.
=#
Der automatische 'syntax highlighter' weiss das leider noch nicht, wie die wechselnde
Graufärbung dieses Kommentars zeigt.
Single and multi-line comments can be enclosed between `#= ... =#`. Nested comments are possible.
`#=`
i.e., unlike in C/C++/Java, the comment does not end with the first comment-end character, but the `#=...=#` pairs act like parentheses.
`=#`
The automatic 'syntax highlighter' does not yet know this, as the alternating
gray shading of this comment shows.
=#
@@ -134,16 +133,16 @@ x #= das ist ein seltener Variablenname! =# = 3
```
## Datentypen Teil I
## Data Types Part I
- Julia ist eine [stark typisierte](https://de.wikipedia.org/wiki/Starke_Typisierung) Sprache. Alle Objekte haben einen Typ. Funktionen/Operationen erwarten Argumente mit dem richtigen Typ.
- Julia ist eine [dynamisch typisierte](https://de.wikipedia.org/wiki/Dynamische_Typisierung) Sprache. Variablen haben keinen Typ. Sie sind Namen, die durch Zuweisung `x = ...` an Objekte gebunden werden können.
- Wenn man vom „Typ einer Variablen“ spricht, meint man den Typ des Objektes, das der Variablen gerade zugewiesen ist.
- Funktionen/Operatoren können verschiedene *methods* für verschiedene Argumenttypen implementieren.
- Abhängig von den konkreten Argumenttypen wird dann bei Verwendung einer Funktion entschieden, welche Methode benutzt wird ([*dynamic dispatch*](https://en.wikipedia.org/wiki/Dynamic_dispatch)).
- Julia is a [strongly typed](https://de.wikipedia.org/wiki/Starke_Typisierung) language. All objects have a type. Functions and operations expect arguments of the correct type.
- Julia is a [dynamically typed](https://de.wikipedia.org/wiki/Dynamische_Typisierung) language. Variables have no type. They are names that can be bound to objects via assignment `x = ...`.
- When speaking of the "type of a variable", one means the type of the object currently assigned to the variable.
- Functions and operators can implement different *methods* for different argument types.
- Depending on the concrete argument types, it is decided at function usage which method is used ([*dynamic dispatch*](https://en.wikipedia.org/wiki/Dynamic_dispatch)).
Einfache Basistypen sind z.B.:
Simple basic types are, for example:
```
Int64, Float64, String, Char, Bool
@@ -176,58 +175,58 @@ x = 3 > π
x, typeof(x), sizeof(x)
```
- `sizeof()` liefert die Größe eines Objekts oder Typs in Bytes (1 Byte = 8 Bit)
- 64bit Ganzzahlen und 64bit Gleitkommazahlen entsprechen dem Befehlssatz moderner Prozessoren und sind daher die numerischen Standardtypen.
- Zeichen/*chars* `'A'` und Zeichenketten/*strings* `"A"` der Länge 1 sind verschiedene Objekte.
- `sizeof()` returns the size of an object or type in bytes (1 byte = 8 bits)
- 64-bit integers and 64-bit floating-point numbers correspond to the instruction set of modern processors and are therefore the standard numeric types.
- Characters/*chars* `'A'` and strings/*strings* `"A"` of length 1 are different objects.
## Ablaufsteuerung
## Control Flow
### `if`-Blöcke
### `if` Blocks
- Ein `if`-Block *kann* **beliebig viele** `elseif`-Zweige und als letztes maximal **einen** `else`-Zweig enthalten.
- Der Block hat einen Wert, den Wert der letzten ausgeführten Anweisung.
- An `if` block can contain any number of `elseif` branches and, at the end, at most one `else` branch.
- The block has a value: the value of the last executed statement.
```{julia}
x = 33
y = 44
z = 34
if x < y && z != x # elseif- und else-Blöcke sind optional
if x < y && z != x # elseif- and else-branches are optional
println("yes")
x += 10
elseif x < z # beliebig viele elseif-Blöcke
elseif x < z # any number of elseif branches
println(" x is smaller than z")
elseif x == z+1
println(" x is successor of z")
else # maximal ein else-Block
else # at most one else block
println("Alles falsch")
end # Wert des gesamten Blocks ist der Wert der
# letzten ausgeführten Auswertung
end # value of the entire block is the value of the
# last evaluated statement
```
Kurze Blöcke kann man in eine Zeile schreiben:
Short blocks can be written on one line:
```{julia}
if x > 10 println("x is larger than 10") end
```
Der Wert eines `if`-Blocks kann natürlich zugewiesen werden:
The value of an `if` block can of course be assigned:
```{julia}
y = 33
z = if y > 10
println("y is larger than 10")
y += 1
end
println("y is larger than 10")
y += 1
end
z
```
### Auswahloperator (ternary operator) `test ? exp1 : exp2`
### Conditional Operator (ternary operator) `test ? exp1 : exp2`
```{julia}
x = 20
y = 15
z = x < y ? x+1 : y+1
```
ist äquivalent zu
is equivalent to
```{julia}
z = if x < y
@@ -237,9 +236,9 @@ z = if x < y
end
```
## Vergleiche, Tests, Logische Operationen
## Comparisons, Tests, Logical Operations
### Arithmetische Vergleiche
### Arithmetic Comparisons
- `==`
- `!=`, `≠`
@@ -248,56 +247,56 @@ z = if x < y
- `<`
- `<=`, `≤`
Wie üblich, ist der Test auf Gleichheit `==` vom Zuweisungsoperator `=` zu unterscheiden. Vergleichen lässt sich so gut wie alles:
As usual, the equality test `==` must be distinguished from the assignment operator `=`. Almost anything can be compared.
```{julia}
"Aachen" < "Leipzig", 10 ≤ 10.01, [3,4,5] < [3,6,2]
```
Nun ja, fast alles:
Well, almost anything:
```{julia}
3 < "vier"
```
Die Fehlermeldung zeigt ein paar Grundprinzipien von Julia:
The error message shows a few fundamental principles of Julia:
- Operatoren sind auch nur Funktionen: `x < y` wird zum Funktionsaufruf `isless(x, y)`.
- Funktionen (und damit Operatoren) können verschiedene *methods* für verschiedene Argumenttypen implementieren.
- Abhängig von den konkreten Argumenttypen wird beim Aufruf der Funktion entschieden, welche Methode benutzt wird ([*dynamic dispatch*](https://en.wikipedia.org/wiki/Dynamic_dispatch)).
- Operators are also just functions: `x < y` becomes the function call `isless(x, y)`.
- Functions (and thus operators) can implement different *methods* for different argument types.
- Depending on the concrete argument types, it is decided at function call which method is used ([*dynamic dispatch*](https://en.wikipedia.org/wiki/Dynamic_dispatch)).
Man kann sich alle Methoden zu einer Funktion anzeigen lassen. Das gibt einen Einblick in das komplexe Typssystem von Julia:
One can display all methods for a function. This provides insight into Julia's complex type system:
```{julia}
methods(<)
```
Zuletzt noch: Vergleiche können gekettet werden.
Finally: comparisons can be chained.
```{julia}
10 < x ≤ 100 # das ist äquivalent zu
10 < x ≤ 100 # this is equivalent to
# 10 < x && x ≤ 100
```
### Tests
Einge Funktionen vom Typ `f(c::Char) -> Bool`
Some functions of type `f(c::Char) -> Bool`
```{julia}
isnumeric('a'), isnumeric('7'), isletter('a')
```
und vom Typ `f(s1::String, s2::String) -> Bool`
and of type `f(s1::String, s2::String) -> Bool`
```{julia}
contains("Lampenschirm", "pensch"), startswith("Lampenschirm", "Lamb"), endswith("Lampenschirm", "rm")
```
- Die Funktion `in(item, collection) -> Bool` testet, ob `item` in `collection` ist.
- Sie hat auch das Alias ` ∈(item, collection)` und
- sowohl `in` als auch `∈` können auch als Infix-Operatoren geschrieben werden.
- The function `in(item, collection) -> Bool` tests whether `item` is in `collection`.
- It also has the alias ` ∈(item, collection)` and
- both `in` and `∈` can also be written as infix operators.
```{julia}
x = 3
@@ -307,23 +306,24 @@ x in [1, 2, 3, 4, 5]
x ∈ [1, 2, 33, 4, 5]
```
### Logische Operationen: `&&`, `||`, `!`
### Logical Operations: `&&`, `||`, `!`
```{julia}
3 < 4 && !(2 > 8) && !contains("aaa", "b")
```
#### Bedingte Auswertung (_short circuit evaluation_)
#### Conditional Evaluation (_short circuit evaluation_)
- in `a && b` wird `b` nur ausgewertet, wenn `a == true`
- in `a || b` wird `b` nur ausgewertet, wenn `a == false`
- in `a && b` `b` is only evaluated if `a == true`
- in `a || b` `b` is only evaluated if `a == false`
(i) Damit kann `if test statement end` auch als `test && statement` geschrieben werden.
(i) Thus, `if test statement end` can also be written as `test && statement`.
(ii) Damit kann `if !test statement end` als `test || statement` geschrieben werden.
(ii) Thus, `if !test statement end` can be written as `test || statement`.
As an example^[from the [Julia documentation](https://docs.julialang.org/en/v1/manual/control-flow/#Short-Circuit-Evaluation)] here is an implementation of the factorial function:
Als Beispiel^[aus der [Julia-Dokumentation](https://docs.julialang.org/en/v1/manual/control-flow/#Short-Circuit-Evaluation)] hier eine Implementierung der Fakultätsfunktion *(factorial)*:
```{julia}
function fact(n::Int)
n >= 0 || error("n must be non-negative")
@@ -336,23 +336,23 @@ fact(5)
Natürlich kann man alle diese Tests auch Variablen vom Typ `Bool` zuordnen und
diese Variablen können als Tests in `if`- und `while`-Blöcken verwendet werden:
Of course, all these tests can also be assigned to variables of type `Bool` and
these variables can be used as tests in `if` and `while` blocks:
```{julia}
x = 3 < 4
y = 5 ∈ [1, 2, 5, 7]
z = x && y
if z # äquivalent zu: if 3 < 4 && 5 in [1,2,5,7]
if z # equivalent to: if 3 < 4 && 5 in [1,2,5,7]
println("Stimmt alles!")
end
```
- In Julia müssen alle Tests in einem logischen Ausdruck vom Typ `Bool` sein.
- Es gibt keine implizite Konvertierung à la *"0 is false and 1 (or anything != 0) is true"*
- Wenn `x` ein numerischer Typ ist, dann muss daher das C-Idiom `if(x)` als `if x != 0` geschrieben werden.
- Es gibt eine Ausnahme zur Unterstützung der _short circuit evaluation_:
- bei den Konstrukten `a && b && c...` bzw `a || b || c...` muss der letzte Teilausdruck nicht vom Typ `Bool` sein, wenn diese Konstrukte nicht als Tests in `if` oder `while` verwendet werden:
- In Julia, all tests in a logical expression must be of type `Bool`.
- There is no implicit conversion such as *"0 is false and 1 (or anything != 0) is true"*
- If `x` is a numeric type, then the C idiom `if(x)` must be written as `if x != 0`.
- There is an exception to support the _short circuit evaluation_:
- in the constructs `a && b && c...` or `a || b || c...` the last subexpression does not need to be of type `Bool` if these constructs are not used as tests in `if` or `while`:
```{julia}
@@ -365,9 +365,9 @@ z = 3 < 4 && 10 < 50 && sqrt(3^3)
z, typeof(z)
```
## Schleifen *(loops)*
## Loops *(loops)*
### Die `while` ("solange")-Schleife
### The `while` ("while") loop
Syntax:
@@ -376,19 +376,19 @@ while *condition*
*loop body*
end
```
Eine Reihe von Anweisungen (der Schleifenkörper) wird immer wieder abgearbeitet, solange eine Bedingung erfüllt ist.
A series of statements (the loop body) is repeatedly executed as long as a condition is satisfied.
```{julia}
i = 1 # typischerweise braucht der Test der
# while-Schleife eine Vorbereitung ...
i = 1 # typically the test of the
# while loop needs preparation ...
while i < 10
println(i)
i += 2 # ... und ein update
i += 2 # ... and an update
end
```
Der Körper einer `while`- und `for`-Schleife kann die Anweisungen `break` und `continue` enthalten. `break` stoppt die Schleife, `continue` überspringt den Rest des Schleifenkörpers und beginnt sofort mit dem nächsten Schleifendurchlauf.
The body of a `while` and `for` loop can contain the statements `break` and `continue`. `break` stops the loop, `continue` skips the rest of the loop body and immediately starts the next loop iteration.
```{julia}
i = 0
@@ -396,20 +396,20 @@ while i<10
i += 1
if i == 3
continue # beginne sofort nächsten Durchlauf,
end # überspringe Rest des Schleifenkörpers
continue # start next iteration immediately,
end # skip rest of loop body
println("i = $i")
if i ≥ 5
break # breche Schleife ab
break # break loop
end
end
println("Fertig!")
```
Mit `break` kann man auch Endlosschleifen verlassen:
With `break` one can also exit infinite loops:
```{julia}
i = 1
@@ -421,7 +421,7 @@ while true
end
```
### `for`-Schleifen
### `for` Loops
Syntax:
@@ -431,9 +431,9 @@ for *var* in *iterable container*
end
```
Der Schleifenkörper wird für alle Items aus einem Container durchlaufen.
The loop body is executed for all items from a container.
Statt `in` kann immer auch $\in$ verwendet werden. Im Kopf einer `for`-Schleife kann auch `=` verwendet werden.
Instead of `in`, $\in$ can always be used. In the header of a `for` loop, `=` can also be used.
```{julia}
for i ∈ ["Mutter", "Vater", "Tochter"]
@@ -442,8 +442,8 @@ end
```
Oft benötigt man einen numerischen Schleifenzähler. Dafür gibt es das *range*-Konstrukt. Die einfachsten Formen sind
`Start:Ende` und `Start:Schrittweite:Ende`.
Often a numerical loop counter is needed. For this purpose, there is the *range* construct. The simplest forms are
`Start:End` and `Start:Step:End`.
```{julia}
endwert = 5
@@ -469,9 +469,9 @@ for k = 14 : -2.5 : 1 print(" $k") end
#### Geschachtelte Schleifen _(nested loops)_
#### Nested Loops _(nested loops)_
Ein `break` beendet die innerste Schleife.
A `break` ends the innermost loop.
```{julia}
for i = 1:3
@@ -484,22 +484,22 @@ for i = 1:3
end
```
Man kann *nested loops* auch in einer `for`-Anweisung zusammenfassen. Dann beendet ein `break` die Gesamtschleife.
*Nested loops* can also be combined in a single `for` statement. Then a `break` ends the entire loop.
```{julia}
for i = 1:3, j=1:3 # im Prinzip dasselbe wie oben, aber:
for i = 1:3, j=1:3 # essentially the same as above, but:
println( (i,j) )
if j == 2
break # break bricht hier die Gesamtschleife ab
break # break ends the entire loop here
end
end
```
:::{.callout-important .titlenormalxx}
## **Wichtig:** Die Semantik ist völlig anders, als bei C-artigen `for`-Schleifen!
## **Important:** The semantics are completely different from C-style `for` loops!
**Bei jedem Schleifendurchlauf wird die Laufvariable neu mit dem nächsten Element aus dem Container initialisiert.**
**In each loop iteration, the loop variable is re-initialized with the next element from the container.**
```{julia}
@@ -512,11 +512,11 @@ end
-------
Die C-Semantik von `for(i=1; i<5; i++)` entspricht der `while`-Schleife:
The C semantics of `for(i=1; i<5; i++)` corresponds to the `while` loop:
```
i = 1
while i<5
*loop body* # hier kann auch wirksam an i rumgepfuscht werden
*loop body* # here one can also mess with i effectively
i += 1
end
```
@@ -524,68 +524,68 @@ end
## Unicode
Julia verwendet Unicode als Zeichensatz. Damit können für Variablen, Funktionen etc auch Bezeichner aus nicht-lateinischen Schriften (zB Kyrillisch, Koreanisch, Sanskrit, Runen,
Emoji,...) verwendet werden. Die Frage, wie man solche Zeichen in seinem Editor eingeben kann und ob der verwendete Bildschirm-Font sie darstellen kann, ist nicht Julias Problem.
Julia uses Unicode as its character set. This allows identifiers from non-Latin scripts (e.g., Cyrillic, Korean, Sanskrit, runes,
emojis,...) to be used for variables, functions, etc. The question of how one can enter such characters in their editor and whether the used screen font can display them is not Julia's problem.
- Einige Unicode-Zeichen, z.B. `≤, ≠, ≥, π, ∈, √`, können anstelle von `<=, !=, >=, pi, in, sqrt` verwendet werden.
- Some Unicode characters, e.g., `≤, ≠, ≥, π, ∈, √`, can be used instead of `<=, !=, >=, pi, in, sqrt`.
- über 3000 Unicode-Zeichen können in Julia in einer LaTeX-ähnlichen Weise mit der Tab-Vervollständigung eingegeben werden.
- `\alpha<TAB>` wird zu `α`,
- `\euler<TAB>` wird zu `` (Eulersche Zahl `exp(1)`, [spezielles Schreibschrift-e, `U+0212F`](https://www.htmlsymbol.com/unicode-code/212f.html))
- `\le<TAB>` wird zu `≤`,
- `\in<TAB>` wird zu `∈`,
- `\:rainbow:<TAB>` wird zu `🌈`
[Hier geht es zur Liste.](https://docs.julialang.org/en/v1/manual/unicode-input/)
- Over 3000 Unicode characters can be entered in Julia in a LaTeX-like manner using tab completion.
- `\alpha<TAB>` becomes `α`,
- `\euler<TAB>` becomes `` (Euler's number `exp(1)`, [special script e, `U+0212F`](https://www.htmlsymbol.com/unicode-code/212f.html))
- `\le<TAB>` becomes `≤`,
- `\in<TAB>` becomes `∈`,
- `\:rainbow:<TAB>` becomes `🌈`
[Here is the list.](https://docs.julialang.org/en/v1/manual/unicode-input/)
## Eigenheiten und Stolperfallen der Syntax
## Idiosyncrasies and Pitfalls of Syntax
- Man kann den Multiplikationsoperator `*` nach einer numerischen Konstanten weglassen, wenn eine Variable, Funktion oder öffnende Klammer folgt.
- After a numeric constant, the multiplication operator `*` can be omitted when a variable, function, or opening parenthesis follows.
```
z = 3.4x + 2(x+y) + xy
```
ist daher korrektes Julia. Beachte allerdings, dass der Term `xy` als eine Variable mit dem Namen xy interpretiert wird __und nicht__ als Produkt von x und y!
is therefore valid Julia. Note, however, that the term `xy` is interpreted as a single variable named xy __and not__ as the product of x and y!
- Diese Regel hat ein paar Tücken:
- This rule has a few pitfalls:
Das funktioniert wie erwartet:
This works as expected:
```{julia}
e = 7
3e
```
Hier wird die Eingabe als Gleitkommazahl interpretiert -- und `3E+2` oder `3f+2` (Float32) ebenso.
Here, the input is interpreted as a floating-point number -- and `3E+2` or `3f+2` (Float32) as well.
```{julia}
3e+2
```
Ein Leerzeichen schafft Eindeutigkeit:
A space creates clarity:
```{julia}
3e + 2
```
Das funktioniert:
This works:
```{julia}
x = 4
3x + 3
```
...und das nicht. `0x`, `0o`, `0b` wird als Anfang einer Hexadezimal-, Oktal- bzw. Binärkonstanten interpretiert.
...and this does not. `0x`, `0o`, `0b` are interpreted as the beginning of a hexadecimal, octal, or binary constant.
```{julia}
3y + 0x
```
- Es gibt noch ein paar andere Fälle, bei denen die sehr kulante Syntax zu Überraschungen führt.
- There are a few other cases where the very permissive syntax leads to surprises.
```{julia}
Wichtig = 21
Wichtig! = 42 # Bezeichner können auch ein ! enthalten
Wichtig! = 42 # identifiers can also contain !
(Wichtig, Wichtig!)
```
@@ -596,28 +596,24 @@ Wichtig!=88
```
Julia interpretiert das als Vergleich `Wichtig != 88`.
Leerzeichen helfen:
Julia interprets this as the comparison `Wichtig != 88`.
Spaces help:
```{julia}
Wichtig! = 88
Wichtig!
```
- Operatoren der Form `.*`, `.+`,... haben in Julia eine spezielle Bedeutung (*broadcasting*, d.h., vektorisierte Operationen).
- Operators of the form `.*`, `.+`,... have a special meaning in Julia (*broadcasting*, i.e., vectorized operations).
```{julia}
1.+2.
```
Wieder gilt: Leerzeichen schaffen Klarheit!
Again, spaces create clarity!
```{julia}
1. + 2.
```

View File

@@ -15,22 +15,22 @@ Base.active_module() = myactive_module()
```
# Das Typsystem von Julia
# The Julia Type System
Man kann umfangreiche Programme in Julia schreiben, ohne auch nur eine einzige Typdeklaration verwenden zu müssen. Das ist natürlich Absicht und soll die Arbeit der Anwender vereinfachen.
One can write extensive programs in Julia without using a single type declaration. This is, of course, intentional and should simplify the work of users.
Wir blicken jetzt trotzdem mal unter die Motorhaube.
However, we will now take a look under the hood.
## Die Typhierarchie am Beispiel der numerischen Typen
## The Type Hierarchy: A Case Study with Numeric Types
Das Typsystem hat die Struktur eines Baums, dessen Wurzel der Typ `Any` ist. Mit den Funktionen `subtypes()` und `supertype()` kann man den Baum erforschen. Sie zeigen alle Kinder bzw. die Mutter eines Knotens an.
The type system has the structure of a tree whose root is the type `Any`. The functions `subtypes()` and `supertype()` can be used to explore the tree. They show all children or the parent of a node.
```{julia}
subtypes(Int64)
```
Das Ergebnis ist eine leere Liste von Typen. `Int64` ist ein sogenannter **konkreter Typ** und hat keine Untertypen.
The result is an empty list of types. `Int64` is a so-called **concrete type** and has no subtypes.
Wir klettern jetzt mal die Typhierarchie auf diesem Ast nach oben bis zur Wurzel (Informatiker-Bäume stehen bekanntlich immer auf dem Kopf).
Let's now climb the type hierarchy on this branch to the root (in computer science, trees are always standing on their heads).
```{julia}
supertype(Int64)
```
@@ -46,72 +46,69 @@ supertype(Real)
```{julia}
supertype(Number)
```
Das wäre übrigens auch schneller gegangen: Die Funktion `supertypes()` (mit Plural-s) zeigt alle Vorfahren an.
This would have been faster, by the way: The function `supertypes()` (with plural-s) shows all ancestors.
```{julia}
supertypes(Int64)
```
Nun kann man sich die Knoten angucken:
Now one can look at the nodes:
{{< embed ../notebooks/nb-types.ipynb#nb3 >}}
Mit einer kleinen rekursiven Funktion kann man schnell einen ganzen (Unter-)Baum ausdrucken:
With a small recursive function, one can quickly print out an entire (sub-)tree:
{{< embed ../notebooks/nb-types.ipynb#nb1 >}}
::::{.content-hidden unless-format="xxx"}
...und natürlich gibt es da auch ein Julia-Paket:
...and of course, there is also a Julia package for this:
{{< embed ../notebooks/nb-types.ipynb#nb2 >}}
:::
::::
Hier das Ganze nochmal als Bild (gemacht mit LaTeX/[TikZ](https://tikz.dev/tikz-trees))
Here again as an image (made with LaTeX/[TikZ](https://tikz.dev/tikz-trees))
::: {.content-visible when-format="html"}
![](../images/TypeTree2.png){width=80%}
:::
::: {.content-visible when-format="pdf"}
![Die Hierarchie der numerischen Typen](../images/TypeTree2.png){width=60%}
![The hierarchy of numeric types](../images/TypeTree2.png){width=60%}
:::
Natürlich hat Julia nicht nur numerische Typen. Die Anzahl der direkten Abkömmlinge (Kinder) von `Any` ist
Of course, Julia has not only numeric types. The number of direct descendants (children) of `Any` is
```{julia}
length(subtypes(Any))
```
und mit (fast) jedem Paket, das man mit `using ...` lädt, werden es mehr.
and with (almost) every package loaded with `using ...`, this increases.
## Abstract and Concrete Types
## Abstrakte und Konkrete Typen
- Ein Objekt hat immer einen **konkreten** Typ.
- Konkrete Typen haben keine Untertypen mehr, sie sind immer „Blätter“ des Baumes.
- Konkrete Typen spezifizieren eine konkrete Datenstruktur.
- An object always has a **concrete** type.
- Concrete types have no more subtypes, they are always the "leaves" of the tree.
- Concrete types specify a concrete data structure.
:::{.xxx}
:::
- Abstrakte Typen können nicht instanziiert werden, d.h., es gibt keine Objekte mit diesem Typ.
- Sie definieren eine Menge von konkreten Typen und gemeinsame Methoden für diese Typen.
- Sie können daher in der Definition von Funktionstypen, Argumenttypen, Elementtypen von zusammengesetzten Typen u.ä. verwendet werden.
- Abstract types cannot be instantiated, i.e., there are no objects of this type.
- They define a set of concrete types and common methods for these types.
- They can therefore be used in the definition of function types, argument types, element types of composite types, etc.
Zum **Deklarieren** *und* **Testen** der "Abstammung" innerhalb der Typhierarchie gibt es einen eigenen Operator:
For **declaring** *and* **testing** the "descent" within the type hierarchy, there is a special operator:
```{julia}
Int64 <: Number
```
Zum Testen, ob ein Objekt einen bestimmten Typ (oder einen abstrakten Supertyp davon) hat, dient `isa(object, typ)`. Es wird meist in der Infix-Form verwendet und sollte als Frage `x is a T?` gelesen werden.
To test whether an object has a certain type (or an abstract supertype of it), `isa(object, typ)` is used. It is usually used in infix form and should be read as the question `x is a T?`.
```{julia}
x = 17.2
@@ -120,7 +117,7 @@ x = 17.2
```
Da abstrakte Typen keine Datenstrukturen definieren, ist ihre Definition recht schlicht. Entweder sie stammen direkt von `Any` ab:
Since abstract types do not define data structures, their definition is quite simple. Either they are derived directly from `Any`:
```{julia}
abstract type MySuperType end
@@ -128,7 +125,7 @@ abstract type MySuperType end
supertype(MySuperType)
```
oder von einem anderen abstrakten Typ:
or from another abstract type:
```{julia}
abstract type MySpecialNumber <: Integer end
@@ -136,24 +133,24 @@ abstract type MySpecialNumber <: Integer end
supertypes(MySpecialNumber)
```
Mit der Definition werden die abstrakten Typen an einer Stelle des Typ-Baums "eingehängt".
With the definition, the abstract types are "hung" at a point in the type tree.
## Die numerischen Typen `Bool` und `Irrational`
## The Numeric Types `Bool` and `Irrational`
Da sie im Baum der numerischen Typen zu sehen sind, seien sie kurz erklärt:
Since they are seen in the numeric type tree, they should be briefly explained:
`Bool` ist numerisch im Sinne von `true=1, false=0`:
`Bool` is numeric in the sense of `true=1, false=0`:
```{julia}
true + true + true, false - true, sqrt(true), true/4
```
`Irrational` ist der Typ einiger vordefinierter Konstanten wie `π` und ``.
Laut [Dokumentation](https://docs.julialang.org/en/v1/base/numbers/#Base.AbstractIrrational) ist `Irrational` ein *"Number type representing an exact irrational value, which is automatically rounded to the correct precision in arithmetic operations with other numeric quantities".*
`Irrational` is the type of some predefined constants such as `π` and ``.
According to the [documentation](https://docs.julialang.org/en/v1/base/numbers/#Base.AbstractIrrational), `Irrational` is a *"Number type representing an exact irrational value, which is automatically rounded to the correct precision in arithmetic operations with other numeric quantities".*
## Union-Typen
## Union Types
Falls die Baum-Hierarchie nicht ausreicht, kann man auch abstrakte Typen als Vereinigung beliebiger (abstrakter und konkreter) Typen definieren.
If the tree hierarchy is not sufficient, one can also define abstract types as a union of arbitrary (abstract and concrete) types.
```{julia}
IntOrString = Union{Int64,String}
@@ -161,17 +158,17 @@ IntOrString = Union{Int64,String}
:::{.callout-note .titlenormal}
## Beispiel
Das Kommando `methods(<)` zeigt, dass unter den über 70 Methoden, die für den Vergleichsoperator definiert sind, einige auch *union types* verwenden, z.B. ist
## Example
The command `methods(<)` shows that among the over 70 methods defined for the comparison operator, some also use *union types*, e.g., there is
```julia
<(x::Union{Float16, Float32, Float64}, y::BigFloat)
```
eine Methode für den Vergleich einer Maschinenzahl fester Länge mit einer Maschinenzahl beliebiger Länge.
a method for comparing a machine number of fixed length with a machine number of arbitrary length.
:::
## Zusammengesetzte (_composite_) Typen: `struct`
## Composite (_composite_) Types: `struct`
Eine `struct` ist eine Zusammenstellung von mehreren benannten Feldern und definiert einen konkreten Typ.
A `struct` is a collection of several named fields and defines a concrete type.
```{julia}
abstract type Point end
@@ -188,7 +185,7 @@ mutable struct Point3D <: Point
end
```
Wie wir schon bei Ausdrücken der Form `x = Int8(33)` gesehen haben, kann man Typnamen direkt als Konstruktoren einsetzen:
As we have already seen with expressions of the form `x = Int8(33)`, type names can be used directly as constructors:
```{julia}
p1 = Point2D(1.4, 3.5)
@@ -200,20 +197,20 @@ p1 isa Point3D, p1 isa Point2D, p1 isa Point
```
Die Felder einer `struct` können über ihren Namen mit dem `.`-Operator adressiert werden.
The fields of a `struct` can be addressed by their name with the `.` operator.
```{julia}
p1.y
```
Da wir unsere `struct` als `mutable` deklariert haben, können wir das Objekt `p1` modifizieren, indem wir den Feldern neue Werte zuweisen.
Since we declared our `struct` as `mutable`, we can modify the object `p1` by assigning new values to the fields.
```{julia}
p1.x = 3333.4
p1
```
Informationen über den Aufbau eines Typs oder eines Objekts von diesem Typ liefert `dump()`.
Information about the structure of a type or an object of that type is provided by `dump()`.
```{julia}
dump(Point3D)
@@ -224,28 +221,28 @@ dump(Point3D)
dump(p1)
```
## Funktionen und *Multiple dispatch*
## Functions and *Multiple Dispatch*
:::{.callout-note .titlenormal}
## Objekte, Funktionen, Methoden
## Objects, Functions, Methods
In klassischen objektorientierten Sprachen wie C++/Java haben Objekte üblicherweise mit ihnen assoziierte Funktionen, die Methoden des Objekts.
In classical object-oriented languages like C++/Java, objects usually have functions associated with them, which are the methods of the object.
In Julia gehören Methoden zu einer Funktion und nicht zu einem Objekt.
(Eine Ausnahme sind die Konstruktoren, also Funktionen, die genauso heißen wie ein Typ und ein Objekt dieses Typs erzeugen.)
In Julia, methods belong to a function and not to an object.
(An exception is the constructors, i.e., functions that have the same name as a type and create an object of that type.)
Sobald man einen neuen Typ definiert hat, kann man sowohl neue als auch bestehende Funktionen um neue Methoden für diesen Typ ergänzen.
Once one has defined a new type, one can add new or existing functions around new methods for this type.
- Eine Funktion kann mehrfach für verschiedene Argumentlisten (Typ und Anzahl) definiert werden.
- Die Funktion hat dann mehrere Methoden.
- Beim Aufruf wird an Hand der konkreten Argumente entschieden, welche Methode genutzt wird *(multiple dispatch)*.
- Es ist typisch für Julia, dass für Standardfunktionen viele Methoden definiert sind. Diese können problemlos um weitere Methoden für eigene Typen erweitert werden.
- A function can be defined multiple times for different argument lists (type and number).
- The function then has multiple methods.
- When calling, it is decided based on the concrete arguments which method is used *(multiple dispatch)*.
- It is typical for Julia that for standard functions, many methods are defined. These can be easily extended by further methods for own types.
:::
Den Abstand zwischen zwei Punkten implementieren wir als Funktion mit zwei Methoden:
We implement the distance between two points as a function with two methods:
```{julia}
function distance(p1::Point2D, p2::Point2D)
@@ -256,35 +253,34 @@ function distance(p1::Point3D, p2::Point3D)
sqrt((p1.x-p2.x)^2 + (p1.y-p2.y)^2 + (p1.z-p2.z)^2)
end
```
```{julia}
distance(p1, Point2D(2200, -300))
```
Wie schon erwähnt, zeigt `methods()` die Methodentabelle einer Funktion an:
As mentioned earlier, `methods()` shows the method table of a function:
```{julia}
methods(distance)
```
Das Macro `@which`, angewendet auf einen vollen Funktionsaufruf mmit konkreter Argumentliste, zeigt an, welche Methode zu diesen konkreten Argumenten ausgewählt wird:
The macro `@which`, applied to a full function call with concrete argument list, shows which method is selected for these concrete arguments:
```{julia}
@which sqrt(3.3)
```
```{julia}
z = "Hallo" * '!'
z = "Hello" * '!'
println(z)
@which "Hallo" * '!'
@which "Hello" * '!'
```
Methoden können auch abstrakte Typen als Argument haben:
Methods can also have abstract types as arguments:
```{julia}
"""
Berechnet den Winkel ϕ (in Grad) der Polarkoordinaten (2D) bzw.
Kugelkoordinaten (3D) eines Punktes
Calculates the angle ϕ (in degrees) of the polar coordinates (2D) or
spherical coordinates (3D) of a point
"""
function phi_winkel(p::Point)
atand(p.y, p.x)
@@ -294,8 +290,8 @@ phi_winkel(p1)
```
:::{.callout-tip collapse="true"}
Ein in *triple quotes* eingeschlossene Text unmittelbat vor der Funktionsdefinition
wird automatisch in die Hilfe-Datenbank von Julia integriert:
A text enclosed in *triple quotes* immediately before the function definition
is automatically integrated into Julia's help database:
```{julia}
?phi_winkel
@@ -304,8 +300,8 @@ wird automatisch in die Hilfe-Datenbank von Julia integriert:
Beim *multiple dispatch* wird die Methode angewendet, die unter allen passenden die spezifischste ist. Hier eine Funktion mit mehreren Methoden
(alle bis auf die letzte in der kurzen [*assignment form*](https://docs.julialang.org/en/v1/manual/functions/#man-functions) geschrieben):
With *multiple dispatch*, the method is applied that is the most specific among all matching ones. Here is a function with several methods
(all but the last in the short [*assignment form*](https://docs.julialang.org/en/v1/manual/functions/#man-functions) written):
```{julia}
f(x::String, y::Number) = "Args: String + Zahl"
@@ -318,35 +314,35 @@ function f(x::Number, y::Number, z::String)
return "Arg: 2 x Zahl + String"
end
```
Hier passen die ersten beiden Methoden. Gewählt wird die zweite, da sie spezifischer ist, `Int64 <: Number`.
Here, the first two methods match. The second is chosen since it is more specific, `Int64 <: Number`.
```{julia}
f("Hallo", 42)
f("Hello", 42)
```
Es kann sein, dass diese Vorschrift zu keinem eindeutigen Ergebnis führt, wenn man seine Methoden schlecht gewählt hat.
It may happen that this rule does not lead to a unique result if one chooses one's methods badly.
```{julia}
f(42, 42)
```
## Parametrisierte numerische Typen: `Rational` und `Complex`
## Parametric Numeric Types: `Rational` and `Complex`
- Für rationale Zahlen (Brüche) verwendet Julia `//` als Infix-Konstruktor:
- For rational numbers (fractions), Julia uses `//` as an infix constructor:
```{julia}
@show Rational(23, 17) 4//16 + 1//3;
```
- Die imaginäre Einheit $\sqrt{-1}$ heißt `im`
- The imaginary unit $\sqrt{-1}$ is called `im`
```{julia}
@show Complex(0.4) 23 + 0.5im/(1-2im);
```
`Rational` und `Complex` bestehen, ähnlich wie unser `Point2D`, aus 2 Feldern: Zähler und Nenner bzw. Real- und Imaginärteil.
`Rational` and `Complex` consist, similar to our `Point2D`, of 2 fields: numerator and denominator or real and imaginary part.
Der Typ dieser Felder ist allerdings nicht vollständig festgelegt. `Rational` und `Complex` sind _parametrisierte_ Typen.
However, the type of these fields is not completely fixed. `Rational` and `Complex` are _parametric_ types.
```{julia}
x = 2//7
@@ -367,14 +363,14 @@ y = 1.0 + 2.0im
typeof(y)
```
Die konkreten Typen `Rational{Int64}`, `Rational{BigInt}`,..., `Complex{Int64}`, `Complex{Float64}}`, ... sind Subtypen von `Rational` bzw. `Complex`.
The concrete types `Rational{Int64}`, `Rational{BigInt}`,..., `Complex{Int64}`, `Complex{Float64}}`, ... are subtypes of `Rational` resp. `Complex`.
```{julia}
Rational{BigInt} <: Rational
```
Die Definitionen [sehen etwa so aus](https://github.com/JuliaLang/julia/blob/master/base/rational.jl#L6-L15):
The definitions [look roughly like this](https://github.com/JuliaLang/julia/blob/master/base/rational.jl#L6-L15):
```{julia}
struct MyComplex{T<:Real} <: Number
@@ -388,19 +384,19 @@ struct MyRational{T<:Integer} <: Real
end
```
Die erste Definition besagt:
The first definition says:
- `MyComplex` hat zwei Felder `re` und `im`, beide vom gleichen Typ `T`.
- Dieser Typ `T` muss ein Untertyp von `Real` sein.
- `MyComplex` und alle seine Varianten wie `MyComplex{Float64}` sind Untertypen von `Number`.
- `MyComplex` has two fields `re` and `im`, both of the same type `T`.
- This type `T` must be a subtype of `Real`.
- `MyComplex` and all its variants like `MyComplex{Float64}` are subtypes of `Number`.
und die zweite besagt analog:
and the second says analogously:
- `MyRational` hat zwei Felder `num` und `den`, beide vom gleichen Typ `T`.
- Dieser Typ `T` muss ein Untertyp von `Integer` sein.
- `MyRational` und seine Varianten sind Untertypen von `Real`.
- `MyRational` has two fields `num` and `den`, both of the same type `T`.
- This type `T` must be a subtype of `Integer`.
- `MyRational` and its variants are subtypes of `Real`.
Nun ist $\subset$ , oder auf julianisch `Rational <: Real`. Also können die Komponenten einer komplexen Zahl auch rational sein:
Now $\subset$ , or in Julia notation `Rational <: Real`. Thus, the components of a complex number can also be rational:
```{julia}
z = 3//4 + 5im
@@ -409,23 +405,24 @@ dump(z)
Diese Strukturen sind ohne das `mutable`-Attribut definiert, also *immutable*:
These structures are defined without the `mutable` attribute, therefore *immutable*:
```{julia}
x = 2.2 + 3.3im
println("Der Realteil ist: $(x.re)")
println("The real part is: $(x.re)")
x.re = 4.4
```
Das ist so üblich. Wir betrachten das Objekt `9` vom Typ `Int64` ja auch als unveränderlich.
Das Folgende geht natürlich trotzdem:
This is common. We also consider the object `9` of type `Int64` as immutable.
The following, of course, still works:
```{julia}
x += 2.2
```
Hier wird ein neues Objekt vom Typ `Complex{Float64}` erzeugt und `x` zur Referenz auf dieses neue Objekt gemacht.
Here, a new object of type `Complex{Float64}` is created and `x` is made a reference to this new object.
Die Möglichkeiten des Typsystems verleiten leicht zum Spielen. Hier definieren wir eine `struct`, die wahlweise eine Maschinenzahl oder ein Paar von Ganzzahlen enthalten kann:
The possibilities of the type system easily invite to play. Here we define a `struct` that can contain either a machine number or a pair of integers:
```{julia}
struct MyParms{T <: Union{Float64, Tuple{Int64, Int64}}}
@@ -441,13 +438,13 @@ p2 = MyParms( (2, 4) )
## Typen als Objekte
## Types as Objects
(1) Typen sind ebenfalls Objekte. Sie sind Objekte einer der drei "Meta-Typen"
(1) Types are also objects. They are objects of one of the three "meta-types"
- `Union` (Union-Typen)
- `UnionAll` (parametrisierte Typen)
- `DataType` (alle konkreten und sonstige abstrakte Typen)
- `Union` (union types)
- `UnionAll` (parametric types)
- `DataType` (all concrete and other abstract types)
```{julia}
@show 23779 isa Int64 Int64 isa DataType;
@@ -463,7 +460,7 @@ p2 = MyParms( (2, 4) )
```
Diese 3 konkreten "Meta-Typen" sind übrigens Subtypen des abstrakten "Meta-Typen" `Type`.
These 3 concrete "meta-types" are, by the way, subtypes of the abstract "meta-type" `Type`.
```{julia}
subtypes(Type)
@@ -471,7 +468,7 @@ subtypes(Type)
-----------------
(2) Damit können Typen auch einfach Variablen zugewiesen werden:
(2) Thus, types can also be easily assigned to variables:
```{julia}
x3 = Float64
@@ -480,15 +477,15 @@ x3 = Float64
:::{.callout-note collapse="true"}
Dies zeigt auch, dass die [Style-Vorgaben in Julia](https://docs.julialang.org/en/v1/manual/style-guide/#Use-naming-conventions-consistent-with-Julia-base/) wie „Typen und Typvariablen starten mit Großbuchstaben, sonstige Variablen und Funktionen werden klein geschrieben.“ nur Konventionen sind und von der Sprache nicht erzwungen werden.
This also shows that the [style guidelines in Julia](https://docs.julialang.org/en/v1/manual/style-guide/#Use-naming-conventions-consistent-with-Julia-base/) such as "Types and type variables start with uppercase letters, other variables and functions are written in lowercase." are only conventions and are not enforced by the language.
Man sollte sie trotzdem einhalten, um den Code lesbar zu halten.
One should still follow them to keep the code readable.
:::
Wenn man solche Zuweisungen mit `const` für dauerhaft erklärt, entsteht ein
*type alias*.
If such assignments are declared permanent with `const`, a
*type alias* is created.
```{julia}
@@ -500,7 +497,7 @@ typeof(z)
--------
(3) Typen können Argumente von Funktionen sein.
(3) Types can be arguments of functions.
```{julia}
@@ -516,74 +513,76 @@ z = myf(43, UInt16, Real)
@show z typeof(z);
```
Wenn man diese Funktion mit Typsignaturen definieren möchte, kann man natürlich
If one wants to define this function with type signatures, of course one can write
```julia
function myf(x, S::Type, T::Type) ... end
```
schreiben. Üblicher ist hier die (dazu äquivalente) spezielle Syntax
However, the (equivalent) special syntax
```julia
function myf(x, ::Type{S}, ::Type{T}) where {S,T} ... end
```
bei der man in der `where`-Klausel auch noch Einschränkungen an die zulässigen Werte der Typvariablen `S` und `T` stellen kann.
is more common here, where one can also impose restrictions on the permissible values of the type variables `S` and `T` in the `where` clause.
Wie definiere ich eine spezielle Methode von `myf`, die nur aufgerufen werden soll, wenn `S` und `T` gleich `Int64` sind? Das ist folgendermaßen möglich:
How do I define a special method of `myf` that should only be called when `S` and `T` are equal to `Int64`? This is possible as follows:
```julia
function myf(x, ::Type{Int64}, ::Type{Int64}) ... end
```
`Type{Int64}` wirkt wie ein "Meta-Typ", dessen einzige Instanz der Typ `Int64` ist.
`Type{Int64}` acts like a "meta-type", whose only instance is the type `Int64`.
-----------------
(4) Es gibt zahlreiche Operationen mit Typen als Argumenten. Wir haben schon `<:(T1, T2)`, `supertype(T)`, `supertypes(T)`, `subtypes(T)` gesehen. Erwähnt seien noch `typejoin(T1,T2)` (nächster gemeinsamer Vorfahre im Typbaum) und Tests wie `isconcretetype(T)`, `isabstracttype(T)`, `isstructtype(T)`.
(4) There are numerous operations with types as arguments. We have already seen `<:(T1, T2)`, `supertype(T)`, `supertypes(T)`, `subtypes(T)`. Mentioned should be still `typejoin(T1,T2)` (next common ancestor in the type tree) and tests like `isconcretetype(T)`, `isabstracttype(T)`, `isstructtype(T)`.
## Invarianz parametrisierter Typen {#sec-invariance}
## Invariance of Parametric Types {#sec-invariance}
Kann man in parametrisierten Typen auch nicht-konkrete Typen einsetzen? Gibt es `Complex{AbstractFloat}` oder `Complex{Union{Float32, Int16}}`?
Can non-concrete types also be substituted into parametric types? Are there `Complex{AbstractFloat}` or `Complex{Union{Float32, Int16}}`?
Ja, die gibt es; und es sind konkrete Typen, man kann also Objekte von diesem Typ erzeugen.
Yes, they exist; and they are concrete types, one can therefore create objects of this type.
```{julia}
z5 = Complex{Integer}(2, 0x33)
dump(z5)
```
Das ist eine heterogene Struktur. Jede Komponente hat einen individuellen Typ `T`, für den `T<:Integer` gilt.
This is a heterogeneous structure. Each component has an individual type `T`, for which `T<:Integer` holds.
Nun gilt zwar
Now it holds that
```{julia}
Int64 <: Integer
```
aber es gilt nicht, dass
but it does not hold that
```{julia}
Complex{Int64} <: Complex{Integer}
```
Diese Typen sind beide konkret. Damit können sie in der Typhierarchie von Julia nicht in einer Sub/Supertype-Relation zueinander stehen. Julias parametrisierte Typen sind [in der Sprache der theoretischen Informatik](https://de.wikipedia.org/wiki/Kovarianz_und_Kontravarianz) **invariant**.
(Wenn aus `S<:T` folgen würde, dass auch `ParamType{S} <: ParamType{T}` gilt, würde man von **Kovarianz** sprechen.)
These types are both concrete. Therefore, they cannot stand in a sub/supertype relation to each other in Julia's type hierarchy. Julia's parametric types are [in the language of theoretical computer science](https://en.wikipedia.org/wiki/Covariance_and_contravariance) **invariant**.
(If from `S<:T` it would follow that also `ParamType{S} <: ParamType{T}`, one would speak of **covariance**.)
## Generische Funktionen
Der übliche (und in vielen Fällen empfohlene!) Programmierstil in Julia ist das Schreiben generischer Funktionen:
## Generic Functions
The usual (and in many cases recommended!) programming style in Julia is writing generic functions:
```{julia}
function fsinnfrei1(x, y)
return x * x * y
end
```
Diese Funktion funktioniert sofort mit allen Typen, für die die verwendeten Operationen definiert sind.
This function works immediately with all types for which the used operations are defined.
```{julia}
fsinnfrei1( Complex(2,3), 10), fsinnfrei1("Hallo", '!')
fsinnfrei1( Complex(2,3), 10), fsinnfrei1("Hello", '!')
```
Man kann natürlich Typ-Annotationen benutzen, um die Verwendbarkeit einzuschränken oder um unterschiedliche Methoden für unterschiedliche Typen zu implementieren:
One can of course use type annotations to restrict usability or to implement different methods for different types:
```{julia}
function fsinnfrei2(x::Number, y::AbstractFloat)
@@ -600,15 +599,15 @@ end
:::{.callout-important}
**Explizite Typannotationen sind fast immer irrelevent für die Geschwindigkeit des Codes!**
**Explicit type annotations are almost always irrelevant for the speed of the code!**
Dies ist einer der wichtigsten *selling points* von Julia.
This is one of the most important *selling points* of Julia.
Sobald eine Funktion zum ersten Mal mit bestimmten Typen aufgerufen wird, wird eine auf diese Argumenttypen spezialisierte Form der Funktion generiert und compiliert. Damit sind generische Funktionen in der Regel genauso schnell, wie die spezialisierten Funktionen, die man in anderen Sprachen schreibt.
Once a function is called for the first time with certain types, a specialized form of the function is generated and compiled for these argument types. Thus, generic functions are usually just as fast as the specialized functions one writes in other languages.
Generische Funktionen erlauben die Zusammenarbeit unterschiedlichster Pakete und eine hohe Abstraktion.
Generic functions enable the cooperation of the most diverse packages and a high level of abstraction.
Ein einfaches Beispiel: Das Paket `Measurements.jl` definiert einen neuen Datentyp `Measurement`, einen Wert mit Fehler, und die Arithmetik dieses Typs. Damit funktionieren generische Funktionen automatisch:
A simple example: The `Measurements.jl` package defines a new data type `Measurement`, a value with error, and the arithmetic of this type. Thus, generic functions work automatically:
```{julia}
#| echo: false
@@ -652,18 +651,18 @@ fsinnfrei1(x, y)
```
:::
## Typ-Parameter in Funktionsdefinitionen: die `where`-Klausel
## Type Parameters in Function Definitions: the `where` Clause
Wir wollen eine Funktion schreiben, die für **alle komplexen Integer** (und nur diese) funktioniert, z.B. eine [in [i] mögliche Primfaktorzerlegung](https://de.wikipedia.org/wiki/Gau%C3%9Fsche_Zahl). Die Definition
We want to write a function that works for **all complex integers** (and only these), e.g., a [possible prime factorization in [i](https://en.wikipedia.org/wiki/Gaussian_integer). The definition
```{julia}
#| eval: false
function isprime(x::Complex{Integer}) ... end
```
liefert nun nicht das Gewünschte, wie wir in @sec-invariance gesehen haben. Die Funktion würde für ein Argument vom Typ `Complex{Int64}` nicht funktionieren, da letzteres kein Subtyp von `Complex{Integer}` ist.
does not give the desired result, as we saw in @sec-invariance. The function would not work for an argument of type `Complex{Int64}`, since the latter is not a subtype of `Complex{Integer}`.
Wir müssen eine Typ-Variable einführen. Dazu dient die `where`-Klausel.
We must introduce a type variable. The `where` clause serves this purpose.
```{julia}
#| eval: false
@@ -672,11 +671,11 @@ function isprime(x::Complex{T}) where {T<:Integer}
end
```
Das ist zu lesen als:
This is to be read as:
> „Das Argument x soll von einem der Typen `Complex{T}` sein, wobei die Typvariable `T` irgendein Untertyp von `Integer` sein kann.“
> "The argument x should be one of the types `Complex{T}`, where the type variable `T` can be any subtype of `Integer`."
Noch ein Beispiel:
Another example:
```{julia}
#| eval: false
function kgV(x::Complex{T}, y::Complex{S}) where {T<:Integer, S<:Integer}
@@ -684,10 +683,11 @@ function kgV(x::Complex{T}, y::Complex{S}) where {T<:Integer, S<:Integer}
end
```
> Die Argumente x und y können verschiedene Typen haben und beide müssen Subtypen von `Integer` sein.
> The arguments x and y can have different types and both must be subtypes of `Integer`.
Wenn es nur eine `where`-Klausel wie im vorletzten Beispiel gibt, kann man die geschweiften Klammern weglassen und
If there is only one `where` clause as in the last example, one can omit the curly braces and
write
```{julia}
#| eval: false
@@ -695,7 +695,7 @@ function isprime(x::Complex{T}) where T<:Integer
...
end
```
schreiben. Das lässt sich noch weiter kürzen zu
This can still be shortened to
```{julia}
#| eval: false
function isprime(x::Complex{<:Integer})
@@ -703,7 +703,7 @@ function isprime(x::Complex{<:Integer})
end
```
Diese verschiedenen Varianten können verwirrend sein, aber das ist nur Syntax.
These different variants can be confusing, but it is only syntax.
```{julia}
C1 = Complex{T} where {T<:Integer}
@@ -713,24 +713,24 @@ C3 = Complex{<:Integer}
C1 == C2 == C3
```
Kurze Syntax für einfache Fälle, ausführliche Syntax für komplexe Varianten.
Short syntax for simple cases, extended syntax for complex variants.
Als letztes sein bemerkt, dass `where T` die Kurzform von `where T<:Any` ist, also eine völlig unbeschränkte Typvariable einführt. Damit ist sowas möglich:
Last, it should be noted that `where T` is the short form of `where T<:Any`, which introduces a completely unrestricted type variable. Thus, something like this is possible:
```{julia}
function fgl(x::T, y::T) where T
println("Glückwunsch! x und y sind vom gleichen Typ!")
println("Congratulations! x and y are of the same type!")
end
```
Diese Methode erfordert, dass die Argumente genau den gleichen, aber ansonsten beliebigen Typ haben.
This method requires that the arguments are exactly the same type, but otherwise arbitrary.
```{julia}
fgl(33, 44)
```
```{julia}
fgl(33, 44.0)
```

View File

@@ -1,12 +1,13 @@
---
engine: julia
---
# Was ist Julia? {.unnumbered}
# What is Julia? {.unnumbered}
Julia ist eine noch recht junge für *scientific computing* konzipierte moderne Programmiersprache.
Julia is a relatively young, modern programming language designed for *scientific computing*.
Ein kleines Codebeispiel:
A small code example:
```{julia}
#| error: false
@@ -33,25 +34,24 @@ end
f
```
## Geschichte {.unnumbered}
## History {.unnumbered}
- 2009 Beginn der Entwicklung am *Computer Science and Artificial
Intelligence Laboratory* des MIT
- 2012 erste Release v0.1
- 2009 Start of development at the *Computer Science and Artificial
Intelligence Laboratory* of MIT
- 2012 first release v0.1
- 2018 Version v1.0
- aktuell: v1.11.4 vom 10. März 2025
- current: v1.11.4 from March 10, 2025
Zum ersten Release 2012 haben die Schöpfer von Julia ihre Ziele und Motivation in dem Blogbeitrag [Why we created Julia](https://julialang.org/blog/2012/02/why-we-created-julia/)
interessant zusammengefasst.
For the first release in 2012, the creators of Julia summarized their goals and motivation in a blog post [Why we created Julia](https://julialang.org/blog/2012/02/why-we-created-julia) interestingly.
Für ein Bild von *Stefan Karpinski, Viral Shah, Jeff
Bezanson* und *Alan Edelman* bitte hier klicken: <https://news.mit.edu/2018/julia-language-co-creators-win-james-wilkinson-prize-numerical-software-1226>.
For a picture of *Stefan Karpinski, Viral Shah, Jeff
Bezanson*, and *Alan Edelman*, please click here: <https://news.mit.edu/2018/julia-language-co-creators-win-james-wilkinson-prize-numerical-software-1226>.
:::{.content-hidden unless-format="xxx"}
Kurzfassung:
Short summary:
> We want a language that is
>
@@ -67,26 +67,26 @@ Bezanson* und *Alan Edelman* bitte hier klicken: <https://news.mit.edu/2018/juli
Formale Syntax
Formal syntax
:
- Algorithmisches Denken
- Gefühl für die Effizienz und Komplezität von Algorithmen
- Besonderheiten der Computerarithmetik, insbes. Gleitkommazahlen
- „Ökosystem“ der Sprache:
- die Kunst des Debugging.
- Algorithmic thinking
- Intuition for the efficiency and complexity of algorithms
- Special features of computer arithmetic, particularly floating-point numbers
- The "ecosystem" of the language
- The art of debugging.
:::
## Warum Julia? {.unnumbered}
## Why Julia? {.unnumbered}
:::{.callout-tip .titlenormal icon=false}
## aus [The fast track to Julia](https://cheatsheet.juliadocs.org/)
## from [The fast track to Julia](https://cheatsheet.juliadocs.org/)
"Julia is an open-source, multi-platform, high-level, high-performance programming language for technical computing.
Julia has an LLVM-based JIT compiler that allows it to match the performance of languages such as C and FORTRAN without the hassle of low-level code. Because the code is compiled on the fly you can run (bits of) code in a shell or REPL , which is part of the recommended workflow .
Julia has an LLVM-based JIT compiler that allows it to match the performance of languages such as C and FORTRAN without the hassle of low-level code. Because the code is compiled on the fly you can run (bits of) code in a shell or REPL, which is part of the recommended workflow.
Julia is dynamically typed, provides multiple dispatch, and is designed for parallelism and distributed computation.
@@ -96,39 +96,38 @@ Julia has a built-in package manager."
*open source*
: - offene Entwicklung auf [GitHub](https://github.com/JuliaLang/julia)
- Implementierungen für alle gängigen Betriebssysteme
: - open development on [GitHub](https://github.com/JuliaLang/julia)
- implementations for all common operating systems
*high-performance programming language for technical computing*
: - viele Funktionen für *scientific computing* eingebaut,
- (bewusste) Ähnlichkeit zu Python, R und Matlab,
- komplexe Berechnungen in wenigen Zeilen
- einfaches Interface zu anderen Sprachen wie C oder Python
: - many functions for *scientific computing* built-in,
- (intentional) similarity to Python, R and Matlab,
- complex calculations in a few lines
- simple interface to other languages like C or Python
*a JIT compiler*
: - interaktives Arbeiten möglich: `read-eval-print loop (REPL)` mit
- just-in-time (JIT) Compilation
- dadurch Laufzeiten vergleichbar mit statischen Sprachen wie C/C++, Fortran oder Rust
: - interactive work possible: `read-eval-print loop (REPL)` with
- just-in-time (JIT) compilation
- thereby runtimes comparable to static languages like C/C++, Fortran or Rust
*a built-in package manager*
: - riesiges *ecosystem* an einfach installierbaren Paketen, z.B.
- [Mathematische Optimierung](https://jump.dev/)
: - huge *ecosystem* of easily installable packages, e.g.
- [Mathematical Optimization](https://jump.dev/)
- [Machine Learning](https://fluxml.ai/)
- [Data Visualization](https://docs.makie.org/stable/)
- [Differentialgleichungen](https://docs.sciml.ai/DiffEqDocs/stable/)
- [Mathematische Modellierung](https://sciml.ai/)
- [Differential Equations](https://docs.sciml.ai/DiffEqDocs/stable/)
- [Mathematical Modeling](https://sciml.ai/)
## Eine kleine Auswahl an Online-Material zu Julia {.unnumbered}
## A Small Selection of Online Materials on Julia {.unnumbered}
- [Dokumentation](https://docs.julialang.org/en/v1/) - die offizielle Dokumentation
- [Documentation](https://docs.julialang.org/en/v1/) - the official documentation
- [Cheat Sheet](https://cheatsheet.juliadocs.org/) - "a quick & dirty overview"
- [Introducing Julia](https://en.wikibooks.org/wiki/Introducing_Julia)-- ein WikiBook
- [The Julia Express](http://bogumilkaminski.pl/files/julia_express.pdf) - Kurzfassung, Julia auf 16 Seiten
- [Think Julia](https://benlauwens.github.io/ThinkJulia.jl/latest/book.html) - Einführung in die Programmierung mit Julia als Sprache
- Das [Julia Forum](https://discourse.julialang.org/)
- Was fürs Auge: [Beispiele zum Julia-Grafikpaket `Makie`](https://beautiful.makie.org/)
- [Introducing Julia](https://en.wikibooks.org/wiki/Introducing_Julia)-- a WikiBook
- [The Julia Express](http://bogumilkaminski.pl/files/julia_express.pdf) - short version, Julia in 16 pages
- [Think Julia](https://benlauwens.github.io/ThinkJulia.jl/latest/book.html) - introduction to programming with Julia as a language
- The [Julia Forum](https://discourse.julialang.org/)
- For the eyes: [Examples for the Julia graphics package `Makie`](https://beautiful.makie.org/)

23
opencode.json Normal file
View File

@@ -0,0 +1,23 @@
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"llama.cpp": {
"npm": "@ai-sdk/openai-compatible",
"name": "llama-server (local)",
"options": {
"baseURL": "http://127.0.0.1:8077/v1"
},
"models": {
"Qwen3-coder-next-100": {
"name": "Qwen3-coder-next-100",
"tool_call": true,
"reasoning": true,
"limit": {
"context": 128000,
"output": 65536
}
}
}
}
}
}