25 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
19c67a3c9b Project.toml added 2026-02-22 16:38:46 +01:00
4919dffca9 .gitignore: .cache added 2026-02-22 14:05:19 +01:00
77e51493a4 Notes for SoSe25 added 2025-05-13 11:55:57 +02:00
9421cf9256 typos 2025-04-23 10:52:14 +02:00
23e9dea0eb scss: monofont noichmal definiert. Quarto bug? 2025-04-23 10:48:23 +02:00
56a3423c24 pcomplex: doppelte ueberschrift weg 2025-04-15 16:42:38 +02:00
92ce555767 style.css: old roboto code removed 2025-03-06 15:51:58 +01:00
6b9a05f69c first adaptions for 2025 2025-03-03 18:09:42 +01:00
0e712f0c33 font roboto condensed erweitert 2024-12-13 13:32:40 +01:00
6711eaedf0 tippfehler 2024-06-05 13:14:30 +02:00
84e180f1bc io: doppelt title weg 2024-06-04 18:03:35 +02:00
8e83a18cd0 IO fertig, trick mit module name in first julia cell 2024-06-04 17:57:12 +02:00
fb58c51aa2 plots erweitert 2024-05-31 20:30:57 +02:00
421f382d07 kleine Erweiterung bei plots 2024-05-28 18:09:35 +02:00
2ebd0803ae small errors corrected 2024-05-27 21:56:40 +02:00
b3079a799e Plot chapter expanded 2024-05-27 20:10:30 +02:00
6d032cfbea some reorganisation, js deleted, readme updated 2024-05-14 14:50:59 +02:00
31981a7612 removed nb dir from git tracking 2024-05-14 13:20:00 +02:00
aa4af0c42a update extensions 2024-05-14 00:11:21 +02:00
c024532262 more chapters adapted to julia engine 2024-05-13 00:38:46 +02:00
cc79833992 first work on julia engine branch 2024-05-13 00:37:52 +02:00
167 changed files with 5969 additions and 15943 deletions

4
.gitignore vendored
View File

@@ -28,5 +28,7 @@ index.html.md
Julia*tex
xelatex.py
.luarc.json
/.luarc.json
nb/*.qmd
nb/*.ipynb
.cache/

15
.vscode/settings.json vendored
View File

@@ -1,14 +1,15 @@
{
"julia.environmentPath": "/home/hellmund/Julia/23",
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"**/*.ipynb": false,
"**/*.md": false
"**/.git": true,
"**/.hg": true,
"**/.svn": true,
"**/*.ipynb": true,
"**/*.md": true,
"**/*.quarto_ipynb": true,
"**/CVS": true,
"**/Thumbs.db": true
},
"explorerExclude.backup": {},
"ltex.enabled": false,

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

16
Notes.txt Normal file
View File

@@ -0,0 +1,16 @@
SoSe25:
14_Plot.html: die beiden Zeilen mit require.js, define jquery entfernen
für Plots/plotlyjs
Book25: Versuch ohne quarto-patch:
LaTeX: ansi in stdout not supported, Julia errors werden total
zerschossen
mit stdout-cell-support koennte ein eigener laufilter gehen, wenn der
vor dem quarto-latex-filter gerufen wird

23
Project.toml Normal file
View File

@@ -0,0 +1,23 @@
[deps]
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7"
PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Primes = "27ebfcd6-29c5-5fa9-bf4b-fb8fc14df3ae"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b"
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
TreeView = "39424ebd-4cf3-5550-a685-96706a953f40"

View File

@@ -1,19 +1,9 @@
# Julia für Numerik
Source code for the website and PDF ["Julia für Numerik"](https://www.math.uni-leipzig.de/~hellmund/juliabook/)
Source code for the website and PDF script ["Julia für Numerik"](https://www.math.uni-leipzig.de/~hellmund/juliabook/)
- It uses the [Quarto publishing system](https://quarto.org/).
- It uses the Quarto extension [julia-color](https://gitea.math.uni-leipzig.de/hellmund/julia-color) to support
- It uses the Quarto extension [julia-color](https://github.com/MHellmund/julia-color) to support
the conversion of Jupyter code output cells with ANSI escape sequences to HTML and LaTeX/PDF
Since the `julia-color` extension needs a patched `Quarto` anyway, we use two more patches.
- `patch-quarto-julia` reduces the `startup.jl` used by quarto to a minimum.
- `patch-quarto-stacktrace` adds the julia stacktrace to the output of code cells with julia errors. See e.g. the second code cell [here](https://www.math.uni-leipzig.de/~hellmund/juliabook/chapters/syntax.html#arithmetische-vergleiche)
```shell
cd quarto-cli
patch -p1 < patch-quarto-julia
patch -p1 < patch-quarto-stacktrace
```
All content & code licenced under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/).

View File

@@ -1 +1 @@
QUARTO_JULIA_PROJECT=/home/hellmund/G/QuartoNotebookRunner.jl
QUARTO_JULIA_PROJECTXXX=/home/hellmund/G/QuartoNotebookRunner.jl

View File

@@ -0,0 +1,21 @@
title: Julia-color
author: Meik Hellmund
version: 1.0.0
quarto-required: ">=99.9.0"
contributes:
formats:
common:
filters:
- "ansi2htmltex.lua"
html:
monofont: "JuliaMono"
css:
- "resources/css/ansicolor.css"
- "resources/css/juliamono.css"
pdf:
include-in-header:
- "resources/tex/juliainc.tex"
typst:
include-in-header:
- "resources/typst/juliainc.typ"

View File

@@ -1,10 +1,5 @@
-- this is essentially
-- based on
-- https://github.com/jupyter/nbconvert/blob/main/nbconvert/filters/ansi.py
-- converted to lua
-- good list of ANSI escape sequences:
-- https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
local ANSI_COLORS = {
"ansi-black",
@@ -60,18 +55,8 @@ local function get_extended_color(numbers)
return {r, g, b}
end
--[=[
local re = require "re"
local ANSI = re.compile [[
'\x1b%[' {.*?} {[@-~]}
]]
--]=]
local function LaTeXconverter(fg, bg, bold, underline, inverse)
if not (fg or bg or bold or underline or inverse) then
local function LaTeXconverter(fg, bg, bold, light, italic, underline, inverse)
if not (fg or bg or bold or light or italic or underline or inverse) then
return "",""
end
@@ -116,6 +101,16 @@ local function LaTeXconverter(fg, bg, bold, underline, inverse)
endtag = "}" .. endtag
end
if light then
starttag = starttag .. [[\textlight{]]
endtag = "}" .. endtag
end
if italic then
starttag = starttag .. [[\textit{]]
endtag = "}" .. endtag
end
if underline then
starttag = starttag .. [[\underline{]]
endtag = "}" .. endtag
@@ -123,8 +118,57 @@ local function LaTeXconverter(fg, bg, bold, underline, inverse)
return starttag, endtag
end
local function HTMLconverter(fg, bg, bold, underline, inverse)
if not (fg or bg or bold or underline or inverse) then
local function Typstconverter(fg, bg, bold, light, italic, underline, inverse)
local starttag = "raw(\""
local endtag = "\")"
if inverse then
fg, bg = bg, fg
end
if underline then
starttag = "show: c => underline(c);" .. starttag
end
if type(bg) == "number" then
starttag = "show: c => invertbox(" .. ANSI_COLORS[bg+1] .. ",c);" .. starttag
elseif type(bg) == "table" then
starttag = string.format("show: c => invertbox(rgb(%d,%d,%d),c);", bg[1], bg[2], bg[3]) .. starttag
elseif inverse then
starttag = "show: c => invertbox(ansi-default-inverse-bg ,c);" .. starttag
end
if type(fg) == "number" then
starttag = "set text(fill:" .. ANSI_COLORS[fg+1] ..");" .. starttag
elseif type(fg) == "table" then
starttag = string.format("set text(fill:rgb(%d,%d,%d));", fg[1], fg[2], fg[3]) .. starttag
elseif inverse then
starttag = "set text(fill: ansi-default-inverse-fg);" .. starttag
end
if italic then
starttag = "set text(style:\"italic\");" .. starttag
end
if bold then
starttag = "set text(weight:\"bold\");" .. starttag
end
if light then
starttag = "set text(weight:\"light\");" .. starttag
end
return "#{" .. starttag, endtag.."}"
end
local function HTMLconverter(fg, bg, bold, light, italic, underline, inverse)
if not (fg or bg or bold or light or italic or underline or inverse) then
return "",""
end
local classes = {}
@@ -156,6 +200,14 @@ local function HTMLconverter(fg, bg, bold, underline, inverse)
table.insert(classes, "ansi-bold")
end
if light then
table.insert(classes, "ansi-light")
end
if italic then
table.insert(classes, "ansi-italic")
end
if underline then
table.insert(classes, "ansi-underline")
end
@@ -181,6 +233,9 @@ local function codeBlockTrans(e)
elseif quarto.doc.isFormat('html') then
converter = HTMLconverter
fmt = 'html'
elseif quarto.doc.isFormat('typst') then
converter = Typstconverter
fmt = 'typst'
else
return
end
@@ -196,7 +251,8 @@ local function codeBlockTrans(e)
local texenv="OutputCell"
local codeclass=""
if string.find(e.text, "\u{a35f}\u{2983}") then
-- if string.find(e.text, "\u{a35f}\u{2983}") then
if string.find(e.text, "\x1b%[") then
texenv = "AnsiOutputCell"
codeclass = "ansi"
end
@@ -206,12 +262,18 @@ local function codeBlockTrans(e)
end
local out=""
-- if string.find(e.text, "\x1b%[") then
if string.find(e.text, "\u{a35f}\u{2983}") then
local text = e.text
-- we remove links (eg in julia ParseErrors. THey link to local files, so they are useless anyway)
text = text:gsub("\x1b%]8;.-\x1b\\", "")
if string.find(text, "\x1b%[") then
-- if string.find(text, "\u{a35f}\u{2983}") then
local bold = false
local light = false
local italic = false
local underline = false
local inverse = false
local text = e.text
local chunk = ""
local fg = nil
local bg = nil
@@ -221,8 +283,9 @@ local function codeBlockTrans(e)
while text ~= "" do
numbers = {}
-- local s1, e1, c1, d1 = string.find(text, "\x1b%[(.-)([@-~])")
local s1, e1, c1, d1 = string.find(text, "\u{a35f}\u{2983}(.-)([@-~])")
-- [@-~]: matches single char between 64 and 126
local s1, e1, c1, d1 = string.find(text, "\x1b%[(.-)([@-~])")
-- local s1, e1, c1, d1 = string.find(text, "\u{a35f}\u{2983}(.-)([@-~])")
if s1 then
if d1 == "m" then
for i in string.gmatch(c1, "([^;]*)") do
@@ -238,9 +301,9 @@ local function codeBlockTrans(e)
if chunk ~= "" then
if bold and type(fg)=="number" and fg<8 then
starttag, endtag = converter(fg+8, bg, bold, underline, inverse)
starttag, endtag = converter(fg+8, bg, bold, light, italic, underline, inverse)
else
starttag, endtag = converter(fg, bg, bold, underline, inverse)
starttag, endtag = converter(fg, bg, bold, light, italic, underline, inverse)
end
out = out .. starttag .. chunk .. endtag
end
@@ -253,20 +316,26 @@ local function codeBlockTrans(e)
bold = false
inverse = false
underline = false
elseif n == 1 then
elseif n == 1 or n == 5 or n == 6 then -- bold and blink
bold = true
elseif n == 2 or n == 8 then -- 'dim' and 'hide'
light = true
elseif n == 3 then
italic = true
elseif n == 4 then
underline = true
elseif n == 5 then
bold = true -- 'blinking'
elseif n == 7 then
inverse = true
elseif n == 21 or n == 22 then
elseif n == 21 or n == 22 or n == 25 then
bold = false
elseif n == 23 then
italic = false
elseif n == 24 then
underline = false
elseif n == 27 then
inverse = false
elseif n == 22 or n == 28 then
light = false
elseif n >= 30 and n <= 37 then
fg = n - 30
elseif n == 38 then
@@ -290,7 +359,7 @@ local function codeBlockTrans(e)
end
end
else
out = e.text
out = text
end
if fmt == 'html' then
return pandoc.RawBlock(fmt,
@@ -299,6 +368,10 @@ local function codeBlockTrans(e)
if fmt == 'latex' then
return pandoc.RawBlock(fmt, [[\begin{]]..texenv.."}\n"..out.."\n"..[[\end{]].. texenv .. "}")
end
if fmt == 'typst' then
return pandoc.RawBlock(fmt, "#"..texenv.."[\n"..out.."\n]")
end
end
@@ -324,67 +397,13 @@ local function divCodeBlockNoHeader1(e)
for i, el in pairs(c) do
if el.t == 'Header' then
el.level = 6
-- elneu = pandoc.Para(el.content)
-- c[i] = elneu
end
if el.t == 'CodeBlock' then
if el.classes:includes("jldoctest") then
x,i = el.classes:find("jldoctest")
el.classes:remove(i)
end
end
end
return e
end
-- test if two divs should be merged
local function testmerge(d1, d2)
return d1 and d1.t == "Div" and d1.classes:includes("cell-output") and #d1.content == 1
and d2 and d2.t == "Div" and d2.classes:includes("cell-output") and #d2.content == 1
and d1.content[1].t == "CodeBlock" and not d1.classes:includes("cell-output-stderr")
and d2.content[1].t == "CodeBlock" and not d2.classes:includes("cell-output-stderr")
end
-- merge (div (codecell (text1)), div (codecell(text2))) to div(codecell(text1+text2))
local function blockMerge(es)
local nl = ""
for i = #es-1, 1, -1 do
if testmerge(es[i], es[i+1]) then
str1 = es[i].content[1].text
str2 = es[i+1].content[1].text
nl = "\n"
if es[i].classes:includes("cell-output-stdout") and es[i+1].classes:includes("cell-output-stdout") then
if str1:sub(-1) == "\n" then
nl = ""
end
if str2:sub(1, 1) == "\n" then
nl = ""
end
end
es[i].content[1].text = str1 .. nl .. str2
es:remove(i+1)
end
end
return es
end
local function metaAdd(meta)
--for key, val in pairs(PANDOC_READER_OPTIONS) do
-- quarto.log.warning(key, val)
--end
quarto.doc.addHtmlDependency({name='ansicolors',
stylesheets = {'resources/css/ansicolor.css'}})
quarto.doc.addHtmlDependency({name='juliamonofont',
stylesheets = {'resources/css/juliamono.css'}})
if quarto.doc.isFormat('latex') then
quarto.doc.include_file("in-header", "resources/juliainc.tex")
end
end
return {
{Div = divStderr},
{Div = divCodeBlockNoHeader1},
{Blocks = blockMerge},
{CodeBlock = codeBlockTrans},
{Meta = metaAdd}
}

View File

@@ -1,7 +1,6 @@
/* CSS added by ANSI escape sequences filter */
.ansi {
/* line-height:1.15; */
overflow:auto;
}
@@ -46,5 +45,8 @@ pre .ansi-cyan-intense-bg { background-color: #258f8f; }
pre .ansi-white-intense-bg { background-color: #a1a6b2; }
pre .ansi-default-inverse-fg { color: rgba(255, 255, 255, 1); }
pre .ansi-default-inverse-bg { background-color: #111111; }
pre .ansi-bold { font-weight: bold; }
pre .ansi-bold { font-weight: 800; }
pre .ansi-light { font-weight: 300; }
pre .ansi-italic { font-style: italic; }
pre .ansi-underline { text-decoration: underline; }

View File

@@ -0,0 +1,110 @@
@font-face {
font-family: JuliaMono;
font-weight: 300;
font-style: normal;
src: url("../fonts/JuliaMono-Light.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 400;
font-style: normal;
src: url("../fonts/JuliaMono-Regular.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 500;
font-style: normal;
src: url("../fonts/JuliaMono-Medium.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 600;
font-style: normal;
src: url("../fonts/JuliaMono-SemiBold.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 700;
font-style: normal;
src: url("../fonts/JuliaMono-Bold.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 800;
font-style: normal;
src: url("../fonts/JuliaMono-ExtraBold.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 900;
font-style: normal;
src: url("../fonts/JuliaMono-Black.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 300;
font-style: italic;
src: url("../fonts/JuliaMono-LightItalic.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 400;
font-style: italic;
src: url("../fonts/JuliaMono-RegularItalic.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 500;
font-style: italic;
src: url("../fonts/JuliaMono-MediumItalic.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 600;
font-style: italic;
src: url("../fonts/JuliaMono-SemiBoldItalic.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 700;
font-style: italic;
src: url("../fonts/JuliaMono-BoldItalic.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 800;
font-style: italic;
src: url("../fonts/JuliaMono-ExtraBoldItalic.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 900;
font-style: italic;
src: url("../fonts/JuliaMono-BlackItalic.woff2") format("woff2");
text-rendering: optimizeLegibility;
}

View File

@@ -8,9 +8,15 @@
BoldFont = *-Bold,
ItalicFont = *-RegularItalic,
BoldItalicFont = *-BoldItalic,
FontFace={l}{n}{Font=*-Light},
FontFace={l}{it}{Font=*-LightItalic},
Contextuals = AlternateOff,
]
\DeclareRobustCommand{\lseries}{\fontseries{l}\selectfont}
\DeclareTextFontCommand{\textlight}{\lseries}
\DefineVerbatimEnvironment{OutputCell}{Verbatim}%
{xleftmargin=1.5em}
\DefineVerbatimEnvironment{AnsiOutputCell}{Verbatim}%
@@ -35,4 +41,4 @@
\definecolor{ansi-white}{HTML}{C5C1B4}
\definecolor{ansi-white-intense}{HTML}{A1A6B2}
\definecolor{ansi-default-inverse-fg}{HTML}{FFFFFF}
\definecolor{ansi-default-inverse-bg}{HTML}{000000}
\definecolor{ansi-default-inverse-bg}{HTML}{000000}

View File

@@ -0,0 +1,31 @@
#show raw: set text(font: "JuliaMono")
// define cell layout
#let OutputCell = block.with(width:100%, inset: 5pt)
#let AnsiOutputCell = block.with(width: 100%, inset: 5pt)
#let StderrOutputCell = block.with(width: 100%, stroke: 1pt + red, inset: 5pt)
//#set highlight(top-edge: "ascender", bottom-edge: "descender")
#let invertbox(color, c) = box(outset: (x: 0.05em, y: 0.25em), fill: color, c)
//https://github.com/typst/typst/discussions/3057q
#let ansi-black = rgb("#3E424D")
#let ansi-black-intense = rgb("#282C36")
#let ansi-red = rgb("#E75C58")
#let ansi-red-intense = rgb("#B22B31")
#let ansi-green = rgb("#00A250")
#let ansi-green-intense = rgb("#007427")
#let ansi-yellow = rgb("#DDB62B")
#let ansi-yellow-intense = rgb("#B27D12")
#let ansi-blue = rgb("#208FFB")
#let ansi-blue-intense = rgb("#0065CA")
#let ansi-magenta = rgb("#D160C4")
#let ansi-magenta-intense = rgb("#A03196")
#let ansi-cyan = rgb("#60C6C8")
#let ansi-cyan-intense = rgb("#258F8F")
#let ansi-white = rgb("#C5C1B4")
#let ansi-white-intense = rgb("#A1A6B2")
#let ansi-default-inverse-fg = rgb("#FFFFFF")
#let ansi-default-inverse-bg = rgb("#000000")

View File

@@ -1,15 +0,0 @@
title: Extensions for Julia
author: Meik Hellmund
version: 0.3.0
contributes:
format:
common:
filters:
- ansi2htmltex.lua
ipynb-filters:
- escfilter.py
pdf:
default
html:
monofont: "JuliaMono"

View File

@@ -1,5 +0,0 @@
import sys
f = sys.stdin.read()
g = f.replace('\\u001b[','ꍟ⦃').replace('\\u001b]8;;','').replace('\\u001b\\\\','')
sys.stdout.write(g)

View File

@@ -1,55 +0,0 @@
@font-face {
font-family: JuliaMono;
font-weight: 300;
font-style: normal;
src: url("../fonts/JuliaMono-Light.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 400;
font-style: normal;
src: url("../fonts/JuliaMono-Regular.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 500;
font-style: normal;
src: url("../fonts/JuliaMono-Medium.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 600;
font-style: normal;
src: url("../fonts/JuliaMono-SemiBold.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 700;
font-style: normal;
src: url("../fonts/JuliaMono-Bold.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 800;
font-style: normal;
src: url("../fonts/JuliaMono-ExtraBold.woff2") format("woff2");
text-rendering: optimizeLegibility;
}
@font-face {
font-family: JuliaMono;
font-weight: 900;
font-style: normal;
src: url("../fonts/JuliaMono-Black.woff2") format("woff2");
text-rendering: optimizeLegibility;
}

View File

@@ -1,7 +1,7 @@
title: LaTeX Environment
author: RStudio, PBC
version: 1.1.1
quarto-required: ">=1.2.198"
author: Posit Software, PBC
version: 1.2.1
quarto-required: ">=1.3"
contributes:
filters:
- latex-environment.lua

View File

@@ -97,6 +97,17 @@ local function writeEnvironments(divEl)
end
end
local function buildCommandArgs(opts, format)
local function wrap(o)
return string.format(format, o)
end
local t = pandoc.List()
for str in string.gmatch(opts, "([^"..",".."]+)") do
t:insert(str)
end
return table.concat(t:map(wrap), "")
end
-- use the environments from metadata to
-- emit a custom environment for latex
local function writeCommands(spanEl)
@@ -105,19 +116,25 @@ local function writeCommands(spanEl)
if spanEl.attr.classes:includes(k) then
-- resolve the begin command
local beginCommand = pandoc.RawInline('latex', '\\' .. pandoc.utils.stringify(v) .. '{')
local beginCommand = '\\' .. pandoc.utils.stringify(v)
local opts = spanEl.attr.attributes['options']
local args = spanEl.attr.attributes['arguments']
if opts then
beginCommand = pandoc.RawInline('latex', '\\' .. pandoc.utils.stringify(v) .. '[' .. opts .. ']{')
beginCommand = beginCommand .. buildCommandArgs(opts, "[%s]")
end
if args then
beginCommand = beginCommand .. buildCommandArgs(args, "{%s}")
end
local beginCommandRaw = pandoc.RawInline('latex', beginCommand .. '{')
-- the end command
local endCommand = pandoc.RawInline('latex', '}')
local endCommandRaw = pandoc.RawInline('latex', '}')
-- attach the raw inlines to the span contents
local result = spanEl.content
table.insert(result, 1, beginCommand)
table.insert(result, endCommand)
table.insert(result, 1, beginCommandRaw)
table.insert(result, endCommandRaw)
return result
end

View File

@@ -2,7 +2,6 @@ project:
type: book
resources:
- fonts/
- js/
- images/
lang: de
@@ -27,7 +26,7 @@ book:
href: "Julia-f%C3%BCr-Numerik.pdf"
search: false
search: true
downloads: [pdf]
date: today
page-footer:
@@ -55,23 +54,19 @@ book:
- chapters/7_ArraysP2.qmd
- chapters/11_LinAlg.qmd
- chapters/10_Strings.qmd
- chapters/13_IO.qmd
- chapters/14_Plot.qmd
# - chapters/makie.qmd
# - chapters/ablaufsteuerung.qmd
# - chapters/example.qmd
# - chapters/intro.qmd
# - chapters/summary.qmd
format:
julia-html:
julia-color-html:
theme:
light: [cosmo, css/light.scss]
dark: [superhero, css/dark.scss]
css:
- css/styles.css
# - css/fonts-HK.css
- css/roboto-condensed.css
highlight-style: github # arrow ?????
mainfont: "Roboto Condensed" # Ubuntu # "Atkinson Hyperlegible" # Verdana #Quicksand
toc: true # change for Vorlesung
@@ -84,9 +79,10 @@ format:
body-width: 1150px # 800
margin-width: 250px
gutter-width: 1.5em
cap-location: bottom
cap-location: bottom
html-math-method: mathjax
julia-pdf:
julia-color-pdf:
pdf-engine: xelatex
papersize: a4
documentclass: scrreprt
@@ -112,7 +108,7 @@ format:
latex-auto-install: false
execute:
cache: false
cache: true
output: true
echo: true
warning: true
@@ -120,6 +116,7 @@ execute:
eval: true
freeze: auto
daemon: 3600
preserve-ansi: true
keep-ipynb: true
keep-tex: true
@@ -129,7 +126,6 @@ jupyter: julia-1.10
filters:
- code-visibility
- julia
- latex-environment
environments: [quote,indentb]
environments: [quote, indentb]

View File

@@ -1,92 +1,107 @@
# Zeichen, Strings und Unicode
---
engine: julia
---
## Zeichencodierungen (Frühgeschichte)
```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
import QuartoNotebookWorker
Base.stdout = QuartoNotebookWorker.with_context(stdout)
```
Es gab - abhängig von Hersteller, Land, Programmiersprache, Betriebsssystem,... - eine große Vielzahl von Codierungen.
# Characters, Strings, and Unicode
Bis heute relevant sind:
## Character Encodings (Early History)
There were - depending on manufacturer, country, programming language, operating system, etc. - a large variety of encodings.
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 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 erschien 2021 mit 149 186 Zeichen (das sind 4489 mehr als Unicode 14), 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 5...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
@@ -104,32 +119,30 @@ 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 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}
"""
printuc(c, n):
print n characters from unicode table, starting with character c
"""
function printuc(c, n)
for i in 0:n-1
print(c + i)
@@ -137,14 +150,15 @@ function printuc(c, n)
end
```
__Kyrillisch__
__Cyrillic__
```{julia}
printuc('\U0400', 100)
```
__Tamilisch__
__Tamil__
:::{.cellmerge}
```{julia}
@@ -165,21 +179,21 @@ printuc('\U0be7',20)
:::
__Schach__
__Chess__
```{julia}
printuc('\U2654', 12)
```
__Mathematische Operatoren__
__Mathematical Operators__
```{julia}
printuc('\U2200', 255)
```
__Runen__
__Runes__
```{julia}
@@ -188,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}
@@ -214,65 +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.
### Zeichenketten: `String`
## Characters and Character Strings in Julia
- 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.
### 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.
```{julia}
@show typeof('a') sizeof('a') typeof("a") sizeof("a");
```
- `Char`s können von/zu `UInt`s umgewandelt werden.
`Char`s can be converted to/from `UInt`s.
```{julia}
UInt('a')
@@ -283,21 +285,34 @@ UInt('a')
b = Char(0x2656)
```
__Bei einem Nicht-ASCII-String unterscheiden sich Anzahl der Bytes und Anzahl der Zeichen:__
### Character Strings: `String`
- 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}
@show typeof('a') sizeof('a') typeof("a") sizeof("a");
```
__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}
@@ -306,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}
@@ -383,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}
@@ -394,7 +409,7 @@ all(ispunct, ";.:")
```{julia}
any(isdigit, "Es ist 3 Uhr! 🕒" )
any(isdigit, "It is 3 o'clock! 🕒" )
```
@@ -402,7 +417,7 @@ any(isdigit, "Es ist 3 Uhr! 🕒" )
count(islowercase, "Hello, du!!")
```
### Weitere String-Funktionen
### Other String Functions
```{julia}
@@ -424,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)
@@ -476,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}
@@ -515,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

@@ -1,12 +1,23 @@
# Lineare Algebra in Julia
---
engine: julia
---
```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
```
# 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`
@@ -14,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
@@ -46,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}
@@ -78,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]
@@ -119,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
@@ -133,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]
@@ -152,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
@@ -189,15 +200,26 @@ 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
#| echo: false
#| output: false
using CairoMakie
CairoMakie.activate!(type = "svg")
# set_theme!(size=(1600, 360))
```
```{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()
])
@@ -231,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
$$
@@ -242,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}
@@ -281,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 \\
@@ -292,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 \\
@@ -320,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
@@ -339,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}
@@ -353,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,:])
@@ -391,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)
@@ -420,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}
@@ -440,4 +459,3 @@ Af \ [1, 2, 3]
```{julia}
Af \ [5, 7, 9]
```

491
chapters/13_IO.qmd Normal file
View File

@@ -0,0 +1,491 @@
---
engine: julia
---
```{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}
#| error: false
#| echo: false
#| output: false
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L516-L520
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L3073-L3077
using InteractiveUtils
import QuartoNotebookWorker
Base.stdout = QuartoNotebookWorker.with_context(stdout)
myactive_module() = Main.Notebook
Base.active_module() = myactive_module()
```
## Console
The operating system normally provides 3 channels (_streams_) for a program:
- Standard input channel `stdin`
- Standard output channel `stdout` and
- Standard error output channel `stderr`.
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`.
- Writing to `stdout`: `print()`,`println()`,`printstyled()`
- Writing to `stderr`: `print(strerr,...)`, `println(stderr,...)`, `printstyled(stderr,...)`
- Reading from `stdin`: `readline()`
### Input
The language _Python_ provides a function `input()`:
```{.python}
ans = input("Please enter a positive number!")
```
The function prints the prompt, waits for input, and returns the
input as a `string`.
In Julia, you can implement this function as follows:
```{julia}
function input(prompt = "Input:")
println(prompt)
flush(stdout)
return chomp(readline())
end
```
**Comments**
- 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("Please enter 2 numbers!")
```
```{julia}
#| echo: false
a = "34 56"
```
### Processing the Input
> `split(str)` splits a string into "words" and returns an _(array of strings)_:
```{julia}
av = split(a)
```
> `parse(T, str)` tries to convert `str` to type `T`:
```{julia}
v = parse.(Int, av)
```
`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()`.
### 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)
## Formatted Output with the `Printf` Macro
Often you want to output numbers or strings with a strict format specification - total length, decimal places, right/left-aligned, etc.
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("Output right-aligned with max. 10 character width and 3 decimal places: x= %10.3f", x)
```
The first argument is a string containing placeholders (here: `%10.3`) for variables to be output; followed by these variables as further arguments.
Placeholders have the form
```
%[flags][width][.precision]type
```
where the entries in square brackets are all optional.
**Type specifications in placeholders**
| | |
|:--|:------------|
|`%s`| `string`|
|`%i`| `integer`|
|`%o`| `integer octal (base=8)`|
|`%x, %X`| `integer hexadecimal (base=16) with digits 0-9abcdef or 0-9ABCDEF, resp.`|
|`%f`| `floating point number`|
|`%e`| `floating point number, scientific representation`|
|`%g`| `floating point, uses %f or %e depending on value`|
: {.striped .hover}
**Flags**
| | |
|:----|:-----|
|Plus sign| right-aligned (default)|
|Minus sign| left-aligned|
|Zero| with leading zeros|
: {.striped .hover}
**Width**
```
Number of minimum characters used (more will be taken if necessary)
```
### Examples:
```{julia}
using Printf # Don't forget to load the package!
```
```{julia}
@printf("|%s|", "Hello") # string with placeholder for string
```
The vertical bars are not part of the placeholder. They are intended to indicate the boundaries of the output field.
```{julia}
@printf("|%10s|", "Hello") # Minimum length, right-aligned
```
```{julia}
@printf("|%-10s|", "Hello") # left-aligned
```
```{julia}
@printf("|%3s|", "Hello") # Length specification can be exceeded
# Better a 'badly formatted' table than incorrect values!
```
```{julia}
j = 123
k = 90019001
l = 3342678
@printf("j= %012i, k= %-12i, l = %12i", j, k, l) # 0-flag for leading zeros
```
`@printf` and `@sprintf` can be called like functions or as macros:
```{julia}
@printf("%i %i", 22, j)
```
-- or as macros, i.e., without function parentheses and without comma:
```{julia}
@printf "%i %i" 22 j
```
`@printf` can take a stream as its first argument.
Otherwise, the argument list consists of
- format string with placeholders
- variables in the order of the placeholders, matching in number and type to the placeholders
```{julia}
@printf(stderr, "First result: %i %s\nSecond result %i",
j, "(estimated)" ,k)
```
The macro `@sprintf` does not print anything but returns the filled formatted string:
```{julia}
str = @sprintf("x = %10.6f", π );
```
```{julia}
str
```
### Formatting Floating Point Numbers:
Meaning of the _precision_ value:
- `%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 decimal places
```
```{julia}
@printf("%20.7f %20.7e", x, x) # 7 decimal places
```
```{julia}
@printf("%20.7g %20.4g", x, x) # total 7 and 4 digits respectively
```
## File Operations
Files are
- 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, opens at file beginning
"w" write, opens at file beginning (file is created or overwritten)
"a" append, opens to continue writing at file end
```
Let's write a file:
```{julia}
file = open("datei.txt", "w")
```
```{julia}
@printf(file, "%10i\n", k)
```
```{julia}
println(file, " second line")
```
```{julia}
close(file)
```
Let's look at the file:
```{julia}
;cat datei.txt
```
...and now we open it again for reading:
```{julia}
stream = open("datei.txt", "r")
```
`readlines(stream)` returns all lines of a text file as a vector of strings.
`eachline(stream)` returns an iterator over the lines of the file.
```{julia}
n = 0
for line in eachline(stream) # Read line by line
n += 1
println(n, line) # Print with line number
end
close(stream)
```
## Packages for File Formats
For input and output in various file formats, there are Julia packages, e.g.,
- [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
and many more...
### DelimitedFiles.jl
This package enables convenient saving/reading of matrices. It provides the functions `writedlm()` and `readdlm()`.
```{julia}
using DelimitedFiles
```
We generate a 200×3 matrix of random numbers
```{julia}
A = rand(200,3)
```
and save it
```{julia}
f = open("data2.txt", "w")
writedlm(f, A)
close(f)
```
The written file starts like this:
```{julia}
;head data2.txt
```
Reading it back is even simpler:
```{julia}
B = readdlm("data2.txt")
```
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
writedlm(io, A)
end
```
### 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
# 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)
file = CSV.File(http_response, header=false);
```
The data looks like this:
```{julia}
# https://dev.meteostat.net/bulk/hourly.html#endpoints
#
# 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
#| output: false
#| eval: false
describe(df)
```
For convenient plotting and handling of date and time formats in the weather table,
we load two helper packages:
```{julia}
using StatsPlots, Dates
```
We create a new column that combines date (from column 1) and time (from column 2):
```{julia}
# new column combining col. 1 and 2 (date & time)
df[!, :datetime] = DateTime.(df.Column1) .+ Hour.(df.Column2);
```
```{julia}
#| error: false
#| echo: false
#| output: false
#| eval: false
@df df plot(:datetime, :Column3)
```
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" "Rain" "Temp"],
legend=:none, size=(800,800))
```

View File

@@ -1,365 +1,433 @@
# Plots, Datenvisualisierung und Grafik in Julia
---
engine: julia
---
```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
```
Es gibt zahlreiche Grafikpakete für Julia. Das Folgende ist nur eine kleine Auswahl.
# Plots and Data Visualization in Julia: _Plots.jl_
## Reines Julia: Makie.jl
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.
`Makie` bezeichnet sich selbst als _"data visualization ecosystem for Julia"_.
## Brief Overview: Some Graphics Packages
Es ist vollständig in Julia geschrieben und bietet als _backends_ `Cairo` (Vektorgrafik), `OpenGL` und `WebGL` an.
| Package/Documentation | Tutorial | Examples | Remarks |
|:----|:--|:--|:--------|
|[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 to Matplotlib (Python), 1:1 transfer of the Python API, therefore see [Matplotlib documentation](https://matplotlib.org/stable/api/pyplot_summary.html)
{: .striped .hover}
- [Makie.jl](https://docs.makie.org/stable/)
- [Beautiful Makie](https://beautiful.makie.org/) - eine Seite mit vielen Beispielen
## Einbindung anderer Grafikbibliotheken
Viele Pakete liefern ein Interface zu existierender hochwertiger Visualisierungsssoftware.
### JavaScript: Interaktive Plots und Visualisierungen im Browser
- [PlotlyJS.jl](http://juliaplots.org/PlotlyJS.jl/stable/examples/3d/) Interface zur PlotlyJS-Grafikbibliothek
- [Bokeh.jl](https://cjdoris.github.io/Bokeh.jl/stable/gallery/) Interface zur Bokeh-Grafikbibliothek
- [VegaLite.jl](https://www.queryverse.org/VegaLite.jl/stable/) Interface zu VegaLite, vor allem statistische Plots
In der Regel kann man die Grafiken auch in ein Bildformat wie PNG exportieren.
### Cairo: 2D Vektorgrafik
- [Luxor.jl](http://juliagraphics.github.io/Luxor.jl/stable/) für Vektorgrafik
- [Javis.jl](https://juliaanimators.github.io/Javis.jl/stable/) für animierte Vektorgrafik
### Matplotlib (Python)
- [PyPlot.jl](https://github.com/JuliaPy/PyPlot.jl)
- weitgehende 1:1-Übertragung der Python-API, deswegen wird auch auf die [Matplotlib-Dokumentation](https://matplotlib.org/stable/gallery/index.html) verwiesen
- Beispiele mit Gegenüberstellung Python/Julia: [https://gist.github.com/gizmaa/7214002](https://gist.github.com/gizmaa/7214002)
### ggplot2 (R)
- [TidierPlots.jl](https://github.com/TidierOrg/TidierPlots.jl) "is a 100% Julia implementation of the R package ggplot2 powered by Makie.jl."
<!--
| [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
### Simple Plots
The `plot()` function expects, in the simplest case:
- 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}
using Plots
plotly()
x = 1:33
y = rand(33)
plot(x, y, linecolor =:green, bg_inside =:pink, line =:solid, label = "Wasserstand")
x = range(0, 8π; length = 100)
sx = @. sin(x) # the @. macro broadcasts (vectorizes) every operation
cx = @. cos(2x^(1/2))
plot(x, [sx cx])
```
- [Plots.jl](https://docs.juliaplots.org/latest/) ist konzipiert als ein einheitliches Interface zu verschiedenen _backends_ (Grafikbibliotheken).
> Man kann zu einem anderen _backend_ wechseln und dieselben Plot-Kommandos und -Attribute verwenden.
- Einige _backends_:
- 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 third one
```
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])
plot1a = deepcopy(plot1) # plot objects are quite deep structures
scatter!(plot1, x, sx) # add scatter plot, i.e. unconnected data points
```
The copied version `plot1a` has not been modified by the `scatter!` statement and can be used independently:
```{julia}
plot!(plot1a, x, 2 .* sx)
```
Plot objects can be saved as graphics files (PDF, SVG, PNG,...):
```{julia}
savefig(plot1, "plot.png")
```
```{julia}
;ls -l plot.png
```
Plot objects can also be inserted as subplots into other plots, see section @sec-subplot.
### Function Plots
`plot()` can also be passed a function and a vector of $x$-values:
```{julia}
# https://mzrg.com/math/graphs.shtml
f(x) = abs(sin(x^x)/2^((x^x-π/2)/π))
plot(f, 0:0.01:3)
```
- [GR](https://gr-framework.org/)
- PyPlot (d.h., Matplotlib)
- Plotly(JS)
The parametric form $x = x(t),\ y = y(t)$ can be drawn by passing two functions and a vector of $t$-values to `plot()`.
__Im Rest dieses Notebooks wird Plots.jl vorgestellt.__
```{julia}
# https://en.wikipedia.org/wiki/Butterfly_curve_(transcendental)
xt(t) = sin(t) * (exp(cos(t))-2cos(4t)-sin(t/12)^5)
yt(t) = cos(t) * (exp(cos(t))-2cos(4t)-sin(t/12)^5)
## einige _backends_
```julia
using Plots
backend() # Anzeige des gewählten backends, GR ist der default
plot(xt, yt, 0:0.01:12π)
```
```julia
x = 1:30
y = rand(30)
plot(x, y, linecolor =:green, bg_inside =:pink, line =:solid, label = "Wasserstand")
```
### Plot Themes
> "PlotThemes is a package to spice up the plots made with Plots.jl."\
Here is the illustrated [list of themes](https://docs.juliaplots.org/stable/generated/plotthemes/)
```julia
# wir wechseln das backend zu
# plotly/js
or:
```{julia}
using PlotThemes
plotly()
```
```julia
# dasselbe Plot-Kommando
# das ist interaktiv (zoom in/out, pan),
# 'überlebt' aber leider die PDF-Konvertierung des notebooks nicht
plot(x, y, linecolor =:green, bg_inside =:pink, line =:solid, label = "Wasserstand")
```
```julia
# und noch ein backend
pyplot()
```
```julia
plot(x, y, linecolor =:green, bg_inside =:pink, line =:solid, label = "Wasserstand")
```
```julia
# zurück zu GR als backend
gr()
```
## Plots.jl und recipes
Andere Pakete können die Möglichkeiten von `Plots.jl` erweitern, indem sie _recipes_ für spezielle Plots und Datenstrukturen definieren, siehe [https://docs.juliaplots.org/latest/ecosystem/](https://docs.juliaplots.org/latest/ecosystem/), z.B.:
- `StatsPlots.jl` direktes Plotten von Dataframes, spezielle statistische Plots,...
- `GraphRecipes.jl` [Plotten von Graphstrukturen](https://docs.juliaplots.org/stable/graphrecipes/examples/)
- ...
## Einige Verschönerungen
```julia
using Plots.PlotMeasures # für Angaben in mm, cm,...
using LaTeXStrings # für LaTeX-Konstrukte in Plot-Beschriftungen
using PlotThemes # vorgefertigte Themen
```
```julia
# Liste der Themen
# list of themes
keys(PlotThemes._themes)
```
```julia
```{julia}
Plots.showtheme(:juno)
```
```{julia}
using PlotThemes
```julia
Plots.showtheme(:dao)
theme(:juno) # set a theme for all further plots
plot(x, [sx cx 1 ./ (1 .+ x)])
```
```julia
# so legt man ein Thema für die folgenden Plots fest:
### Plot Attributes
theme(:dao)
The functions of the `Plots.jl` package have a large number of options.
`Plots.jl` divides the attributes into 4 groups:
# Wir wollen es wieder langweilig haben...
theme(:default)
::::{.cell}
```{julia}
#| output: asis
plotattr(:Plot) # attributes for the overall plot
```
::::
## Funktionen in Plots.jl
::::{.cell}
```{julia}
#| output: asis
plotattr(:Subplot) # attributes for a subplot
```
plot()
scatter()
contour()
heatmap()
histogram()
bar()
plot3d()
... und weitere
::::
::::{.cell}
```{julia}
#| output: asis
plotattr(:Axis) # attributes for an axis
```
Diese Funktionen erzeugen ein neues `Plot`-Objekt.
::::
Die Varianten mit Ausrufezeichen `plot!(), scatter!(),...` modifizieren das letzte `Plot`-Objekt oder das `Plot`-Objekt, das ihnen als 1. Argument übergeben wird:
::::{.cell}
```{julia}
#| output: asis
plotattr(:Series) # attributes for a series, e.g., a line in the plot
```
::::
```julia
x = range(0,10, length=40) # 40 x-Werte von 0 bis 10
pl1 = plot(x, sin.(x))
One can also ask what the individual attributes mean and which values are allowed:
```{julia}
plotattr("linestyle")
```
```julia
pl1a = deepcopy(pl1) # unmodifizierte copy aufheben
An example:
```{julia}
theme(:default) # return to default theme
pl2 = plot!(x, cos.(x)) # modifiziert pl1
x = 0:0.05:1
y = sin.(2π*x)
plot(x, y, seriestype = :sticks, linewidth = 4, seriescolor = "#00b300",
marker = :circle, markersize = 8, markercolor = :green,
)
```
Many specifications can also be abbreviated significantly, see e.g. the `Aliases:` in the above output of the command `plotattr("linestyle")`.
The following `plot()` command is equivalent to the previous one:
```{julia}
#| eval: false
plot(x, y, t = :sticks, w = 4, c = "#00b300", m = (:circle, 8, :green ))
```
```julia
pl3 = scatter!(pl1a, x, cos.(x)) # add to (copy of) original Plot
### Additional Extras
```{julia}
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
```
Plot-Objekte kann man als Grafikdateien (PDF, SVG, PNG,...) abspeichern:
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
savefig(pl2, "pl2.png")
```
```julia
;ls -l pl2.png
```
... oder zB als Sub-Plots mit einem layout-Parameter zusammenfügen:
```julia
plot(pl1, pl2, pl3, layout = (1,3))
```
```julia
plot(pl1, pl2, pl3, layout = (3,1))
```
## Input-Daten
- im einfachsten Fall ein Vektor von $m$ `x`-Werten und ein gleichlanger Vektor von $m$ `y`-Werten
- falls $y$ eine $m\times n$-Matrix ist, wird jeder Spaltenvektor als eine `Series` angesehen und es werden $n$ Kurven geplottet:
```julia
plot(x, [sin.(x) cos.(x) sqrt.(x)])
```
- Durch eine `layout`-Angabe kann man die einzelnen `series` auch in einzelnen Subplots
unterbringen.
- Man kann `layouts` auch schachteln und explizite Breiten/Höhenangaben verwenden.
```julia
theme(:dark)
la1 = @layout [
a{0.3w} [ b
c{0.2h} ]
]
plot(x, [sin.(x) cos.(x) sqrt.(x)] , layout = la1)
```
## Plot-Attribute
`Plots.jl` teilt die Attribute in 4 Gruppen ein:
```julia
plotattr(:Plot) # Attribute für den Gesamtplot
```
```julia
plotattr(:Subplot) # Attribute für einen Teilplot
```
```julia
plotattr(:Axis) # Attribute für eine Achse
```
```julia
plotattr(:Series) # Attribute für eine Serie, also zB ein Linienzug im Plot
```
```julia
# Zur Erinnerung nochmal:
using Plots
using Plots.PlotMeasures # für Angaben in mm, cm,...
using LaTeXStrings # für LaTeX-Konstrukte in Plot-Beschriftungen
using PlotThemes # vorgefertigte Themen
```
```julia
```{julia}
xs = range(0, 2π, length = 100)
data = [sin.(xs) cos.(xs) 2sin.(xs) (x->sin(x^2)).(xs)]
data = [sin.(xs) cos.(xs) 2sin.(xs) (x->sin(x^2)).(xs)] # 4 functions
pl10 = plot(xs, data,
theme(:ggplot2)
plot10 = plot(xs, data,
fontfamily="Computer Modern",
# LaTeX-String L"" ist im Math-mode
title = L"\textrm{Winkelfunktionen}\ \sin(\alpha), \cos(\alpha), 2\sin(\alpha), \sin(\alpha^2)",
xlabel = L"\textrm{ Winkel\ } \alpha",
ylabel = L"\textrm{Funktionswert}",
# 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'
color=[:black :green RGB(0.3, 0.8, 0.2) :blue ],
# 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 = [3 3 0 6],
linewidth = [1 3 1 5],
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,
yticks = -2:.4:2.3, # with step size
# legend
legend = :bottomleft,
label = [ L"\sin(\alpha)" "cos" "2sin" L"\sin(\alpha^2)"],
label = [ L"\sin(\alpha)" L"\cos(\alpha)" L"2\sin(\alpha)" L"\sin(\alpha^2)"],
top_margin = 5mm,
top_margin = 5mm, # here Plots.PlotMeasures is needed
)
# Zusatzelement
# additional text: annotate!(x-pos, y-pos, text("...", font, fontsize))
annotate!(pl10, 4.1, 1.8, text("nicht schön, aber viel",10))
annotate!(plot10, 4.1, 1.8, text("nicht schön, aber viel","Computer Modern", 10) )
```
### Other Plot Functions
So far, we have plotted mainly lines. There are many other types such as _scatter plot, contour, heatmap, histogram, stick,..._
This can be controlled with the `seriestype` attribute:
```{julia}
theme(:default)
x = range(0, 2π; length = 50)
plot(x, sin.(x), seriestype=:scatter)
```
or by using the specific function named after the `seriestype`:
```{julia}
x = range(0, 2π; length = 50)
scatter(x, sin.(x))
```
### Subplots and Layout {#sec-subplot}
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)
plots = [] # vector of plot objects
for f in [sin, cos, tan, sinc]
p = plot(x, f.(x))
push!(plots, p)
end
plot(plots..., layout=(2,2), legend=false, title=["sin" "cos" "tan" "sinc"])
```
```{julia}
plot(plots..., layout=(4,1), legend=false, title=["sin" "cos" "tan" "sinc"])
```
Layouts can also be nested and explicit width/height proportions can be specified using the `@layout` macro:
```{julia}
mylayout = @layout [
a{0.3w} [ b
c{0.2h} ]
d{0.2h}
]
plot(plots..., layout=mylayout, legend=false, title=["sin" "cos" "tan" "sinc"])
```
### Backends
`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.
However, not all _backends_ support all plot types and attributes. An overview is available [here](https://docs.juliaplots.org/stable/generated/supported/).
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() # display the selected backend, GR is the default
```
Another example
```{julia}
x = 1:30
y = rand(30)
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Wasserstand")
```
and here the same plot with the `PlotlyJS` backend.
```{julia}
plotlyjs() # change plots backend
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Wasserstand")
```
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() # return to GR as backend
```
### 3D Plots
The functions `surface()` and `contour()` allow plotting of a function $f(x,y)$. The required arguments are:
- 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)
surface( -3:0.02:3, -3:0.02:3, f)
```
```{julia}
contour( -3:0.02:3, -3:0.02:3, f, fill=true, colormap=:summer, levels=20, contour_labels=false)
```
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()
t = range(0, stop=8π, length=100) # parameter t
x = @. t * cos(t) # x(t), y(t), z(t)
y = @. 0.1 * t * sin(t)
z = @. 100 * t/8π
plot(x, y, z, zcolor=reverse(z), markersize=3, markershape= :circle,
linewidth=5, legend=false, colorbar=false)
```
### Säulendiagramm
> We use the `plotlyjs` backend here, so the plot is interactive and can be rotated and zoomed with the mouse.
### Plots.jl and _recipes_
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` direct plotting of _Dataframes_, special statistical plots, etc. or
- `GraphRecipes.jl` [Plotting of graph structures](https://docs.juliaplots.org/latest/GraphRecipes/examples/)
### A Bar Chart
```julia
For the last example, we load a package that provides over 700 free (_"public domain"_) datasets, including, for example:
- the passenger list of the _Titanic_,
- fuel consumption data of American cars from the 70s or
- historical exchange rates
provides:
```{julia}
using RDatasets
```
Inhalt: über 700 freie (_"public domain"_) Datensätze, darunter z.B:
- Passagierliste der _Titanic_
- Verbrauchsdaten amerikanischer Autos aus den 70ern
- historische Währungskurse
```julia
RDatasets.datasets()
```{julia}
#| error: false
#| echo: false
#| output: false
#RDatasets.datasets()
```
The dataset ["Motor Trend Car Road Tests"](https://rdrr.io/r/datasets/mtcars.html)
```julia
```{julia}
cars = dataset("datasets", "mtcars")
```
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
```{julia}
theme(:bright)
bar(cars.Model, cars.MPG,
@@ -375,6 +443,35 @@ bar(cars.Model, cars.MPG,
```
```julia
### What is Missing: Animation
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
#| warning: false
using Plots, Random
theme(:default)
anim = @animate for i in 1:50
Random.seed!(123)
scatter(cumsum(randn(i)), ms=i, lab="", alpha = 1 - i/50,
xlim=(0,50), ylim=(-5, 7))
end
gif(anim, fps=50)
```
:::: {.content-visible when-format="pdf"}
```{julia}
#| echo: false
Random.seed!(123)
i = 33
scatter(cumsum(randn(i)), ms=i, lab="", alpha = 1 - i/50,
xlim=(0,50), ylim=(-5, 7))
```
::::

View File

@@ -1,36 +1,63 @@
# Arbeit mit Julia: REPL, Pakete, Introspection
---
engine: julia
---
## Dokumentation
```{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()
```
Die offizielle Julia-Dokumentation [https://docs.julialang.org/](https://docs.julialang.org/) enthält zahlreiche Übersichten, darunter:
# Working with Julia: REPL, Packages, Introspection
- [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
```{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()
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L516-L520
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L3073-L3077
```
## Documentation
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`|
@@ -38,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}
@@ -51,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}
@@ -59,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}
@@ -67,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 |
@@ -103,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
@@ -120,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}
@@ -139,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
@@ -218,5 +246,3 @@ walk_tree(p)
```{julia}
@code_native f(2,4)
```

View File

@@ -1,63 +1,66 @@
# Container
---
engine: julia
---
# Containers
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`.
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`.
Diese Container sind:
These containers are:
- **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}
@@ -69,96 +72,100 @@ 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 [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
@allocated r = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
```
```{julia}
@allocated 1:20
@allocated r = 1:20
```
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)
@@ -169,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)
```
@@ -202,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
@@ -227,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}
@@ -274,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
@@ -330,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

@@ -1,36 +1,53 @@
---
engine: julia
---
# Funktionen und Operatoren
# Functions and Operators
Funktionen verarbeiten ihre Argumente zu einem Ergebnis, das sie beim Aufruf zurückliefern.
```{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()
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L516-L520
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L3073-L3077
```
## Formen
Funktionen können in verschiedenen Formen definiert werden:
Functions process their arguments to produce a result, which they return when called.
I. Als `function ... end`-Block
## Forms
Functions can be defined in different forms:
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)
@@ -40,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)
@@ -51,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}
@@ -78,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
@@ -107,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])
@@ -125,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}
@@ -158,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")
@@ -177,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")
@@ -187,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}
@@ -198,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
@@ -218,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.
@@ -246,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))$$
@@ -272,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}
@@ -289,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
## 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)
@@ -332,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
@@ -348,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;
@@ -362,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.
@@ -382,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}
@@ -393,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
@@ -447,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
@@ -523,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
@@ -540,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)
```
@@ -598,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

@@ -1,45 +1,57 @@
# Erste Miniprogramme
---
engine: julia
---
```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
```
# 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.
@@ -47,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])
@@ -87,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,
@@ -104,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
@@ -147,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

@@ -1,126 +1,76 @@
---
format:
html:
include-in-header:
text: |
<script type="application/javascript">
window.PlotlyConfig = {MathJaxConfig: 'local'}
</script>
engine: julia
---
# Ein Beispiel zur Stabilität von Gleitkommaarithmetik
## Berechnung von $\pi$ nach Archimedes
```{julia}
#| error: false
#| echo: false
#| output: false
using PlotlyJS, Random
using HypertextLiteral
using JSON, UUIDs
using Base64
## see https://github.com/JuliaPlots/PlotlyJS.jl/blob/master/src/PlotlyJS.jl
## https://discourse.julialang.org/t/encode-a-plot-to-base64/27765/3
function IJulia.display_dict(p::PlotlyJS.SyncPlot)
Dict(
# "application/vnd.plotly.v1+json" => JSON.lower(p),
# "text/plain" => sprint(show, "text/plain", p),
"text/html" => let
buf = IOBuffer()
show(buf, MIME("text/html"), p)
#close(buf)
#String(resize!(buf.data, buf.size))
String(take!(buf))
end,
"image/png" => let
buf = IOBuffer()
buf64 = Base64EncodePipe(buf)
show(buf64, MIME("image/png"), p)
close(buf64)
#String(resize!(buf.data, buf.size))
String(take!(buf))
end,
)
end
function Base.show(io::IO, mimetype::MIME"text/html", p::PlotlyJS.SyncPlot)
uuid = string(UUIDs.uuid4())
show(io,mimetype,@htl("""
<div style="height: auto" id=\"$(uuid)\"></div>
<script>
require(['../js/plotly-latest.min.js'], function(plotly) {
plotly.newPlot($(uuid),
$(HypertextLiteral.JavaScript(json(p.plot.data))),
$(HypertextLiteral.JavaScript(json(p.plot.layout))),{responsive: true});
});
</script>
"""))
end
using InteractiveUtils
```
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.
```{julia}
#| error: false
#| echo: false
#| output: false
flush(stdout)
```
# A Case Study in Floating-Point Arithmetic Stability
## Calculation of $\pi$ According to Archimedes
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
@@ -128,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)
@@ -148,78 +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.10.2 (2024-03-01)
_/ |\__'_|_|_|\__'_| | 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

@@ -1,9 +1,20 @@
---
engine: julia
---
```{julia}
#| error: false
#| echo: false
#| output: false
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
@@ -19,33 +30,34 @@ function mhelp(s,n,m)
end;
function Tab(s)
l = filter(x->startswith(x,s), REPL.doc_completions(s))
println.(l[2:end])
dc = map(x->x.name, REPL.doc_completions(s))
l = filter(x->startswith(x,s), dc)
println.(l)
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
@@ -57,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
@@ -66,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
```
@@ -91,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
@@ -194,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
@@ -269,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]
@@ -286,24 +299,25 @@ 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
function Tab(s)
l = filter(x->startswith(x,s), REPL.doc_completions(s))
println.(l[2:end])
dc = map(x->x.name, REPL.doc_completions(s))
l = filter(x->startswith(x,s), dc)
println.(l)
return # return nothing, since broadcast println produces empty vector
end

View File

@@ -1,6 +1,26 @@
# Maschinenzahlen
---
engine: julia
---
```{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
#| echo: false
#| output: false
using InteractiveUtils
```
```{julia}
for x ∈ ( 3, 3.3e4, Int16(20), Float32(3.3e4), UInt16(9) )
@@ -9,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
@@ -41,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
@@ -93,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}
@@ -110,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}
@@ -125,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)
@@ -163,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)
@@ -173,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)
@@ -224,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}
@@ -238,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)
@@ -255,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)
@@ -267,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}
@@ -283,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)
@@ -374,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\\
@@ -385,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}
@@ -401,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)
@@ -417,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}
@@ -455,7 +470,7 @@ end
Eps
```
oder als Bitmuster:
or as a bit pattern:
```{julia}
Eps=1
@@ -469,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)
@@ -493,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
@@ -533,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} &=
@@ -544,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) &=
@@ -555,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
@@ -584,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)
@@ -593,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
@@ -609,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
@@ -638,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
@@ -648,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))
```
@@ -662,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
@@ -686,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$
@@ -710,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)
@@ -740,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}
@@ -759,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

@@ -1,14 +1,31 @@
---
engine: julia
---
# Ein Fallbeispiel: Der parametrisierte Datentyp PComplex
# A Case Study: The Parametric Data Type PComplex
Wir wollen als neuen numerischen Typen **komplexe Zahlen in Polardarstellung $z=r e^{i\phi}=(r,ϕ)$** einführen.
```{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()
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L516-L520
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L3073-L3077
```
- 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.)
## Die Definition von `PComplex`
We want to introduce a new numeric type **complex numbers in polar representation $z=r e^{i\phi}=(r,\phi)$**.
Ein erster Versuch könnte so aussehen:
- 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.)
## The Definition of `PComplex`
A first attempt could look like this:
```{julia}
struct PComplex1{T <: AbstractFloat} <: Number
@@ -23,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}
@@ -56,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
@@ -77,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,ϕ)
@@ -88,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, '°')
@@ -134,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
@@ -159,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")
```
:::
@@ -173,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.))
@@ -181,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)
@@ -197,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)...)
@@ -225,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)
@@ -244,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);
@@ -260,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)
@@ -277,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?):
>
@@ -287,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, ϕ))
@@ -312,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))
@@ -321,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))
@@ -332,8 +348,7 @@ PComplex(z::Complex{S}) where {S<:Real} =
```
Ein Test der neuen Konstruktoren:
A test of the new constructors:
```{julia}
@@ -342,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}
@@ -354,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
@@ -374,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
@@ -390,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
@@ -426,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, '°')
@@ -448,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

@@ -1,65 +1,76 @@
---
engine: julia
---
```{julia}
#| error: false
#| echo: false
#| output: false
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
Im interaktiven Betrieb wird der Wert der letzten Anweisung auch ohne explizites `print()` ausgegeben:
## Example:
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]);
@@ -71,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
@@ -86,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) )
@@ -97,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.
=#
@@ -124,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
@@ -166,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
@@ -227,9 +236,9 @@ z = if x < y
end
```
## Vergleiche, Tests, Logische Operationen
## Comparisons, Tests, Logical Operations
### Arithmetische Vergleiche
### Arithmetic Comparisons
- `==`
- `!=`, `≠`
@@ -238,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
@@ -297,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")
@@ -326,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}
@@ -355,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:
@@ -366,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
@@ -386,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
@@ -411,7 +421,7 @@ while true
end
```
### `for`-Schleifen
### `for` Loops
Syntax:
@@ -421,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"]
@@ -432,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
@@ -459,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
@@ -474,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}
@@ -502,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
```
@@ -514,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!)
```
@@ -586,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

@@ -1,23 +1,36 @@
---
notebook-links: false
engine: julia
---
# Das Typsystem von Julia
```{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()
```
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.
Wir blicken jetzt trotzdem mal unter die Motorhaube.
# The Julia Type System
## Die Typhierarchie am Beispiel der numerischen Typen
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.
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.
However, we will now take a look under the hood.
## The Type Hierarchy: A Case Study with Numeric Types
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)
```
@@ -33,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
@@ -107,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
@@ -115,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
@@ -123,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}
@@ -148,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
@@ -175,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)
@@ -187,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)
@@ -211,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)
@@ -243,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)
@@ -281,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
@@ -291,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"
@@ -305,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
@@ -354,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
@@ -375,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
@@ -396,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}}}
@@ -428,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;
@@ -450,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)
@@ -458,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
@@ -467,27 +477,27 @@ 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}
const MyCmplxF64 = MyComplex{Float64}
z = MyComplex(1.1, 2.2)
z = MyCmplxF64(1.1, 2.2)
typeof(z)
```
--------
(3) Typen können Argumente von Funktionen sein.
(3) Types can be arguments of functions.
```{julia}
@@ -503,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)
@@ -587,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
@@ -639,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
@@ -659,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}
@@ -671,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
@@ -682,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})
@@ -690,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}
@@ -700,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,9 +1,12 @@
/*-- scss:defaults --*/
$h3-font-size: 1.2rem !default;
$border-radius: 0;
$font-family-monospace: "JuliaMono";
/* bug in superhero theme? */
h1,h2,h3,h4,h5,h6 {color: #f0f0f0 !important;}
@@ -12,6 +15,7 @@ h1,h2,h3,h4,h5,h6 {color: #f0f0f0 !important;}
.cell-output code span {color: #000;}
/*-- scss:rules --*/
div.cell-output { background-color: #dbdbdb; }

View File

@@ -1,11 +1,15 @@
/*-- scss:defaults --*/
$h3-font-size: 1.2rem !default;
$border-radius: 0;
/* $code-block-border-left: #909090; */
/* $code-block-bg: #f3f3f3; */
$code-block-bg: #f7f7f7;
$font-family-monospace: "JuliaMono";
/*-- scss:rules --*/
div.cell-output { background-color: #ffffff; }
code {color: #202020;}

162
css/roboto-condensed.css Normal file
View File

@@ -0,0 +1,162 @@
/* roboto-condensed-100 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 100;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-100.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-100.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-100italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: italic;
font-weight: 100;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-100italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-100italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-200 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 200;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-200.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-200.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-200italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: italic;
font-weight: 200;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-200italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-200italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-300 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 300;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-300.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-300.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-300italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: italic;
font-weight: 300;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-300italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-300italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-regular - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 400;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-regular.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-regular.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: italic;
font-weight: 400;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-500 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 500;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-500.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-500.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-500italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: italic;
font-weight: 500;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-500italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-500italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-600 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 600;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-600.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-600.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-600italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: italic;
font-weight: 600;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-600italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-600italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-700 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 700;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-700.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-700.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-700italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: italic;
font-weight: 700;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-700italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-700italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-800 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 800;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-800.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-800.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-800italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: italic;
font-weight: 800;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-800italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-800italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-900 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 900;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-900.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-900.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-condensed-900italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto Condensed';
font-style: italic;
font-weight: 900;
src: url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-900italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-condensed-v27-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext-900italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}

108
css/roboto.css Normal file
View File

@@ -0,0 +1,108 @@
/* roboto-100 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: normal;
font-weight: 100;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-100.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-100.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-100italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: italic;
font-weight: 100;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-100italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-100italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-300 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-300.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-300.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-300italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: italic;
font-weight: 300;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-300italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-300italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-regular - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-regular.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-regular.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-500 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-500.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-500.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-500italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: italic;
font-weight: 500;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-500italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-500italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-700 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-700.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-700.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-700italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: italic;
font-weight: 700;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-700italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-700italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-900 - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-900.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-900.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}
/* roboto-900italic - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Roboto';
font-style: italic;
font-weight: 900;
src: url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-900italic.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
url('../fonts/roboto-v32-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-900italic.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
}

View File

@@ -15,33 +15,7 @@
}
/* roboto-condensed-regular - latin-ext_latin_greek_cyrillic */
@font-face {
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 400;
src: url('../fonts/roboto-condensed-v25-latin-ext_latin_greek_cyrillic-regular.eot'); /* IE9 Compat Modes */
src: local(''),
url('../fonts/roboto-condensed-v25-latin-ext_latin_greek_cyrillic-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('../fonts/roboto-condensed-v25-latin-ext_latin_greek_cyrillic-regular.woff2') format('woff2'), /* Super Modern Browsers */
url('../fonts/roboto-condensed-v25-latin-ext_latin_greek_cyrillic-regular.woff') format('woff'), /* Modern Browsers */
url('../fonts/roboto-condensed-v25-latin-ext_latin_greek_cyrillic-regular.ttf') format('truetype'), /* Safari, Android, iOS */
url('../fonts/roboto-condensed-v25-latin-ext_latin_greek_cyrillic-regular.svg#RobotoCondensed') format('svg'); /* Legacy iOS */
}
/* roboto-regular - latin-ext_latin_greek_cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url('../fonts/roboto-v30-latin-ext_latin_greek_cyrillic-regular.eot'); /* IE9 Compat Modes */
src: local(''),
url('../fonts/roboto-v30-latin-ext_latin_greek_cyrillic-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('../fonts/roboto-v30-latin-ext_latin_greek_cyrillic-regular.woff2') format('woff2'), /* Super Modern Browsers */
url('../fonts/roboto-v30-latin-ext_latin_greek_cyrillic-regular.woff') format('woff'), /* Modern Browsers */
url('../fonts/roboto-v30-latin-ext_latin_greek_cyrillic-regular.ttf') format('truetype'), /* Safari, Android, iOS */
url('../fonts/roboto-v30-latin-ext_latin_greek_cyrillic-regular.svg#Roboto') format('svg'); /* Legacy iOS */
}
/* quicksand-regular - latin-ext_latin */
@font-face {
font-family: 'Quicksand';

View File

@@ -1,306 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<defs >
<font id="RobotoCondensed" horiz-adv-x="1021" ><font-face
font-family="Roboto Condensed"
units-per-em="2048"
panose-1="2 0 0 0 0 0 0 0 0 0"
ascent="1900"
descent="-500"
alphabetic="0" />
<glyph unicode=" " horiz-adv-x="469" />
<glyph unicode="!" horiz-adv-x="503" d="M332 411H173L160 1456H346L332 411ZM257 199Q307 199 332 169T358 93T333 19T257 -11Q206 -11 181 18T156 93T181 168T257 199Z" />
<glyph unicode="&quot;" horiz-adv-x="655" d="M277 1400L247 1042H136L137 1536H277V1400ZM547 1400L517 1042H406L407 1536H547V1400Z" />
<glyph unicode="#" horiz-adv-x="1122" d="M666 410H460L392 0H258L326 410H131V547H349L408 901H195V1040H431L500 1456H634L565 1040H771L840 1456H975L906 1040H1068V901H883L824 547H1005V410H801L733 0H598L666 410ZM483 547H689L748 901H542L483 547Z" />
<glyph unicode="$" horiz-adv-x="1011" d="M724 375Q724 466 674 528T502 644Q323 709 241 813T159 1079Q159 1243 238 1346T455 1472V1692H596V1471Q736 1446 812 1329T889 1008H714Q714 1147 663 1231T523 1315T385 1254T335 1082Q335 981 388 921T563 809Q744
741 822 640T901 377Q901 213 817 109T576 -16V-208H437V-16Q279 7 195 122T111 429H287Q287 290 343 215T501 140Q605 140 664 202T724 375Z" />
<glyph unicode="%" horiz-adv-x="1296" d="M107 1176Q107 1306 177 1391T361 1477Q473 1477 544 1393T616 1172V1099Q616 968 546 884T363 800T179 884T107 1105V1176ZM236 1099Q236 1019 271 970T363 920Q418 920 452 968T487 1103V1176Q487 1257 452 1306T361
1356Q304 1356 270 1306T236 1173V1099ZM695 357Q695 488 766 572T949 657T1133 573T1205 350V279Q1205 147 1133 63T951 -21Q839 -21 767 63T695 284V357ZM824 279Q824 198 859 149T951 99Q1007 99 1041 149T1075 282V357Q1075 438 1040 487T949 536Q894 536 859
488T824 354V279ZM399 110L302 176L899 1314L997 1248L399 110Z" />
<glyph unicode="&amp;" horiz-adv-x="1113" d="M103 391Q103 494 152 581T342 785Q260 900 230 974T199 1122Q199 1289 284 1382T514 1476Q646 1476 731 1388T816 1168Q816 1082 782 1009T662 861L559 773L815 404Q862 523 862 672H1020Q1020 420 918 256L1096
0H884L810 107Q753 48 672 14T504 -20Q321 -20 212 94T103 391ZM504 131Q621 131 719 241L430 662L400 637Q279 522 279 391Q279 275 339 203T504 131ZM375 1128Q375 1074 402 1017T472 896L549 962Q610 1011 632 1056T654 1168T614 1279T513 1324Q448 1324 412
1268T375 1128Z" />
<glyph unicode="&apos;" horiz-adv-x="357" d="M253 1425L232 1057H103L104 1536H253V1425Z" />
<glyph unicode="(" horiz-adv-x="643" d="M129 591Q129 853 200 1084T401 1489Q480 1594 553 1643L588 1521Q468 1406 391 1175T307 660L306 579Q306 227 405 -43Q480 -246 588 -357L553 -470Q461 -408 366 -266Q129 91 129 591Z" />
<glyph unicode=")" horiz-adv-x="652" d="M513 581Q513 135 313 -208Q205 -392 89 -470L54 -357Q180 -236 257 12T336 557V593Q336 973 211 1273Q142 1437 54 1530L89 1643Q199 1569 302 1400Q513 1052 513 581Z" />
<glyph unicode="*" horiz-adv-x="882" d="M330 983L28 1073L74 1224L376 1112L367 1456H520L510 1107L807 1217L853 1065L546 974L744 703L620 609L434 897L254 616L129 707L330 983Z" />
<glyph unicode="+" horiz-adv-x="1017" d="M596 781H925V606H596V146H418V606H86V781H418V1206H596V781Z" />
<glyph unicode="," horiz-adv-x="402" d="M134 -290L29 -218Q123 -87 127 52V219H308V74Q308 -27 259 -128T134 -290Z" />
<glyph unicode="-" horiz-adv-x="508" d="M460 543H47V694H460V543Z" />
<glyph unicode="." horiz-adv-x="539" d="M144 97Q144 145 172 177T258 209T344 177T374 97Q374 51 345 20T258 -11T173 20T144 97Z" />
<glyph unicode="/" horiz-adv-x="759" d="M181 -125H31L542 1456H691L181 -125Z" />
<glyph unicode="0" horiz-adv-x="1011" d="M895 621Q895 299 801 140T506 -20Q311 -20 215 133T115 593V843Q115 1162 209 1319T504 1476Q701 1476 795 1327T895 876V621ZM718 874Q718 1105 667 1214T504 1324Q395 1324 344 1217T291 892V592Q291 362 344 247T506
131Q614 131 665 240T718 573V874Z" />
<glyph unicode="1" horiz-adv-x="1011" d="M644 0H466V1233L160 1096V1264L616 1463H644V0Z" />
<glyph unicode="2" horiz-adv-x="1011" d="M931 0H117V133L532 683Q626 810 662 891T699 1064Q699 1180 645 1252T503 1324Q392 1324 332 1248T271 1027H94Q94 1228 204 1352T503 1476Q677 1476 777 1370T877 1086Q877 870 652 575L328 151H931V0Z" />
<glyph unicode="3" horiz-adv-x="1011" d="M343 818H456Q565 818 624 885T683 1068Q683 1324 485 1324Q390 1324 336 1255T282 1074H106Q106 1249 212 1362T485 1476Q657 1476 758 1369T859 1064Q859 963 807 876T670 747Q876 671 876 406Q876 211 768 96T484
-20Q311 -20 205 89T98 384H275Q275 268 331 200T484 131Q583 131 641 198T700 402Q700 667 449 667H343V818Z" />
<glyph unicode="4" horiz-adv-x="1011" d="M787 489H949V338H787V0H610V338H60V447L601 1456H787V489ZM256 489H610V1181L256 489Z" />
<glyph unicode="5" horiz-adv-x="1011" d="M189 730L252 1456H885V1285H401L367 888Q457 951 561 951Q731 951 828 819T925 464Q925 238 820 109T530 -20Q366 -20 263 87T145 383H311Q326 258 382 195T530 131Q633 131 691 220T749 462Q749 605 687 695T518 785Q430
785 377 739L330 692L189 730Z" />
<glyph unicode="6" horiz-adv-x="1011" d="M733 1457V1300H704Q527 1296 427 1181T312 833Q409 955 560 955Q721 955 815 823T910 475Q910 246 806 113T525 -20Q348 -20 240 137T132 554V625Q132 925 197 1103T388 1367T703 1457H733ZM530 801Q458 801 397 746T309
606V533Q309 356 371 245T525 133Q624 133 680 224T736 466Q736 614 680 707T530 801Z" />
<glyph unicode="7" horiz-adv-x="1011" d="M920 1352L419 0H234L734 1304H85V1456H920V1352Z" />
<glyph unicode="8" horiz-adv-x="1011" d="M866 1076Q866 967 818 882T687 749Q784 699 839 606T894 393Q894 205 788 93T505 -20T223 92T116 393Q116 513 170 607T319 750Q237 798 190 882T143 1076Q143 1260 242 1368T505 1476Q667 1476 766 1369T866 1076ZM717
397Q717 522 658 597T503 673Q405 673 349 597T292 397Q292 271 347 201T505 131T662 201T717 397ZM690 1073Q690 1184 638 1254T505 1324Q420 1324 370 1255T320 1073Q320 959 371 892T505 825Q590 825 640 893T690 1073Z" />
<glyph unicode="9" horiz-adv-x="1011" d="M699 622Q593 487 451 487Q292 487 198 621T104 972Q104 1200 206 1338T486 1476Q670 1476 773 1317T877 875V820Q877 578 841 428T733 186T552 47T277 -1V155H308Q496 159 593 269T699 622ZM481 640Q545 640 606 693T701
834V912Q701 1093 638 1207T486 1322Q390 1322 334 1228T277 982T332 736T481 640Z" />
<glyph unicode=":" horiz-adv-x="478" d="M394 97Q394 145 422 177T508 209T594 177T624 97Q624 51 595 20T508 -11T423 20T394 97ZM139 980Q139 1028 167 1060T253 1092T339 1060T369 980Q369 934 340 903T253 872T168 903T139 980Z" />
<glyph unicode=";" horiz-adv-x="415" d="M115 980Q115 1028 143 1060T229 1092T315 1060T345 980Q345 934 316 903T229 872T144 903T115 980ZM148 -290L43 -218Q137 -87 141 52V219H322V74Q322 -27 273 -128T148 -290Z" />
<glyph unicode="&lt;" horiz-adv-x="913" d="M253 644L763 391V195L79 574V720L763 1098V902L253 644Z" />
<glyph unicode="=" horiz-adv-x="981" d="M849 814H148V975H849V814ZM849 399H148V559H849V399Z" />
<glyph unicode="&gt;" horiz-adv-x="942" d="M678 651L136 909V1099L856 721V575L136 196V388L678 651Z" />
<glyph unicode="?" horiz-adv-x="864" d="M314 410Q314 530 339 605T461 796L531 886Q601 984 601 1090Q601 1195 558 1254T433 1314Q357 1314 307 1260T256 1115H80Q82 1280 180 1378T433 1476Q594 1476 686 1375T778 1096Q778 926 639 755L547 644Q490 563 490
410H314ZM410 199Q460 199 485 169T511 93T486 19T410 -11Q359 -11 335 18T310 93T334 168T410 199Z" />
<glyph unicode="@" horiz-adv-x="1575" d="M1474 502Q1466 267 1375 124T1124 -20Q969 -20 921 139Q876 59 821 20T708 -20Q586 -20 525 96T480 417Q492 580 543 710T675 915T842 989Q913 989 968 967T1091 883L1046 329Q1030 98 1145 98Q1234 98 1290 206T1354
502Q1369 893 1234 1096T826 1299Q658 1299 532 1200T334 913T253 478Q239 99 376 -114T772 -328Q849 -328 925 -306T1051 -249L1084 -364Q1031 -403 945 -428T769 -453Q560 -453 409 -341T182 -18T116 478Q125 753 218 973T471 1312T830 1431Q1036 1431 1186 1319T1410
997T1474 502ZM630 417Q619 275 652 199T754 123Q798 123 838 171T906 309L908 329L947 838Q903 861 858 861Q765 861 704 741T630 417Z" />
<glyph unicode="A" horiz-adv-x="1180" d="M836 380H344L231 0H43L512 1456H669L1139 0H951L836 380ZM392 538H789L590 1200L392 538Z" />
<glyph unicode="B" horiz-adv-x="1117" d="M157 0V1456H572Q771 1456 871 1359T972 1068Q972 966 921 888T783 767Q883 737 941 644T1000 420Q1000 224 893 112T586 0H157ZM340 681V157H590Q694 157 755 225T816 418Q816 681 594 681H340ZM340 835H575Q670 835
728 899T787 1069Q787 1189 734 1243T572 1298H340V835Z" />
<glyph unicode="C" horiz-adv-x="1161" d="M1070 462Q1058 228 939 104T601 -20Q382 -20 253 146T124 598V862Q124 1146 256 1311T618 1476Q829 1476 944 1350T1070 988H885Q873 1166 810 1242T618 1318Q469 1318 389 1202T309 860V593Q309 372 383 254T601 136T807
207T885 462H1070Z" />
<glyph unicode="D" horiz-adv-x="1169" d="M157 0V1456H504Q759 1456 900 1297T1041 848V604Q1041 315 898 158T483 0H157ZM340 1298V157H487Q680 157 769 267T860 595V853Q860 1083 772 1190T504 1298H340Z" />
<glyph unicode="E" horiz-adv-x="1017" d="M855 673H340V157H940V0H157V1456H930V1298H340V830H855V673Z" />
<glyph unicode="F" horiz-adv-x="984" d="M832 643H340V0H157V1456H915V1298H340V800H832V643Z" />
<glyph unicode="G" horiz-adv-x="1210" d="M1068 181L1036 141Q898 -20 632 -20Q396 -20 262 136T124 579V865Q124 1171 246 1323T613 1476Q821 1476 938 1360T1068 1029H885Q874 1165 810 1241T614 1318Q457 1318 384 1216T308 888V591Q308 371 392 254T633 136Q781
136 858 208L885 233V569H619V725H1068V181Z" />
<glyph unicode="H" horiz-adv-x="1270" d="M1110 0H926V673H340V0H157V1456H340V830H926V1456H1110V0Z" />
<glyph unicode="I" horiz-adv-x="512" d="M348 0H165V1456H348V0Z" />
<glyph unicode="J" horiz-adv-x="990" d="M659 1456H843V425Q843 216 737 98T450 -20Q265 -20 162 92T59 402H242Q242 277 297 207T450 137Q545 137 602 213T659 426V1456Z" />
<glyph unicode="K" horiz-adv-x="1116" d="M483 671L340 498V0H157V1456H340V753L460 912L852 1456H1072L599 815L1109 0H890L483 671Z" />
<glyph unicode="L" horiz-adv-x="973" d="M341 157H912V0H157V1456H341V157Z" />
<glyph unicode="M" horiz-adv-x="1547" d="M393 1456L773 268L1153 1456H1389V0H1206V567L1223 1135L842 0H702L323 1131L340 567V0H157V1456H393Z" />
<glyph unicode="N" horiz-adv-x="1268" d="M1108 0H924L341 1122V0H157V1456H341L926 329V1456H1108V0Z" />
<glyph unicode="O" horiz-adv-x="1230" d="M1104 600Q1104 302 977 141T616 -20Q391 -20 261 136T125 579V853Q125 1145 254 1310T614 1476Q844 1476 972 1318T1104 865V600ZM921 855Q921 1086 846 1198T614 1311Q463 1311 386 1197T307 861V600Q307 377 384 260T616
143T844 251T921 582V855Z" />
<glyph unicode="P" horiz-adv-x="1135" d="M340 570V0H157V1456H621Q824 1456 940 1335T1056 1011Q1056 801 946 688T634 570H340ZM340 727H621Q743 727 808 800T873 1009Q873 1140 806 1219T622 1298H340V727Z" />
<glyph unicode="Q" horiz-adv-x="1230" d="M1096 601Q1096 409 1045 277T898 70L1115 -125L991 -246L729 -7Q666 -20 607 -20Q380 -20 250 139T116 588V853Q116 1147 245 1311T605 1476Q838 1476 966 1316T1096 861V601ZM913 855Q913 1086 838 1198T605 1311Q455
1311 378 1197T299 861V601Q299 377 376 260T607 143Q759 143 834 249T913 576V855Z" />
<glyph unicode="R" horiz-adv-x="1087" d="M597 589H341V0H157V1456H565Q779 1456 889 1345T999 1018Q999 883 940 783T771 631L1053 12V0H856L597 589ZM341 746H563Q678 746 746 820T815 1018Q815 1298 561 1298H341V746Z" />
<glyph unicode="S" horiz-adv-x="1061" d="M793 368Q793 477 734 535T521 648T286 763T164 901T123 1079Q123 1252 238 1364T541 1476Q669 1476 769 1419T923 1259T977 1035H793Q793 1170 728 1244T541 1318Q430 1318 369 1256T308 1082Q308 990 374 928T578 817Q793
746 885 642T978 370Q978 193 863 87T550 -20Q423 -20 316 35T147 191T85 422H269Q269 287 344 212T550 137Q671 137 732 199T793 368Z" />
<glyph unicode="T" horiz-adv-x="1066" d="M1008 1298H625V0H442V1298H60V1456H1008V1298Z" />
<glyph unicode="U" horiz-adv-x="1150" d="M1025 1456V421Q1023 214 905 97T576 -20Q360 -20 246 94T130 421V1456H312V428Q312 281 374 209T576 136Q716 136 778 208T841 428V1456H1025Z" />
<glyph unicode="V" horiz-adv-x="1147" d="M573 281L906 1456H1107L654 0H494L42 1456H242L573 281Z" />
<glyph unicode="W" horiz-adv-x="1560" d="M435 459L454 296L483 440L716 1456H869L1095 440L1124 292L1145 460L1323 1456H1506L1216 0H1051L808 1061L793 1147L778 1061L526 0H360L71 1456H254L435 459Z" />
<glyph unicode="X" horiz-adv-x="1128" d="M566 898L840 1456H1055L676 734L1063 0H846L566 568L285 0H68L457 734L76 1456H290L566 898Z" />
<glyph unicode="Y" horiz-adv-x="1074" d="M536 725L834 1456H1041L627 543V0H444V543L30 1456H238L536 725Z" />
<glyph unicode="Z" horiz-adv-x="1070" d="M294 157H985V0H91V144L754 1298H98V1456H958V1315L294 157Z" />
<glyph unicode="[" horiz-adv-x="513" d="M469 1512H314V-160H469V-312H137V1664H469V1512Z" />
<glyph unicode="\" horiz-adv-x="756" d="M51 1456H218L728 -125H562L51 1456Z" />
<glyph unicode="]" horiz-adv-x="513" d="M30 1664H363V-312H30V-160H187V1512H30V1664Z" />
<glyph unicode="^" horiz-adv-x="760" d="M379 1211L232 729H69L321 1456H439L689 729H528L379 1211Z" />
<glyph unicode="_" horiz-adv-x="829" d="M805 -151H24V0H805V-151Z" />
<glyph unicode="`" horiz-adv-x="633" d="M474 1242H315L57 1536H280L474 1242Z" />
<glyph unicode="a" horiz-adv-x="981" d="M689 0Q673 35 666 118Q572 -20 426 -20Q279 -20 197 62T114 295Q114 460 226 557T533 656H663V771Q663 868 620 909T489 950Q409 950 359 903T309 782H132Q132 865 181 940T313 1059T498 1102Q664 1102 750 1020T839
779V233Q840 108 873 16V0H689ZM453 141Q518 141 577 177T663 267V525H563Q437 523 364 469T291 316Q291 224 328 183T453 141Z" />
<glyph unicode="b" horiz-adv-x="1010" d="M916 489Q916 236 825 108T561 -20Q389 -20 303 128L294 0H133V1536H309V963Q396 1102 559 1102Q737 1102 826 976T916 596V489ZM740 590Q740 782 687 863T513 945Q376 945 309 797V282Q375 136 515 136Q635 136 687
220T740 481V590Z" />
<glyph unicode="c" horiz-adv-x="946" d="M508 131Q596 131 649 185T707 341H874Q868 185 764 83T508 -20Q307 -20 202 106T96 483V602Q96 847 201 974T507 1102Q673 1102 770 997T874 710H707Q701 830 650 890T507 950Q389 950 332 873T273 618V480Q273 289 329
210T508 131Z" />
<glyph unicode="d" horiz-adv-x="1016" d="M95 590Q95 840 188 971T457 1102Q612 1102 699 976V1536H876V0H714L705 116Q618 -20 456 -20Q288 -20 193 110T95 479V590ZM272 489Q272 307 326 222T502 136Q634 136 699 269V815Q631 945 503 945Q381 945 327 860T272
597V489Z" />
<glyph unicode="e" horiz-adv-x="959" d="M519 -20Q317 -20 209 100T99 454V585Q99 827 204 964T499 1102Q689 1102 783 981T879 604V488H275V463Q275 289 340 210T529 131Q607 131 666 160T778 254L870 142Q755 -20 519 -20ZM499 950Q389 950 336 875T276 640H702V664Q695
818 647 884T499 950Z" />
<glyph unicode="f" horiz-adv-x="648" d="M210 0V939H69V1082H210V1207Q213 1372 293 1464T521 1557Q574 1557 628 1540L619 1390Q581 1399 538 1399Q387 1399 387 1184V1082H572V939H387V0H210Z" />
<glyph unicode="g" horiz-adv-x="1009" d="M97 590Q97 843 189 972T458 1102Q623 1102 709 961L718 1082H878V-10Q878 -211 775 -318T488 -426Q408 -426 309 -387T159 -289L231 -167Q341 -275 474 -275Q695 -275 701 -34V107Q615 -20 457 -20Q289 -20 195 106T97
470V590ZM274 489Q274 307 327 222T503 136Q635 136 701 271V812Q632 945 505 945Q383 945 329 860T274 597V489Z" />
<glyph unicode="h" horiz-adv-x="989" d="M309 971Q410 1102 567 1102Q854 1102 858 719V0H682V711Q682 838 640 891T512 945Q446 945 394 901T309 786V0H132V1536H309V971Z" />
<glyph unicode="i" horiz-adv-x="469" d="M323 0H146V1082H323V0ZM337 1369Q337 1324 312 1294T236 1264Q186 1264 161 1294T136 1369T161 1445T236 1476T311 1445T337 1369Z" />
<glyph unicode="j" horiz-adv-x="458" d="M313 1082V-136Q310 -437 75 -437Q21 -437 -22 -419L-23 -271Q4 -279 46 -279Q91 -279 113 -246T136 -129V1082H313ZM321 1369Q321 1324 296 1294T220 1264Q170 1264 146 1294T121 1369T145 1445T220 1476T295 1445T321 1369Z" />
<glyph unicode="k" horiz-adv-x="923" d="M404 495L310 387V0H133V1536H310V617L647 1082H859L515 630L904 0H698L404 495Z" />
<glyph unicode="l" horiz-adv-x="469" d="M323 0H146V1536H323V0Z" />
<glyph unicode="m" horiz-adv-x="1541" d="M299 1082L303 982Q402 1102 564 1102Q745 1102 817 945Q919 1102 1101 1102Q1400 1102 1407 729V0H1231V712Q1231 830 1189 887T1047 945Q967 945 917 883T859 725V0H681V720Q678 945 498 945Q364 945 309 811V0H133V1082H299Z" />
<glyph unicode="n" horiz-adv-x="991" d="M299 1082L304 965Q407 1102 567 1102Q854 1102 858 719V0H682V711Q682 838 640 891T512 945Q446 945 394 901T309 786V0H132V1082H299Z" />
<glyph unicode="o" horiz-adv-x="1028" d="M95 591Q95 827 209 964T512 1102T814 968T932 603V489Q932 254 818 117T514 -20Q326 -20 213 113T95 473V591ZM272 489Q272 322 337 227T514 131Q748 131 755 469V591Q755 757 689 853T512 950Q403 950 338 854T272 592V489Z" />
<glyph unicode="p" horiz-adv-x="1010" d="M914 489Q914 232 822 106T560 -20Q397 -20 309 103V-416H133V1082H293L302 962Q391 1102 557 1102Q735 1102 823 978T914 607V489ZM738 590Q738 772 682 858T502 945Q375 945 309 818V255Q374 131 504 131Q624 131 680
217T738 482V590Z" />
<glyph unicode="q" horiz-adv-x="1025" d="M95 590Q95 843 187 972T461 1102Q618 1102 705 976L713 1082H875V-416H698V95Q612 -20 460 -20Q285 -20 191 107T95 479V590ZM272 489Q272 307 328 219T506 131Q630 131 698 250V830Q626 950 507 950Q385 950 329 862T272
597V489Z" />
<glyph unicode="r" horiz-adv-x="623" d="M579 916Q542 923 499 923Q363 923 309 774V0H132V1082H304L307 972Q378 1102 508 1102Q550 1102 578 1088L579 916Z" />
<glyph unicode="s" horiz-adv-x="933" d="M658 277Q658 334 615 375T449 471Q306 530 248 572T160 667T131 795Q131 927 227 1014T474 1102Q632 1102 728 1010T824 774H648Q648 847 599 898T474 950Q396 950 352 910T307 801Q307 747 339 714T496 627Q693 550
764 477T835 290Q835 149 738 65T478 -20Q309 -20 204 77T99 323H277Q280 233 332 182T478 131Q566 131 612 170T658 277Z" />
<glyph unicode="t" horiz-adv-x="605" d="M364 1344V1082H527V939H364V268Q364 204 385 171T457 138Q492 138 528 150L526 0Q466 -20 403 -20Q298 -20 243 55T188 267V939H23V1082H188V1344H364Z" />
<glyph unicode="u" horiz-adv-x="990" d="M684 95Q596 -20 427 -20Q280 -20 205 81T129 377V1082H305V390Q305 137 457 137Q618 137 679 281V1082H856V0H688L684 95Z" />
<glyph unicode="v" horiz-adv-x="876" d="M439 269L644 1082H824L503 0H371L46 1082H226L439 269Z" />
<glyph unicode="w" horiz-adv-x="1331" d="M939 311L1103 1082H1278L1013 0H872L661 774L455 0H313L50 1082H224L392 330L593 1082H733L939 311Z" />
<glyph unicode="x" horiz-adv-x="899" d="M445 687L630 1082H835L541 547L842 0H639L448 405L256 0H52L353 547L60 1082H263L445 687Z" />
<glyph unicode="y" horiz-adv-x="853" d="M428 294L625 1082H813L459 -153Q419 -292 346 -364T180 -437Q144 -437 88 -421V-271L127 -275Q204 -275 247 -239T318 -112L353 9L35 1082H228L428 294Z" />
<glyph unicode="z" horiz-adv-x="899" d="M296 151H818V0H94V136L590 929H98V1082H798V951L296 151Z" />
<glyph unicode="{" horiz-adv-x="627" d="M549 -366Q398 -316 322 -203T244 95V302Q244 543 72 543V688Q244 688 244 929V1135Q245 1319 320 1432T549 1597L585 1482Q425 1419 421 1147V931Q421 705 274 615Q421 525 421 298V79Q426 -189 584 -251L549 -366Z" />
<glyph unicode="|" horiz-adv-x="499" d="M324 -270H175V1456H324V-270Z" />
<glyph unicode="}" horiz-adv-x="627" d="M39 -251Q199 -188 204 80V301Q204 532 363 615Q204 697 204 933V1140Q202 1418 39 1482L75 1597Q225 1548 300 1438T380 1149V913Q385 688 552 688V543Q380 543 380 302V98Q380 -266 75 -366L39 -251Z" />
<glyph unicode="~" horiz-adv-x="1207" d="M1084 777Q1084 622 1003 512T803 402Q739 402 681 432T552 541Q512 588 478 613T406 639Q344 639 311 586T278 438L125 436Q125 594 205 698T406 802Q478 802 536 766T656 663Q697 613 730 589T803 565Q862 565 901
623T940 776L1084 777Z" />
<glyph unicode="&#xa0;" horiz-adv-x="469" />
<glyph unicode="&#xa1;" horiz-adv-x="474" d="M161 684H321L334 -360H148L161 684ZM237 889Q186 889 161 920T136 996T161 1071T237 1101Q287 1101 312 1071T338 996T313 920T237 889Z" />
<glyph unicode="&#xa2;" horiz-adv-x="982" d="M514 131Q592 131 650 191T714 341H881Q875 216 793 117T592 -11V-245H416V-8Q269 27 187 167T104 525V562Q104 769 186 911T416 1090V1318H592V1094Q718 1069 796 965T881 710H714Q708 815 653 882T514 950Q401
950 341 851T280 555V520Q280 329 340 230T514 131Z" />
<glyph unicode="&#xa3;" horiz-adv-x="1046" d="M411 622L418 402Q416 249 363 157H978L977 0H99V157H157Q191 167 212 234T233 401L227 622H96V779H222L215 1039Q215 1237 321 1356T601 1476Q762 1476 857 1371T953 1087H771Q771 1197 720 1257T584 1318Q502
1318 451 1240T399 1039L407 779H667V622H411Z" />
<glyph unicode="&#xa4;" horiz-adv-x="1460" d="M1103 112Q944 -20 735 -20Q528 -20 369 110L235 -26L105 109L244 250Q140 406 140 608Q140 814 252 977L105 1128L235 1264L382 1114Q540 1234 735 1234Q931 1234 1090 1113L1239 1265L1371 1128L1220 974Q1330
811 1330 608Q1330 412 1228 253L1371 109L1239 -27L1103 112ZM311 608Q311 485 368 379T524 212T735 151T946 212T1100 379T1157 608Q1157 730 1101 835T946 1001T735 1062Q622 1062 524 1002T369 836T311 608Z" />
<glyph unicode="&#xa5;" horiz-adv-x="949" d="M476 832L717 1456H920L615 736H824V611H563V446H824V322H563V0H379V322H123V446H379V611H123V736H335L30 1456H236L476 832Z" />
<glyph unicode="&#xa6;" horiz-adv-x="491" d="M147 -270V521H333V-270H147ZM333 698H147V1456H333V698Z" />
<glyph unicode="&#xa7;" horiz-adv-x="1100" d="M990 431Q990 241 832 157Q891 108 921 40T952 -128Q952 -297 841 -396T536 -495Q330 -495 211 -383T92 -64L269 -62Q269 -193 340 -268T536 -343Q644 -343 709 -284T775 -130Q775 -41 717 11T486 126Q267 195 182
293T97 551Q97 644 137 713T251 824Q134 925 134 1110Q134 1276 248 1376T551 1476Q749 1476 859 1363T970 1045H794Q794 1169 728 1247T551 1325T376 1268T312 1112Q312 1012 367 963T594 855T840 744T953 615T990 431ZM528 691Q443 718 390 741Q274 702 274 553Q274
452 328 401T556 289Q644 260 690 239Q750 261 781 310T813 428Q813 517 757 571T528 691Z" />
<glyph unicode="&#xa8;" horiz-adv-x="856" d="M101 1371Q101 1416 128 1446T210 1477T292 1447T320 1371T292 1296T210 1266T129 1296T101 1371ZM531 1369Q531 1414 558 1445T640 1476T722 1445T750 1369T722 1294T640 1264T559 1294T531 1369Z" />
<glyph unicode="&#xa9;" horiz-adv-x="1609" d="M1119 597Q1119 444 1033 364T788 283Q631 283 537 388T442 676V786Q442 962 537 1067T788 1173Q948 1173 1034 1091T1120 860H974Q974 959 927 1001T788 1044Q694 1044 640 975T586 783V670Q586 550 640 481T788
412Q880 412 926 454T973 597H1119ZM206 729Q206 557 286 411T503 181T801 98T1098 181T1315 410T1395 729Q1395 899 1316 1044T1100 1272T801 1356Q641 1356 503 1274T286 1045T206 729ZM91 729Q91 931 184 1104T443 1376T801 1476T1158 1377T1416 1104T1510 729Q1510
532 1420 360T1165 84T801 -21Q604 -21 439 82T182 358T91 729Z" />
<glyph unicode="&#xaa;" horiz-adv-x="811" d="M529 705L515 773Q452 691 349 691Q248 691 194 753T140 918Q140 1145 419 1149H509V1201Q509 1336 417 1336Q365 1336 336 1309T307 1231L154 1243Q154 1347 227 1411T417 1476Q531 1476 597 1405T663 1200V886Q663
790 685 705H529ZM388 828Q453 828 509 889V1037H439Q294 1037 294 922Q294 828 388 828Z" />
<glyph unicode="&#xab;" horiz-adv-x="856" d="M521 804L732 407H603L355 795V814L603 1203H732L521 804ZM549 548L760 151H631L383 539V558L631 947H760L549 548Z" />
<glyph unicode="&#xac;" horiz-adv-x="998" d="M832 375H654V639H127V800H832V375Z" />
<glyph unicode="&#xad;" horiz-adv-x="508" d="M460 543H47V694H460V543Z" />
<glyph unicode="&#xae;" horiz-adv-x="1610" d="M90 729Q90 931 183 1104T442 1376T800 1476T1157 1377T1415 1104T1509 729Q1509 532 1419 360T1164 84T800 -21Q603 -21 438 82T181 358T90 729ZM205 729Q205 557 285 411T502 181T800 98Q961 98 1099 182T1315
412T1394 729Q1394 900 1316 1044T1099 1272T800 1356Q640 1356 502 1274T285 1045T205 729ZM653 654V316H512V1165H788Q941 1165 1025 1100T1110 909Q1110 786 982 721Q1104 671 1105 517V456Q1105 370 1122 332V316H977Q963 352 963 444T960 554Q944 650 829
654H653ZM653 782H809Q881 784 925 817T969 904Q969 977 930 1007T791 1038H653V782Z" />
<glyph unicode="&#xaf;" horiz-adv-x="848" d="M722 1302H141V1445H722V1302Z" />
<glyph unicode="&#xb0;" horiz-adv-x="765" d="M130 1216Q130 1320 204 1398T385 1476Q489 1476 562 1399T636 1216Q636 1110 563 1035T385 960Q280 960 205 1035T130 1216ZM385 1088Q439 1088 476 1123T513 1216Q513 1274 476 1311T385 1349Q330 1349 293 1310T255
1216T292 1125T385 1088Z" />
<glyph unicode="&#xb1;" horiz-adv-x="962" d="M578 854H875V703H578V289H420V703H105V854H420V1267H578V854ZM837 0H135V152H837V0Z" />
<glyph unicode="&#xb2;" horiz-adv-x="675" d="M599 667H87V775L343 1063Q425 1160 425 1228Q425 1277 401 1307T332 1338Q274 1338 248 1300T221 1205H72Q72 1319 143 1393T328 1467Q444 1467 509 1404T574 1230Q574 1123 477 1011L276 795H599V667Z" />
<glyph unicode="&#xb3;" horiz-adv-x="675" d="M242 1126H308Q425 1126 425 1235Q425 1279 401 1308T324 1338Q282 1338 254 1314T226 1246H77Q77 1343 146 1405T322 1467Q440 1467 507 1407T574 1242Q574 1187 545 1142T459 1071Q584 1031 584 887Q584 779 510
718T321 656Q207 656 138 719T69 889H219Q219 844 247 814T327 784Q381 784 408 814T436 895Q436 1009 317 1010H242V1126Z" />
<glyph unicode="&#xb4;" horiz-adv-x="642" d="M316 1536H540L272 1242H123L316 1536Z" />
<glyph unicode="&#xb5;" d="M323 1082V440Q325 281 364 206T494 130Q641 130 696 264V1082H874V0H715L707 102Q633 -20 501 -20Q386 -20 323 47V-416H147V1082H323Z" />
<glyph unicode="&#xb6;" horiz-adv-x="890" d="M551 0V520H482Q357 520 264 578T121 743T71 988Q71 1201 183 1328T486 1456H729V0H551Z" />
<glyph unicode="&#xb7;" horiz-adv-x="498" d="M138 729Q138 777 164 809T244 841T324 809T351 729Q351 682 324 651T244 619T165 650T138 729Z" />
<glyph unicode="&#xb8;" horiz-adv-x="469" d="M272 0L262 -52Q322 -65 354 -110T386 -225Q386 -321 320 -378T129 -435L123 -328Q251 -328 251 -229Q251 -184 225 -164T119 -134L147 0H272Z" />
<glyph unicode="&#xb9;" horiz-adv-x="675" d="M446 667H297V1268L121 1211V1339L429 1456H446V667Z" />
<glyph unicode="&#xba;" horiz-adv-x="825" d="M118 1123Q118 1277 198 1376T412 1476T626 1378T706 1118V1043Q706 886 626 788T413 690Q278 690 198 789T118 1047V1123ZM273 1043Q273 942 311 886T413 829T514 886T551 1046V1123Q551 1222 514 1279T412 1336Q349
1336 312 1281T273 1126V1043Z" />
<glyph unicode="&#xbb;" horiz-adv-x="856" d="M232 949L480 560V541L232 152H101L312 550L101 949H232ZM535 949L783 560V541L535 152H404L615 550L404 949H535Z" />
<glyph unicode="&#xbc;" horiz-adv-x="1305" d="M407 664H258V1265L82 1208V1336L390 1453H407V664ZM401 118L305 184L902 1322L999 1256L401 118ZM1142 299H1226V169H1142V0H994V169H686L681 271L991 789H1142V299ZM827 299H994V578L984 560L827 299Z" />
<glyph unicode="&#xbd;" horiz-adv-x="1388" d="M364 118L268 184L865 1322L962 1256L364 118ZM406 664H257V1265L81 1208V1336L389 1453H406V664ZM1278 0H766V108L1022 396Q1104 493 1104 561Q1104 610 1080 640T1011 671Q953 671 927 633T900 538H751Q751 652
822 726T1007 800Q1123 800 1188 737T1253 563Q1253 456 1156 344L955 128H1278V0Z" />
<glyph unicode="&#xbe;" horiz-adv-x="1379" d="M502 118L406 184L1003 1322L1100 1256L502 118ZM1211 299H1295V169H1211V0H1063V169H755L750 271L1060 789H1211V299ZM896 299H1063V578L1053 560L896 299ZM284 1126H350Q467 1126 467 1235Q467 1279 443 1308T366
1338Q324 1338 296 1314T268 1246H119Q119 1343 188 1405T364 1467Q482 1467 549 1407T616 1242Q616 1187 587 1142T501 1071Q626 1031 626 887Q626 779 552 718T363 656Q249 656 180 719T111 889H261Q261 844 289 814T369 784Q423 784 450 814T478 895Q478 1009
359 1010H284V1126Z" />
<glyph unicode="&#xbf;" horiz-adv-x="863" d="M526 680Q525 577 507 513T445 388L377 298L322 223Q247 118 247 0Q247 -109 292 -166T424 -224Q498 -224 549 -168T601 -20H777Q775 -184 677 -284T424 -385Q257 -385 164 -286T71 -5Q71 164 205 342L291 452Q349
536 349 680H526ZM530 997Q530 952 505 921T430 890T355 921T329 997Q329 1041 354 1071T430 1101T505 1071T530 997Z" />
<glyph unicode="&#xc0;" horiz-adv-x="1180" d="M836 380H344L231 0H43L512 1456H669L1139 0H951L836 380ZM392 538H789L590 1200L392 538ZM700 1552H541L283 1846H506L700 1552Z" />
<glyph unicode="&#xc1;" horiz-adv-x="1180" d="M836 380H344L231 0H43L512 1456H669L1139 0H951L836 380ZM392 538H789L590 1200L392 538ZM685 1846H909L641 1552H492L685 1846Z" />
<glyph unicode="&#xc2;" horiz-adv-x="1180" d="M836 380H344L231 0H43L512 1456H669L1139 0H951L836 380ZM392 538H789L590 1200L392 538ZM856 1572V1562H714L594 1732L474 1562H332V1574L541 1846H646L856 1572Z" />
<glyph unicode="&#xc3;" horiz-adv-x="1180" d="M836 380H344L231 0H43L512 1456H669L1139 0H951L836 380ZM392 538H789L590 1200L392 538ZM896 1814Q896 1709 844 1641T710 1572Q675 1572 650 1582T585 1623T527 1660T486 1667Q452 1667 430 1635T407 1555L292
1562Q292 1671 345 1740T477 1809Q507 1809 531 1798T591 1760T651 1724T701 1713Q735 1713 758 1745T781 1826L896 1814Z" />
<glyph unicode="&#xc4;" horiz-adv-x="1180" d="M836 380H344L231 0H43L512 1456H669L1139 0H951L836 380ZM392 538H789L590 1200L392 538ZM272 1681Q272 1726 299 1756T381 1787T463 1757T491 1681T463 1606T381 1576T300 1606T272 1681ZM702 1679Q702 1724 729
1755T811 1786T893 1755T921 1679T893 1604T811 1574T730 1604T702 1679Z" />
<glyph unicode="&#xc5;" horiz-adv-x="1180" d="M836 380H344L231 0H43L512 1456H669L1139 0H951L836 380ZM392 538H789L590 1200L392 538ZM809 1729Q809 1642 747 1584T594 1525Q502 1525 441 1584T379 1729T440 1876T594 1937T747 1876T809 1729ZM478 1729Q478
1682 511 1648T594 1614Q642 1614 676 1647T710 1729T677 1812T594 1847Q544 1847 511 1812T478 1729Z" />
<glyph unicode="&#xc6;" horiz-adv-x="1663" d="M1616 0H853L840 353H382L214 0H-2L737 1456H1564V1304H984L1001 833H1496V682H1006L1025 151H1616V0ZM465 527H834L809 1250L465 527Z" />
<glyph unicode="&#xc7;" horiz-adv-x="1161" d="M1070 462Q1058 228 939 104T601 -20Q382 -20 253 146T124 598V862Q124 1146 256 1311T618 1476Q829 1476 944 1350T1070 988H885Q873 1166 810 1242T618 1318Q469 1318 389 1202T309 860V593Q309 372 383 254T601
136T807 207T885 462H1070ZM659 -9L649 -61Q709 -74 741 -119T773 -234Q773 -330 707 -387T516 -444L510 -337Q638 -337 638 -238Q638 -193 612 -173T506 -143L534 -9H659Z" />
<glyph unicode="&#xc8;" horiz-adv-x="1017" d="M855 673H340V157H940V0H157V1456H930V1298H340V830H855V673ZM646 1564H487L229 1858H452L646 1564Z" />
<glyph unicode="&#xc9;" horiz-adv-x="1017" d="M855 673H340V157H940V0H157V1456H930V1298H340V830H855V673ZM631 1858H855L587 1564H438L631 1858Z" />
<glyph unicode="&#xca;" horiz-adv-x="1017" d="M855 673H340V157H940V0H157V1456H930V1298H340V830H855V673ZM802 1584V1574H660L540 1744L420 1574H278V1586L487 1858H592L802 1584Z" />
<glyph unicode="&#xcb;" horiz-adv-x="1017" d="M855 673H340V157H940V0H157V1456H930V1298H340V830H855V673ZM218 1693Q218 1738 245 1768T327 1799T409 1769T437 1693T409 1618T327 1588T246 1618T218 1693ZM648 1691Q648 1736 675 1767T757 1798T839 1767T867
1691T839 1616T757 1586T676 1616T648 1691Z" />
<glyph unicode="&#xcc;" horiz-adv-x="512" d="M348 0H165V1456H348V0ZM362 1564H203L-55 1858H168L362 1564Z" />
<glyph unicode="&#xcd;" horiz-adv-x="512" d="M348 0H165V1456H348V0ZM346 1858H570L302 1564H153L346 1858Z" />
<glyph unicode="&#xce;" horiz-adv-x="512" d="M348 0H165V1456H348V0ZM518 1584V1574H376L256 1744L136 1574H-6V1586L203 1858H308L518 1584Z" />
<glyph unicode="&#xcf;" horiz-adv-x="512" d="M348 0H165V1456H348V0ZM-66 1693Q-66 1738 -39 1768T43 1799T125 1769T153 1693T125 1618T43 1588T-38 1618T-66 1693ZM364 1691Q364 1736 391 1767T473 1798T555 1767T583 1691T555 1616T473 1586T392 1616T364 1691Z" />
<glyph unicode="&#xd0;" horiz-adv-x="1199" d="M187 0V666H18V817H187V1456H534Q789 1456 930 1297T1071 848V604Q1071 315 928 158T513 0H187ZM560 666H370V157H517Q710 157 799 267T890 595V853Q890 1083 802 1190T534 1298H370V817H560V666Z" />
<glyph unicode="&#xd1;" horiz-adv-x="1268" d="M1108 0H924L341 1122V0H157V1456H341L926 329V1456H1108V0ZM932 1814Q932 1709 880 1641T746 1572Q711 1572 686 1582T621 1623T563 1660T522 1667Q488 1667 466 1635T443 1555L328 1562Q328 1671 381 1740T513
1809Q543 1809 567 1798T627 1760T687 1724T737 1713Q771 1713 794 1745T817 1826L932 1814Z" />
<glyph unicode="&#xd2;" horiz-adv-x="1230" d="M1104 600Q1104 302 977 141T616 -20Q391 -20 261 136T125 579V853Q125 1145 254 1310T614 1476Q844 1476 972 1318T1104 865V600ZM921 855Q921 1086 846 1198T614 1311Q463 1311 386 1197T307 861V600Q307 377
384 260T616 143T844 251T921 582V855ZM724 1554H565L307 1848H530L724 1554Z" />
<glyph unicode="&#xd3;" horiz-adv-x="1230" d="M1104 600Q1104 302 977 141T616 -20Q391 -20 261 136T125 579V853Q125 1145 254 1310T614 1476Q844 1476 972 1318T1104 865V600ZM921 855Q921 1086 846 1198T614 1311Q463 1311 386 1197T307 861V600Q307 377
384 260T616 143T844 251T921 582V855ZM709 1848H933L665 1554H516L709 1848Z" />
<glyph unicode="&#xd4;" horiz-adv-x="1230" d="M1104 600Q1104 302 977 141T616 -20Q391 -20 261 136T125 579V853Q125 1145 254 1310T614 1476Q844 1476 972 1318T1104 865V600ZM921 855Q921 1086 846 1198T614 1311Q463 1311 386 1197T307 861V600Q307 377
384 260T616 143T844 251T921 582V855ZM880 1574V1564H738L618 1734L498 1564H356V1576L565 1848H670L880 1574Z" />
<glyph unicode="&#xd5;" horiz-adv-x="1230" d="M1104 600Q1104 302 977 141T616 -20Q391 -20 261 136T125 579V853Q125 1145 254 1310T614 1476Q844 1476 972 1318T1104 865V600ZM921 855Q921 1086 846 1198T614 1311Q463 1311 386 1197T307 861V600Q307 377
384 260T616 143T844 251T921 582V855ZM920 1816Q920 1711 868 1643T734 1574Q699 1574 674 1584T609 1625T551 1662T510 1669Q476 1669 454 1637T431 1557L316 1564Q316 1673 369 1742T501 1811Q531 1811 555 1800T615 1762T675 1726T725 1715Q759 1715 782 1747T805
1828L920 1816Z" />
<glyph unicode="&#xd6;" horiz-adv-x="1230" d="M1104 600Q1104 302 977 141T616 -20Q391 -20 261 136T125 579V853Q125 1145 254 1310T614 1476Q844 1476 972 1318T1104 865V600ZM921 855Q921 1086 846 1198T614 1311Q463 1311 386 1197T307 861V600Q307 377
384 260T616 143T844 251T921 582V855ZM296 1683Q296 1728 323 1758T405 1789T487 1759T515 1683T487 1608T405 1578T324 1608T296 1683ZM726 1681Q726 1726 753 1757T835 1788T917 1757T945 1681T917 1606T835 1576T754 1606T726 1681Z" />
<glyph unicode="&#xd7;" horiz-adv-x="964" d="M93 329L368 663L91 1000L204 1123L476 793L748 1123L860 1000L582 663L858 329L745 206L475 533L206 206L93 329Z" />
<glyph unicode="&#xd8;" horiz-adv-x="1230" d="M1112 681Q1112 358 978 169T616 -20Q476 -20 366 58L287 -93H156L278 140Q117 333 117 689V773Q117 981 178 1141T352 1388T614 1476Q793 1476 916 1357L1000 1516H1131L995 1258Q1108 1077 1112 792V681ZM299
681Q299 453 369 313L832 1195Q750 1311 614 1311Q466 1311 383 1167T299 773V681ZM930 775Q930 942 893 1063L445 209Q517 143 616 143Q766 143 848 281T930 681V775Z" />
<glyph unicode="&#xd9;" horiz-adv-x="1150" d="M1025 1456V421Q1023 214 905 97T576 -20Q360 -20 246 94T130 421V1456H312V428Q312 281 374 209T576 136Q716 136 778 208T841 428V1456H1025ZM681 1552H522L264 1846H487L681 1552Z" />
<glyph unicode="&#xda;" horiz-adv-x="1150" d="M1025 1456V421Q1023 214 905 97T576 -20Q360 -20 246 94T130 421V1456H312V428Q312 281 374 209T576 136Q716 136 778 208T841 428V1456H1025ZM666 1846H890L622 1552H473L666 1846Z" />
<glyph unicode="&#xdb;" horiz-adv-x="1150" d="M1025 1456V421Q1023 214 905 97T576 -20Q360 -20 246 94T130 421V1456H312V428Q312 281 374 209T576 136Q716 136 778 208T841 428V1456H1025ZM837 1572V1562H695L575 1732L455 1562H313V1574L522 1846H627L837 1572Z" />
<glyph unicode="&#xdc;" horiz-adv-x="1150" d="M1025 1456V421Q1023 214 905 97T576 -20Q360 -20 246 94T130 421V1456H312V428Q312 281 374 209T576 136Q716 136 778 208T841 428V1456H1025ZM253 1681Q253 1726 280 1756T362 1787T444 1757T472 1681T444 1606T362
1576T281 1606T253 1681ZM683 1679Q683 1724 710 1755T792 1786T874 1755T902 1679T874 1604T792 1574T711 1604T683 1679Z" />
<glyph unicode="&#xdd;" horiz-adv-x="1074" d="M536 725L834 1456H1041L627 543V0H444V543L30 1456H238L536 725ZM631 1846H855L587 1552H438L631 1846Z" />
<glyph unicode="&#xde;" horiz-adv-x="1055" d="M331 1456V1163H554Q745 1161 855 1045T965 738Q965 546 854 430T544 313H331V0H154V1456H331ZM331 1012V465H549Q661 465 724 540T788 736Q788 859 725 934T553 1011H332L331 1012Z" />
<glyph unicode="&#xdf;" horiz-adv-x="1069" d="M309 0H133V1111Q133 1320 224 1437T473 1554Q629 1554 714 1466T800 1216Q800 1091 746 990T691 819Q691 767 722 720T831 600T945 460T980 317Q980 152 895 66T654 -20Q588 -20 513 1T404 52L443 207Q476 179
533 155T635 131Q804 131 804 307Q804 360 773 409T665 528T551 669T514 821Q514 881 533 926T574 1013T616 1099T635 1201Q635 1301 592 1351T482 1402Q312 1402 309 1120V0Z" />
<glyph unicode="&#xe0;" horiz-adv-x="981" d="M689 0Q673 35 666 118Q572 -20 426 -20Q279 -20 197 62T114 295Q114 460 226 557T533 656H663V771Q663 868 620 909T489 950Q409 950 359 903T309 782H132Q132 865 181 940T313 1059T498 1102Q664 1102 750 1020T839
779V233Q840 108 873 16V0H689ZM453 141Q518 141 577 177T663 267V525H563Q437 523 364 469T291 316Q291 224 328 183T453 141ZM615 1242H456L198 1536H421L615 1242Z" />
<glyph unicode="&#xe1;" horiz-adv-x="981" d="M689 0Q673 35 666 118Q572 -20 426 -20Q279 -20 197 62T114 295Q114 460 226 557T533 656H663V771Q663 868 620 909T489 950Q409 950 359 903T309 782H132Q132 865 181 940T313 1059T498 1102Q664 1102 750 1020T839
779V233Q840 108 873 16V0H689ZM453 141Q518 141 577 177T663 267V525H563Q437 523 364 469T291 316Q291 224 328 183T453 141ZM600 1536H824L556 1242H407L600 1536Z" />
<glyph unicode="&#xe2;" horiz-adv-x="981" d="M689 0Q673 35 666 118Q572 -20 426 -20Q279 -20 197 62T114 295Q114 460 226 557T533 656H663V771Q663 868 620 909T489 950Q409 950 359 903T309 782H132Q132 865 181 940T313 1059T498 1102Q664 1102 750 1020T839
779V233Q840 108 873 16V0H689ZM453 141Q518 141 577 177T663 267V525H563Q437 523 364 469T291 316Q291 224 328 183T453 141ZM771 1262V1252H629L509 1422L389 1252H247V1264L456 1536H561L771 1262Z" />
<glyph unicode="&#xe3;" horiz-adv-x="981" d="M689 0Q673 35 666 118Q572 -20 426 -20Q279 -20 197 62T114 295Q114 460 226 557T533 656H663V771Q663 868 620 909T489 950Q409 950 359 903T309 782H132Q132 865 181 940T313 1059T498 1102Q664 1102 750 1020T839
779V233Q840 108 873 16V0H689ZM453 141Q518 141 577 177T663 267V525H563Q437 523 364 469T291 316Q291 224 328 183T453 141ZM811 1504Q811 1399 759 1331T625 1262Q590 1262 565 1272T500 1313T442 1350T401 1357Q367 1357 345 1325T322 1245L207 1252Q207 1361
260 1430T392 1499Q422 1499 446 1488T506 1450T566 1414T616 1403Q650 1403 673 1435T696 1516L811 1504Z" />
<glyph unicode="&#xe4;" horiz-adv-x="981" d="M689 0Q673 35 666 118Q572 -20 426 -20Q279 -20 197 62T114 295Q114 460 226 557T533 656H663V771Q663 868 620 909T489 950Q409 950 359 903T309 782H132Q132 865 181 940T313 1059T498 1102Q664 1102 750 1020T839
779V233Q840 108 873 16V0H689ZM453 141Q518 141 577 177T663 267V525H563Q437 523 364 469T291 316Q291 224 328 183T453 141ZM187 1371Q187 1416 214 1446T296 1477T378 1447T406 1371T378 1296T296 1266T215 1296T187 1371ZM617 1369Q617 1414 644 1445T726
1476T808 1445T836 1369T808 1294T726 1264T645 1294T617 1369Z" />
<glyph unicode="&#xe5;" horiz-adv-x="981" d="M689 0Q673 35 666 118Q572 -20 426 -20Q279 -20 197 62T114 295Q114 460 226 557T533 656H663V771Q663 868 620 909T489 950Q409 950 359 903T309 782H132Q132 865 181 940T313 1059T498 1102Q664 1102 750 1020T839
779V233Q840 108 873 16V0H689ZM453 141Q518 141 577 177T663 267V525H563Q437 523 364 469T291 316Q291 224 328 183T453 141ZM724 1419Q724 1332 662 1274T509 1215Q417 1215 356 1274T294 1419T355 1566T509 1627T662 1566T724 1419ZM393 1419Q393 1372 426
1338T509 1304Q557 1304 591 1337T625 1419T592 1502T509 1537Q459 1537 426 1502T393 1419Z" />
<glyph unicode="&#xe6;" horiz-adv-x="1491" d="M1079 -20Q859 -20 744 152Q688 70 592 25T381 -20Q242 -20 163 65T83 304Q83 461 179 548T462 635H639V720Q639 827 596 888T472 950Q391 950 337 896T282 759L107 778Q107 920 209 1011T472 1102Q670 1102 757
949Q868 1102 1038 1102Q1218 1102 1316 973T1415 611V497H813Q818 323 887 227T1079 130Q1205 130 1303 206L1342 237L1401 101Q1350 46 1264 13T1079 -20ZM417 130Q511 130 609 218L639 248V495H462Q371 494 316 440T260 300Q260 219 301 175T417 130ZM1038 950Q947
950 888 863T816 640H1239V671Q1239 806 1187 878T1038 950Z" />
<glyph unicode="&#xe7;" horiz-adv-x="946" d="M508 131Q596 131 649 185T707 341H874Q868 185 764 83T508 -20Q307 -20 202 106T96 483V602Q96 847 201 974T507 1102Q673 1102 770 997T874 710H707Q701 830 650 890T507 950Q389 950 332 873T273 618V480Q273
289 329 210T508 131ZM532 -9L522 -61Q582 -74 614 -119T646 -234Q646 -330 580 -387T389 -444L383 -337Q511 -337 511 -238Q511 -193 485 -173T379 -143L407 -9H532Z" />
<glyph unicode="&#xe8;" horiz-adv-x="959" d="M519 -20Q317 -20 209 100T99 454V585Q99 827 204 964T499 1102Q689 1102 783 981T879 604V488H275V463Q275 289 340 210T529 131Q607 131 666 160T778 254L870 142Q755 -20 519 -20ZM499 950Q389 950 336 875T276
640H702V664Q695 818 647 884T499 950ZM600 1242H441L183 1536H406L600 1242Z" />
<glyph unicode="&#xe9;" horiz-adv-x="959" d="M519 -20Q317 -20 209 100T99 454V585Q99 827 204 964T499 1102Q689 1102 783 981T879 604V488H275V463Q275 289 340 210T529 131Q607 131 666 160T778 254L870 142Q755 -20 519 -20ZM499 950Q389 950 336 875T276
640H702V664Q695 818 647 884T499 950ZM585 1536H809L541 1242H392L585 1536Z" />
<glyph unicode="&#xea;" horiz-adv-x="959" d="M519 -20Q317 -20 209 100T99 454V585Q99 827 204 964T499 1102Q689 1102 783 981T879 604V488H275V463Q275 289 340 210T529 131Q607 131 666 160T778 254L870 142Q755 -20 519 -20ZM499 950Q389 950 336 875T276
640H702V664Q695 818 647 884T499 950ZM756 1262V1252H614L494 1422L374 1252H232V1264L441 1536H546L756 1262Z" />
<glyph unicode="&#xeb;" horiz-adv-x="959" d="M519 -20Q317 -20 209 100T99 454V585Q99 827 204 964T499 1102Q689 1102 783 981T879 604V488H275V463Q275 289 340 210T529 131Q607 131 666 160T778 254L870 142Q755 -20 519 -20ZM499 950Q389 950 336 875T276
640H702V664Q695 818 647 884T499 950ZM172 1371Q172 1416 199 1446T281 1477T363 1447T391 1371T363 1296T281 1266T200 1296T172 1371ZM602 1369Q602 1414 629 1445T711 1476T793 1445T821 1369T793 1294T711 1264T630 1294T602 1369Z" />
<glyph unicode="&#xec;" horiz-adv-x="481" d="M323 0H146V1082H323V0ZM602 1497H443L185 1791H408L602 1497Z" />
<glyph unicode="&#xed;" horiz-adv-x="481" d="M323 0H146V1082H323V0ZM330 1791H554L286 1497H137L330 1791Z" />
<glyph unicode="&#xee;" horiz-adv-x="481" d="M323 0H146V1082H323V0ZM502 1261V1251H360L240 1421L120 1251H-22V1263L187 1535H292L502 1261Z" />
<glyph unicode="&#xef;" horiz-adv-x="481" d="M323 0H146V1082H323V0ZM-82 1370Q-82 1415 -55 1445T27 1476T109 1446T137 1370T109 1295T27 1265T-54 1295T-82 1370ZM348 1368Q348 1413 375 1444T457 1475T539 1444T567 1368T539 1293T457 1263T376 1293T348 1368Z" />
<glyph unicode="&#xf0;" horiz-adv-x="1051" d="M705 1302Q922 1036 922 627V535Q922 376 872 250T729 52T521 -20Q408 -20 315 43T170 219T118 467Q118 614 166 731T303 912T498 977Q623 977 721 877Q679 1062 569 1194L388 1051L320 1150L484 1280Q374 1371
221 1421L275 1580Q473 1527 622 1390L781 1516L849 1416L705 1302ZM746 635L744 695Q718 754 664 789T542 825Q428 825 362 729T295 467Q295 326 360 229T525 131Q623 131 683 241T746 525V635Z" />
<glyph unicode="&#xf1;" horiz-adv-x="991" d="M299 1082L304 965Q407 1102 567 1102Q854 1102 858 719V0H682V711Q682 838 640 891T512 945Q446 945 394 901T309 786V0H132V1082H299ZM802 1504Q802 1399 750 1331T616 1262Q581 1262 556 1272T491 1313T433 1350T392
1357Q358 1357 336 1325T313 1245L198 1252Q198 1361 251 1430T383 1499Q413 1499 437 1488T497 1450T557 1414T607 1403Q641 1403 664 1435T687 1516L802 1504Z" />
<glyph unicode="&#xf2;" horiz-adv-x="1028" d="M95 591Q95 827 209 964T512 1102T814 968T932 603V489Q932 254 818 117T514 -20Q326 -20 213 113T95 473V591ZM272 489Q272 322 337 227T514 131Q748 131 755 469V591Q755 757 689 853T512 950Q403 950 338 854T272
592V489ZM610 1242H451L193 1536H416L610 1242Z" />
<glyph unicode="&#xf3;" horiz-adv-x="1028" d="M95 591Q95 827 209 964T512 1102T814 968T932 603V489Q932 254 818 117T514 -20Q326 -20 213 113T95 473V591ZM272 489Q272 322 337 227T514 131Q748 131 755 469V591Q755 757 689 853T512 950Q403 950 338 854T272
592V489ZM595 1536H819L551 1242H402L595 1536Z" />
<glyph unicode="&#xf4;" horiz-adv-x="1028" d="M95 591Q95 827 209 964T512 1102T814 968T932 603V489Q932 254 818 117T514 -20Q326 -20 213 113T95 473V591ZM272 489Q272 322 337 227T514 131Q748 131 755 469V591Q755 757 689 853T512 950Q403 950 338 854T272
592V489ZM766 1262V1252H624L504 1422L384 1252H242V1264L451 1536H556L766 1262Z" />
<glyph unicode="&#xf5;" horiz-adv-x="1028" d="M95 591Q95 827 209 964T512 1102T814 968T932 603V489Q932 254 818 117T514 -20Q326 -20 213 113T95 473V591ZM272 489Q272 322 337 227T514 131Q748 131 755 469V591Q755 757 689 853T512 950Q403 950 338 854T272
592V489ZM806 1504Q806 1399 754 1331T620 1262Q585 1262 560 1272T495 1313T437 1350T396 1357Q362 1357 340 1325T317 1245L202 1252Q202 1361 255 1430T387 1499Q417 1499 441 1488T501 1450T561 1414T611 1403Q645 1403 668 1435T691 1516L806 1504Z" />
<glyph unicode="&#xf6;" horiz-adv-x="1028" d="M95 591Q95 827 209 964T512 1102T814 968T932 603V489Q932 254 818 117T514 -20Q326 -20 213 113T95 473V591ZM272 489Q272 322 337 227T514 131Q748 131 755 469V591Q755 757 689 853T512 950Q403 950 338 854T272
592V489ZM182 1371Q182 1416 209 1446T291 1477T373 1447T401 1371T373 1296T291 1266T210 1296T182 1371ZM612 1369Q612 1414 639 1445T721 1476T803 1445T831 1369T803 1294T721 1264T640 1294T612 1369Z" />
<glyph unicode="&#xf7;" horiz-adv-x="1024" d="M918 600H79V784H918V600ZM396 1098Q396 1146 422 1178T502 1210T582 1178T609 1098Q609 1051 582 1020T502 989T423 1020T396 1098ZM396 281Q396 329 422 361T502 393T582 361T609 281Q609 235 582 204T502 172T423
203T396 281Z" />
<glyph unicode="&#xf8;" d="M97 551Q97 796 212 949T512 1102Q602 1102 680 1063L740 1208H854L768 1002Q931 847 931 529Q931 286 816 133T514 -20Q433 -20 358 12L297 -134H183L268 71Q97 219 97 551ZM273 529Q273 349 338 239L619 917Q572 950 512 950Q404
950 339 842T273 529ZM753 551Q753 719 696 827L418 156Q462 131 514 131Q625 131 689 239T753 551Z" />
<glyph unicode="&#xf9;" horiz-adv-x="990" d="M684 95Q596 -20 427 -20Q280 -20 205 81T129 377V1082H305V390Q305 137 457 137Q618 137 679 281V1082H856V0H688L684 95ZM600 1242H441L183 1536H406L600 1242Z" />
<glyph unicode="&#xfa;" horiz-adv-x="990" d="M684 95Q596 -20 427 -20Q280 -20 205 81T129 377V1082H305V390Q305 137 457 137Q618 137 679 281V1082H856V0H688L684 95ZM585 1536H809L541 1242H392L585 1536Z" />
<glyph unicode="&#xfb;" horiz-adv-x="990" d="M684 95Q596 -20 427 -20Q280 -20 205 81T129 377V1082H305V390Q305 137 457 137Q618 137 679 281V1082H856V0H688L684 95ZM756 1262V1252H614L494 1422L374 1252H232V1264L441 1536H546L756 1262Z" />
<glyph unicode="&#xfc;" horiz-adv-x="990" d="M684 95Q596 -20 427 -20Q280 -20 205 81T129 377V1082H305V390Q305 137 457 137Q618 137 679 281V1082H856V0H688L684 95ZM172 1371Q172 1416 199 1446T281 1477T363 1447T391 1371T363 1296T281 1266T200 1296T172
1371ZM602 1369Q602 1414 629 1445T711 1476T793 1445T821 1369T793 1294T711 1264T630 1294T602 1369Z" />
<glyph unicode="&#xfd;" horiz-adv-x="853" d="M428 294L625 1082H813L459 -153Q419 -292 346 -364T180 -437Q144 -437 88 -421V-271L127 -275Q204 -275 247 -239T318 -112L353 9L35 1082H228L428 294ZM536 1536H760L492 1242H343L536 1536Z" />
<glyph unicode="&#xfe;" horiz-adv-x="1041" d="M923 529Q923 282 828 131T569 -20Q412 -20 318 88V-416H142V1536H318V989Q410 1102 566 1102Q734 1102 828 954T923 529ZM747 550Q747 730 685 837T511 945Q385 945 318 807V265Q383 131 513 131Q622 131 684 238T747
550Z" />
<glyph unicode="&#xff;" horiz-adv-x="853" d="M428 294L625 1082H813L459 -153Q419 -292 346 -364T180 -437Q144 -437 88 -421V-271L127 -275Q204 -275 247 -239T318 -112L353 9L35 1082H228L428 294ZM123 1371Q123 1416 150 1446T232 1477T314 1447T342 1371T314
1296T232 1266T151 1296T123 1371ZM553 1369Q553 1414 580 1445T662 1476T744 1445T772 1369T744 1294T662 1264T581 1294T553 1369Z" />
<glyph unicode="&#x2013;" horiz-adv-x="1172" d="M1259 651H417V802H1259V651Z" />
<glyph unicode="&#x2014;" horiz-adv-x="1389" d="M1537 651H415V802H1537V651Z" />
<glyph unicode="&#x2018;" horiz-adv-x="398" d="M257 1555L357 1483Q278 1353 275 1211V1073H100V1189Q100 1290 144 1391T257 1555Z" />
<glyph unicode="&#x2019;" horiz-adv-x="398" d="M155 1046L56 1118Q134 1249 137 1390V1536H312V1401Q310 1305 268 1207T155 1046Z" />
<glyph unicode="&#x201a;" horiz-adv-x="399" d="M148 -283L48 -210Q128 -79 128 73V181H305V81Q305 -17 262 -117T148 -283Z" />
<glyph unicode="&#x201c;" horiz-adv-x="684" d="M266 1555L366 1483Q287 1353 284 1211V1073H109V1189Q109 1290 153 1391T266 1555ZM551 1555L651 1483Q572 1353 569 1211V1073H394V1189Q394 1290 438 1391T551 1555Z" />
<glyph unicode="&#x201d;" horiz-adv-x="691" d="M167 1046L68 1118Q146 1249 149 1390V1536H324V1401Q322 1305 280 1207T167 1046ZM445 1046L346 1118Q424 1249 427 1390V1536H602V1401Q600 1305 558 1207T445 1046Z" />
<glyph unicode="&#x201e;" horiz-adv-x="668" d="M148 -301L48 -229Q125 -93 128 59V246H305V82Q305 -23 262 -127T148 -301ZM416 -301L317 -229Q394 -93 397 59V246H574V82Q574 -23 531 -128T416 -301Z" />
<glyph unicode="&#x2022;" horiz-adv-x="690" d="M138 772Q138 859 193 915T341 971Q432 971 489 917T546 769V732Q546 645 491 590T342 535Q249 535 194 590T138 734V772Z" />
<glyph unicode="&#x2039;" horiz-adv-x="557" d="M277 550L488 153H359L111 541V560L359 949H488L277 550Z" />
<glyph unicode="&#x203a;" horiz-adv-x="557" d="M223 949L471 560V541L223 152H92L303 550L92 949H223Z" />
</font>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 47 KiB

Some files were not shown because too many files have changed in this diff Show More