Compare commits
10 Commits
juliaengin
...
english
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b5571f8b1 | |||
| 0e6b3d92fa | |||
| 733fe8c290 | |||
| c6609d15f5 | |||
| 457873a31b | |||
| 68983e30b1 | |||
| 552438aebe | |||
| 3b9c141c44 | |||
| 04b8a23362 | |||
| 9e418381ca |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -32,3 +32,5 @@ xelatex.py
|
||||
nb/*.qmd
|
||||
nb/*.ipynb
|
||||
.cache/
|
||||
|
||||
**/*.quarto_ipynb
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"julia.environmentPath": "/home/hellmund/Julia/23",
|
||||
"julia.environmentPath": "/home/hellmund/Julia/Book26/JuliaKurs23/",
|
||||
"files.exclude": {
|
||||
"**/.DS_Store": true,
|
||||
"**/.git": true,
|
||||
|
||||
147
AGENTS.md
Normal file
147
AGENTS.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# AGENTS.md - Guidelines for JuliaKurs23
|
||||
|
||||
This is a **Quarto-based Julia programming course book**. The book teaches scientific computing with Julia using interactive Jupyter notebooks rendered with Quarto.
|
||||
|
||||
**Translation Note:** The book was originally written in German and translated to English. The English needs improvement—focus on making the prose professional, concise, and suitable for mathematicians.
|
||||
|
||||
## Project Overview
|
||||
|
||||
- **Type**: Educational book (HTML website + PDF) generated from Quarto (.qmd) files
|
||||
- **Language**: English (all content)
|
||||
- **Build System**: Quarto with Julia Jupyter kernel
|
||||
- **Julia Version**: 1.10
|
||||
- **License**: CC BY-NC-SA 4.0
|
||||
|
||||
---
|
||||
|
||||
## Current Task: English Translation Improvement
|
||||
|
||||
The English text in this book was translated from German and needs refinement for quality.
|
||||
|
||||
### Workflow (one change at a time)
|
||||
|
||||
For each chapter file in `chapters/`:
|
||||
|
||||
1. I read the file and identify English improvements
|
||||
2. I present ONE improvement at a time showing:
|
||||
- The current text
|
||||
- The proposed improvement
|
||||
- Explanation of why the change is needed
|
||||
3. You reply **yes** or **no**
|
||||
4. If yes, I apply the change; if no, I skip it
|
||||
5. Repeat until all improvements for that file are done
|
||||
6. Move to the next chapter file
|
||||
|
||||
### What to improve:
|
||||
- English prose, grammar, word choice
|
||||
- Clarity and flow for mathematical audience
|
||||
- Professional tone suitable for mathematicians/scientists
|
||||
|
||||
### What NOT to change:
|
||||
- Julia code
|
||||
- LaTeX equations
|
||||
- Markdown formatting
|
||||
- Quarto cell options (`#| eval:`, etc.)
|
||||
|
||||
---
|
||||
|
||||
## Build Commands
|
||||
|
||||
```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
|
||||
|
||||
# Render a specific chapter
|
||||
quarto render chapters/first_contact.qmd
|
||||
|
||||
# Run in daemon mode (faster rebuilds)
|
||||
quarto render --execute-daemon 3600
|
||||
```
|
||||
|
||||
### Deployment
|
||||
|
||||
```bash
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### Quarto Structure (.qmd files)
|
||||
|
||||
- All `.qmd` files start with YAML front matter: `engine: julia`
|
||||
- Code blocks use triple backticks with `julia` identifier
|
||||
- Cell options in comments: `#| option: value`
|
||||
|
||||
### Julia Code Conventions
|
||||
|
||||
**Imports:**
|
||||
```julia
|
||||
using Statistics, LinearAlgebra, Plots # many exports
|
||||
import Base: convert, show # specific exports
|
||||
```
|
||||
|
||||
**Naming:**
|
||||
- Variables/functions: lowercase with underscores (`my_variable`)
|
||||
- Types: CamelCase (`MyType`, `AbstractMatrix`)
|
||||
- Constants: ALL_UPPERCASE (`MAX_ITER`)
|
||||
- Modules: PascalCase (`Statistics`)
|
||||
|
||||
**Formatting:**
|
||||
- 4 spaces indentation
|
||||
- ~92 character line limit
|
||||
- Spaces around operators: `a + b`
|
||||
- No spaces before commas: `f(a, b)`
|
||||
|
||||
**Types:**
|
||||
- Explicit types for performance/clarity
|
||||
- Parameterize: `Vector{Float64}`, `Dict{Symbol, Int}`
|
||||
- Concrete types for struct fields
|
||||
|
||||
**Error Handling:**
|
||||
```julia
|
||||
try
|
||||
parse(Int, user_input)
|
||||
catch e
|
||||
println("Invalid input: $e")
|
||||
end
|
||||
|
||||
@assert x >= 0 "x must be non-negative"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Important Notes
|
||||
|
||||
1. **All content is in English** — professional, concise, suitable for mathematicians
|
||||
2. **Code, LaTeX, formatting preserved** — only improve English prose
|
||||
3. **Code execution cached** — use `#| eval: true` to execute cells
|
||||
4. **Freeze mode** — set to `auto` in _quarto.yml; use `freeze: false` to re-run all code
|
||||
5. **Keep intermediates** — `keep-ipynb`, `keep-tex`, `keep-md` are all true
|
||||
2345
Manifest.toml
Normal file
2345
Manifest.toml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,8 @@ SoSe25:
|
||||
für Plots/plotlyjs
|
||||
|
||||
|
||||
26: es reicht, die eine Zeile mit requirejs zu entfernen.
|
||||
|
||||
Book25: Versuch ohne quarto-patch:
|
||||
LaTeX: ansi in stdout not supported, Julia errors werden total
|
||||
zerschossen
|
||||
|
||||
21
_extensions/MHellmund/julia-color/LICENSE_quarto_bookext.txt
Normal file
21
_extensions/MHellmund/julia-color/LICENSE_quarto_bookext.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Posit Software, PBC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,7 +1,7 @@
|
||||
title: Julia-color
|
||||
author: Meik Hellmund
|
||||
version: 1.0.0
|
||||
quarto-required: ">=99.9.0"
|
||||
quarto-required: ">=1.9.0"
|
||||
contributes:
|
||||
formats:
|
||||
common:
|
||||
@@ -14,8 +14,18 @@ contributes:
|
||||
- "resources/css/juliamono.css"
|
||||
pdf:
|
||||
include-in-header:
|
||||
- "resources/tex/juliainc.tex"
|
||||
- "resources/tex/juliainc.tex"
|
||||
|
||||
typst:
|
||||
include-in-header:
|
||||
- "resources/typst/juliainc.typ"
|
||||
- "resources/typst/juliainc.typ"
|
||||
# the following is from
|
||||
# quarto-cli/src/resources/extension-subtrees/orange-book/_extensions/orange-book
|
||||
# comment out for an article
|
||||
template-partials:
|
||||
- numbering.typ
|
||||
- page.typ
|
||||
- typst-show.typ
|
||||
filters:
|
||||
- path: orange-book.lua
|
||||
at: post-quarto
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
-- based on
|
||||
-- https://github.com/jupyter/nbconvert/blob/main/nbconvert/filters/ansi.py
|
||||
|
||||
-- debug: pandoc -t native file.{typst,html,..}.md
|
||||
|
||||
local ANSI_COLORS = {
|
||||
"ansi-black",
|
||||
"ansi-red",
|
||||
@@ -224,18 +226,47 @@ local function HTMLconverter(fg, bg, bold, light, italic, underline, inverse)
|
||||
return starttag..">","</span>"
|
||||
end
|
||||
|
||||
|
||||
local function escapeTypstString(s)
|
||||
s = s:gsub("\\", "\\\\")
|
||||
s = s:gsub("%$", "\\$")
|
||||
s = s:gsub("*", "\\*")
|
||||
s = s:gsub([["]],[[\"]])
|
||||
return s
|
||||
end
|
||||
|
||||
local function escapeTypstString2(s)
|
||||
s = s:gsub("@", "\\@")
|
||||
s = s:gsub("<", "\\<")
|
||||
s = s:gsub("#", "\\#")
|
||||
s = s:gsub(">", "\\>")
|
||||
--s = s:gsub("]","\\]")
|
||||
s = s:gsub("\n","\\\n")
|
||||
s = s:gsub("+","\\+")
|
||||
s = s:gsub("/","\\/")
|
||||
s = s:gsub("=","\\=")
|
||||
return s
|
||||
end
|
||||
|
||||
|
||||
local function noescapeString(s)
|
||||
return s
|
||||
end
|
||||
|
||||
|
||||
local function codeBlockTrans(e)
|
||||
local converter, fmt
|
||||
local converter, fmt, escapeString
|
||||
if quarto.doc.isFormat('latex') then
|
||||
converter = LaTeXconverter
|
||||
fmt = 'latex'
|
||||
escapeString = noescapeString
|
||||
elseif quarto.doc.isFormat('html') then
|
||||
converter = HTMLconverter
|
||||
fmt = 'html'
|
||||
escapeString = noescapeString
|
||||
elseif quarto.doc.isFormat('typst') then
|
||||
converter = Typstconverter
|
||||
fmt = 'typst'
|
||||
escapeString = escapeTypstString
|
||||
else
|
||||
return
|
||||
end
|
||||
@@ -264,7 +295,7 @@ local function codeBlockTrans(e)
|
||||
local out=""
|
||||
local text = e.text
|
||||
|
||||
-- we remove links (eg in julia ParseErrors. THey link to local files, so they are useless anyway)
|
||||
-- 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
|
||||
@@ -305,7 +336,7 @@ local function codeBlockTrans(e)
|
||||
else
|
||||
starttag, endtag = converter(fg, bg, bold, light, italic, underline, inverse)
|
||||
end
|
||||
out = out .. starttag .. chunk .. endtag
|
||||
out = out .. starttag .. escapeString(chunk) .. endtag
|
||||
end
|
||||
|
||||
while next(numbers) ~= nil do
|
||||
@@ -359,7 +390,7 @@ local function codeBlockTrans(e)
|
||||
end
|
||||
end
|
||||
else
|
||||
out = text
|
||||
out = escapeString(text)
|
||||
end
|
||||
if fmt == 'html' then
|
||||
return pandoc.RawBlock(fmt,
|
||||
@@ -369,7 +400,11 @@ local function codeBlockTrans(e)
|
||||
return pandoc.RawBlock(fmt, [[\begin{]]..texenv.."}\n"..out.."\n"..[[\end{]].. texenv .. "}")
|
||||
end
|
||||
if fmt == 'typst' then
|
||||
return pandoc.RawBlock(fmt, "#"..texenv.."[\n"..out.."\n]")
|
||||
if texenv == "OutputCell" then
|
||||
return pandoc.RawBlock(fmt, "#"..texenv.."[\n" .. escapeTypstString2(out) .. "\n]")
|
||||
else
|
||||
return pandoc.RawBlock(fmt, "#"..texenv.."[\n" .. out .. "\n]")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -398,12 +433,52 @@ local function divCodeBlockNoHeader1(e)
|
||||
if el.t == 'Header' then
|
||||
el.level = 6
|
||||
end
|
||||
-- if el.t == 'CodeBlock' then -- attempt for typst, but we use an extra quarto cell
|
||||
-- for i,v in ipairs(el.classes) do
|
||||
-- if v=="julia" or v=="jldoctest" then -- example code and before
|
||||
-- el.classes:remove(i)
|
||||
-- end
|
||||
-- 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
|
||||
|
||||
return {
|
||||
{Div = divStderr},
|
||||
{Div = divCodeBlockNoHeader1},
|
||||
{Blocks = blockMerge},
|
||||
{CodeBlock = codeBlockTrans},
|
||||
}
|
||||
|
||||
38
_extensions/MHellmund/julia-color/numbering.typ
Normal file
38
_extensions/MHellmund/julia-color/numbering.typ
Normal file
@@ -0,0 +1,38 @@
|
||||
// Chapter-based numbering for books with appendix support
|
||||
#let equation-numbering = it => {
|
||||
let pattern = if state("appendix-state", none).get() != none { "(A.1)" } else { "(1.1)" }
|
||||
numbering(pattern, counter(heading).get().first(), it)
|
||||
}
|
||||
#let callout-numbering = it => {
|
||||
let pattern = if state("appendix-state", none).get() != none { "A.1" } else { "1.1" }
|
||||
numbering(pattern, counter(heading).get().first(), it)
|
||||
}
|
||||
#let subfloat-numbering(n-super, subfloat-idx) = {
|
||||
let chapter = counter(heading).get().first()
|
||||
let pattern = if state("appendix-state", none).get() != none { "A.1a" } else { "1.1a" }
|
||||
numbering(pattern, chapter, n-super, subfloat-idx)
|
||||
}
|
||||
// Theorem configuration for theorion
|
||||
// Chapter-based numbering (H1 = chapters)
|
||||
#let theorem-inherited-levels = 1
|
||||
|
||||
// Appendix-aware theorem numbering
|
||||
#let theorem-numbering(loc) = {
|
||||
if state("appendix-state", none).at(loc) != none { "A.1" } else { "1.1" }
|
||||
}
|
||||
|
||||
// Theorem render function
|
||||
// Note: brand-color is not available at this point in template processing
|
||||
#let theorem-render(prefix: none, title: "", full-title: auto, body) = {
|
||||
block(
|
||||
width: 100%,
|
||||
inset: (left: 1em),
|
||||
stroke: (left: 2pt + black),
|
||||
)[
|
||||
#if full-title != "" and full-title != auto and full-title != none {
|
||||
strong[#full-title]
|
||||
linebreak()
|
||||
}
|
||||
#body
|
||||
]
|
||||
}
|
||||
69
_extensions/MHellmund/julia-color/orange-book.lua
Normal file
69
_extensions/MHellmund/julia-color/orange-book.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
-- orange-book.lua
|
||||
-- Orange-book specific part and appendix handling for Typst books
|
||||
|
||||
local function is_typst_book()
|
||||
local file_state = quarto.doc.file_metadata()
|
||||
return quarto.doc.is_format("typst") and
|
||||
file_state ~= nil and
|
||||
file_state.file ~= nil
|
||||
end
|
||||
|
||||
local header_filter = {
|
||||
Header = function(el)
|
||||
local file_state = quarto.doc.file_metadata()
|
||||
|
||||
if not is_typst_book() then
|
||||
return nil
|
||||
end
|
||||
|
||||
if file_state == nil or file_state.file == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
local file = file_state.file
|
||||
local bookItemType = file.bookItemType
|
||||
|
||||
if el.level ~= 1 or bookItemType == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Handle parts
|
||||
if bookItemType == "part" then
|
||||
return pandoc.RawBlock('typst', '#part[' .. pandoc.utils.stringify(el.content) .. ']')
|
||||
end
|
||||
|
||||
-- Handle appendices
|
||||
if bookItemType == "appendix" then
|
||||
-- First appendix triggers the show rule with localized "Appendices" title
|
||||
if file.bookItemNumber == 1 or file.bookItemNumber == nil then
|
||||
-- Get localized title from language settings
|
||||
local language = quarto.doc.language
|
||||
local appendicesTitle = (language and language["section-title-appendices"]) or "Appendices"
|
||||
|
||||
-- Use hide-parent: true to work around orange-book bug where unnumbered headings
|
||||
-- (like Bibliography) trigger duplicate "Appendices" TOC entries.
|
||||
local appendixStart = pandoc.RawBlock('typst',
|
||||
'#show: appendices.with("' .. appendicesTitle .. '", hide-parent: true)')
|
||||
|
||||
-- If this is the synthetic "Appendices" divider heading (has .unnumbered class),
|
||||
-- emit our own Appendices heading for TOC display
|
||||
if el.classes:includes("unnumbered") then
|
||||
local appendicesHeading = pandoc.RawBlock('typst',
|
||||
'#heading(level: 1, numbering: none)[' .. appendicesTitle .. ']')
|
||||
return {appendixStart, appendicesHeading}
|
||||
end
|
||||
|
||||
return {appendixStart, el}
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
}
|
||||
|
||||
-- Combine with file_metadata_filter so book metadata markers are parsed
|
||||
-- during this filter's document traversal (needed for bookItemType, etc.)
|
||||
return quarto.utils.combineFilters({
|
||||
quarto.utils.file_metadata_filter(),
|
||||
header_filter
|
||||
})
|
||||
15
_extensions/MHellmund/julia-color/page.typ
Normal file
15
_extensions/MHellmund/julia-color/page.typ
Normal file
@@ -0,0 +1,15 @@
|
||||
#set page(
|
||||
paper: $if(papersize)$"$papersize$"$else$"us-letter"$endif$,
|
||||
$if(margin-geometry)$
|
||||
// Margins handled by marginalia.setup in typst-show.typ AFTER book.with()
|
||||
$elseif(margin)$
|
||||
margin: ($for(margin/pairs)$$margin.key$: $margin.value$,$endfor$),
|
||||
$else$
|
||||
margin: (x: 1.25in, y: 1.25in),
|
||||
$endif$
|
||||
numbering: $if(page-numbering)$"$page-numbering$"$else$none$endif$,
|
||||
columns: $if(columns)$$columns$$else$1$endif$,
|
||||
)
|
||||
// Logo is handled by orange-book's cover page, not as a page background
|
||||
// NOTE: marginalia.setup is called in typst-show.typ AFTER book.with()
|
||||
// to ensure marginalia's margins override the book format's default margins
|
||||
@@ -2,10 +2,45 @@
|
||||
#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 EndLine() = raw("\n")
|
||||
//#let OutputCell(lines) = {
|
||||
// let blocks = []
|
||||
// for ln in lines {
|
||||
// blocks = blocks + ln + EndLine()
|
||||
// }
|
||||
// block(width:100%, inset:(x:5pt, y:0pt), stroke:( left: 2pt + gray), blocks)
|
||||
//}
|
||||
|
||||
#let OutputCell(content) = block(
|
||||
width: 100%,
|
||||
inset: (x: 5pt, y: 5pt),
|
||||
above: 0pt,
|
||||
below: 8pt,
|
||||
stroke: (left: 2pt + gray, bottom: .5pt + gray)
|
||||
)[
|
||||
#set text(font: "JuliaMono", size:8pt)
|
||||
#content
|
||||
]
|
||||
|
||||
|
||||
#let AnsiOutputCell(content) = block(
|
||||
width: 100%,
|
||||
inset: (x: 5pt, y: 5pt),
|
||||
above: 0pt,
|
||||
below: 8pt,
|
||||
stroke: (left: 2pt + gray, bottom: .5pt + gray)
|
||||
)[
|
||||
#set text(font: "JuliaMono", size:9pt)
|
||||
#content
|
||||
]
|
||||
|
||||
|
||||
|
||||
// does not exist with julia engine
|
||||
#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)
|
||||
|
||||
|
||||
61
_extensions/MHellmund/julia-color/typst-show.typ
Normal file
61
_extensions/MHellmund/julia-color/typst-show.typ
Normal file
@@ -0,0 +1,61 @@
|
||||
#import "@preview/orange-book:0.7.1": book, part, chapter, appendices
|
||||
|
||||
#show: book.with(
|
||||
$if(title)$
|
||||
title: [$title$],
|
||||
$endif$
|
||||
$if(subtitle)$
|
||||
subtitle: [$subtitle$],
|
||||
$endif$
|
||||
$if(by-author)$
|
||||
author: "$for(by-author)$$it.name.literal$$sep$, $endfor$",
|
||||
$endif$
|
||||
$if(date)$
|
||||
date: "$date$",
|
||||
$endif$
|
||||
$if(lang)$
|
||||
lang: "$lang$",
|
||||
$endif$
|
||||
main-color: brand-color.at("primary", default: blue),
|
||||
logo: {
|
||||
let logo-info = brand-logo.at("medium", default: none)
|
||||
if logo-info != none { image(logo-info.path, alt: logo-info.at("alt", default: none)) }
|
||||
},
|
||||
$if(toc-depth)$
|
||||
outline-depth: $toc-depth$,
|
||||
$endif$
|
||||
$if(lof)$
|
||||
list-of-figure-title: "$if(crossref.lof-title)$$crossref.lof-title$$else$$crossref-lof-title$$endif$",
|
||||
$endif$
|
||||
$if(lot)$
|
||||
list-of-table-title: "$if(crossref.lot-title)$$crossref.lot-title$$else$$crossref-lot-title$$endif$",
|
||||
$endif$
|
||||
$if(margin-geometry)$
|
||||
padded-heading-number: false,
|
||||
$endif$
|
||||
)
|
||||
|
||||
$if(margin-geometry)$
|
||||
// Configure marginalia page geometry for book context
|
||||
// Geometry computed by Quarto's meta.lua filter (typstGeometryFromPaperWidth)
|
||||
// IMPORTANT: This must come AFTER book.with() to override the book format's margin settings
|
||||
#import "@preview/marginalia:0.3.1" as marginalia
|
||||
|
||||
#show: marginalia.setup.with(
|
||||
inner: (
|
||||
far: $margin-geometry.inner.far$,
|
||||
width: $margin-geometry.inner.width$,
|
||||
sep: $margin-geometry.inner.separation$,
|
||||
),
|
||||
outer: (
|
||||
far: $margin-geometry.outer.far$,
|
||||
width: $margin-geometry.outer.width$,
|
||||
sep: $margin-geometry.outer.separation$,
|
||||
),
|
||||
top: $if(margin.top)$$margin.top$$else$1.25in$endif$,
|
||||
bottom: $if(margin.bottom)$$margin.bottom$$else$1.25in$endif$,
|
||||
// CRITICAL: Enable book mode for recto/verso awareness
|
||||
book: true,
|
||||
clearance: $margin-geometry.clearance$,
|
||||
)
|
||||
$endif$
|
||||
65
_quarto.yml
65
_quarto.yml
@@ -4,15 +4,15 @@ project:
|
||||
- fonts/
|
||||
- images/
|
||||
|
||||
lang: de
|
||||
language:
|
||||
title-block-published: "Updated"
|
||||
title-block-author-single: "Autor"
|
||||
toc-title-document: "Auf dieser Seite"
|
||||
lang: en
|
||||
#language:
|
||||
# title-block-published: "Updated"
|
||||
# title-block-author-single: "Autor"
|
||||
# toc-title-document: "Auf dieser Seite"
|
||||
|
||||
book:
|
||||
title: "Julia für Numerik"
|
||||
subtitle: "Einführung in die wissenschaftliche Programmierung"
|
||||
title: "Julia for Numerical Analysis"
|
||||
subtitle: "Introduction to Scientific Computing"
|
||||
author: "Meik Hellmund"
|
||||
site-url: "https://www.math.uni-leipzig.de/~hellmund/juliabook"
|
||||
favicon: "images/favicon-32x32.png"
|
||||
@@ -23,7 +23,7 @@ book:
|
||||
- icon: github
|
||||
href: https://gitea.math.uni-leipzig.de/hellmund/JuliaKurs23
|
||||
- icon: download
|
||||
href: "Julia-f%C3%BCr-Numerik.pdf"
|
||||
href: "Julia-for-Numerical-Analysis.pdf"
|
||||
|
||||
|
||||
search: true
|
||||
@@ -56,7 +56,7 @@ book:
|
||||
- chapters/10_Strings.qmd
|
||||
- chapters/13_IO.qmd
|
||||
- chapters/14_Plot.qmd
|
||||
# - chapters/makie.qmd
|
||||
|
||||
|
||||
|
||||
format:
|
||||
@@ -82,12 +82,33 @@ format:
|
||||
cap-location: bottom
|
||||
html-math-method: mathjax
|
||||
|
||||
julia-color-pdf:
|
||||
pdf-engine: xelatex
|
||||
# julia-color-pdf:
|
||||
# pdf-engine: xelatex
|
||||
# papersize: a4
|
||||
# documentclass: scrreprt
|
||||
# classoption: [notitlepage,DIV=16,BCOR=5mm,10pt]
|
||||
# toc: false
|
||||
# number-depth: 2
|
||||
# fig-cap-location: bottom
|
||||
# fig-pos: H
|
||||
# tbl-cap-location: bottom
|
||||
# hyperrefoptions:
|
||||
# - linktoc=all
|
||||
# colorlinks: true
|
||||
# linkcolor: "blue"
|
||||
# keep-tex: true
|
||||
# keep-ipynb: true
|
||||
# keep-md: true
|
||||
# code-block-bg: "#e0e0e0"
|
||||
# code-block-border-left: "#e0e0e0"
|
||||
# code-overflow: wrap
|
||||
# include-in-header:
|
||||
# - file: macros.tex
|
||||
|
||||
julia-color-typst:
|
||||
papersize: a4
|
||||
documentclass: scrreprt
|
||||
classoption: [notitlepage,DIV=16,BCOR=5mm,10pt]
|
||||
toc: false
|
||||
toc: true
|
||||
toc-depth: 2
|
||||
number-depth: 2
|
||||
fig-cap-location: bottom
|
||||
fig-pos: H
|
||||
@@ -95,16 +116,12 @@ format:
|
||||
hyperrefoptions:
|
||||
- linktoc=all
|
||||
colorlinks: true
|
||||
linkcolor: "blue"
|
||||
keep-tex: true
|
||||
keep-ipynb: true
|
||||
keep-md: true
|
||||
code-block-bg: "#e0e0e0"
|
||||
code-block-border-left: "#e0e0e0"
|
||||
code-overflow: wrap
|
||||
linkcolor: #0000FF
|
||||
keep-typ: true
|
||||
include-in-header:
|
||||
- file: macros.tex
|
||||
|
||||
- file: macros.typ
|
||||
|
||||
|
||||
latex-auto-install: false
|
||||
|
||||
execute:
|
||||
@@ -122,8 +139,6 @@ keep-ipynb: true
|
||||
keep-tex: true
|
||||
keep-md: true
|
||||
|
||||
jupyter: julia-1.10
|
||||
|
||||
filters:
|
||||
- code-visibility
|
||||
- latex-environment
|
||||
|
||||
@@ -9,98 +9,98 @@ engine: julia
|
||||
using InteractiveUtils
|
||||
import QuartoNotebookWorker
|
||||
Base.stdout = QuartoNotebookWorker.with_context(stdout)
|
||||
|
||||
```
|
||||
|
||||
# Zeichen, Strings und Unicode
|
||||
# Characters, Strings, and Unicode
|
||||
|
||||
## Zeichencodierungen (Frühgeschichte)
|
||||
## Character Encodings (Early History)
|
||||
|
||||
Es gab - abhängig von Hersteller, Land, Programmiersprache, Betriebsssystem,... - eine große Vielzahl von Codierungen.
|
||||
There were - depending on manufacturer, country, programming language, operating system, etc. - a large variety of encodings.
|
||||
|
||||
Bis heute relevant sind:
|
||||
Still relevant today are:
|
||||
|
||||
|
||||
### ASCII
|
||||
Der _American Standard Code for Information Interchange_ wurde 1963 in den USA als Standard veröffentlicht.
|
||||
The American Standard Code for Information Interchange (ASCII) 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, you can fit another 128 characters by setting the 8th bit.
|
||||
- In 1987/88, various 1-byte encodings were standardized in ISO 8859, all ASCII-compatible, including:
|
||||
|
||||
:::{.narrow}
|
||||
|Codierung | Region | Sprachen|
|
||||
|Encoding | Region | Languages|
|
||||
|:-----------|:----------|:-------|
|
||||
|ISO 8859-1 (Latin-1) | Westeuropa | Deutsch, Französisch,...,Isländisch
|
||||
|ISO 8859-2 (Latin-2) | Osteuropa | slawische Sprachen mit lateinischer Schrift
|
||||
|ISO 8859-3 (Latin-3) | Südeuropa | Türkisch, Maltesisch,...
|
||||
|ISO 8859-4 (Latin-4) | Nordeuropa | Estnisch, Lettisch, Litauisch, Grönländisch, Sami
|
||||
|ISO 8859-5 (Latin/Cyrillic) | Osteuropa | slawische Sprachen mit kyrillischer Schrift
|
||||
|ISO 8859-1 (Latin-1) | Western Europe | German, French,..., Icelandic
|
||||
|ISO 8859-2 (Latin-2) | Eastern Europe | Slavic languages with Latin script
|
||||
|ISO 8859-3 (Latin-3) | Southern Europe | Turkish, Maltese,...
|
||||
|ISO 8859-4 (Latin-4) | Northern Europe | Estonian, Latvian, Lithuanian, Greenlandic, Sami
|
||||
|ISO 8859-5 (Latin/Cyrillic) | Eastern Europe | Slavic languages with Cyrillic script
|
||||
|ISO 8859-6 (Latin/Arabic) | |
|
||||
|ISO 8859-7 (Latin/Greek) | |
|
||||
|...| |
|
||||
|ISO 8859-15 (Latin-9)| | 1999: Revision von Latin-1: jetzt u.a. mit Euro-Zeichen
|
||||
|ISO 8859-15 (Latin-9)| | 1999: Revision of Latin-1: now including Euro sign
|
||||
|
||||
:::
|
||||
|
||||
|
||||
## Unicode
|
||||
|
||||
Das Ziel des Unicode-Consortiums ist eine einheitliche Codierung für alle Schriften der Welt.
|
||||
The goal of the Unicode Consortium is a uniform encoding for all scripts worldwide.
|
||||
|
||||
- Unicode Version 1 erschien 1991
|
||||
- Unicode Version 15.1 erschien 2023 mit 149 813 Zeichen, darunter:
|
||||
- 161 Schriften
|
||||
- mathematische und technische Symbole
|
||||
- Emojis und andere Symbole, Steuer- und Formatierungszeichen
|
||||
- davon entfallen über 90 000 Zeichen auf die CJK-Schriften (Chinesisch/Japanisch/Koreanisch)
|
||||
|
||||
|
||||
### Technische Details
|
||||
- Unicode version 1 was published in 1991
|
||||
- Unicode version 17 was published in 2025 with 159,801 characters, including:
|
||||
- 172 scripts
|
||||
- mathematical and technical symbols
|
||||
- Emojis and other symbols, control and formatting characters
|
||||
- Over 90,000 characters are assigned to the CJK scripts (Chinese/Japanese/Korean)
|
||||
|
||||
- Jedem Zeichen wird ein `codepoint` zugeordnet. Das ist einfach eine fortlaufende Nummer.
|
||||
- Diese Nummer wird hexadezimal notiert
|
||||
- entweder 4-stellig als `U+XXXX` (0-te Ebene)
|
||||
- oder 6-stellig als `U+XXXXXX` (weitere Ebenen)
|
||||
- Jede Ebene geht von `U+XY0000` bis `U+XYFFFF`, kann also $2^{16}=65\;534$ Zeichen enthalten.
|
||||
- Vorgesehen sind bisher 17 Ebenen `XY=00` bis `XY=10`, also der Wertebereich von `U+0000` bis `U+10FFFF`.
|
||||
- Damit sind maximal 21 Bits pro Zeichen nötig.
|
||||
- Die Gesamtzahl der damit möglichen Codepoints ist etwas kleiner als 0x10FFFF, da aus technischen Gründen gewisse Bereiche nicht verwendet werden. Sie beträgt etwa 1.1 Millionen, es ist also noch viel Platz.
|
||||
- Bisher wurden nur Codepoints aus den Ebenen
|
||||
- Ebene 0 = BMP _Basic Multilingual Plane_ `U+0000 - U+FFFF`,
|
||||
- Ebene 1 = SMP _Supplementary Multilingual Plane_ `U+010000 - U+01FFFF`,
|
||||
- Ebene 2 = SIP _Supplementary Ideographic Plane_ `U+020000 - U+02FFFF`,
|
||||
- Ebene 3 = TIP _Tertiary Ideographic Plane_ `U+030000 - U+03FFFF` und
|
||||
- Ebene 14 = SSP _Supplementary Special-purpose Plane_ `U+0E0000 - U+0EFFFF`
|
||||
vergeben.
|
||||
- `U+0000` bis `U+007F` ist identisch mit ASCII
|
||||
- `U+0000` bis `U+00FF` ist identisch mit ISO 8859-1 (Latin-1)
|
||||
|
||||
### Eigenschaften von Unicode-Zeichen
|
||||
### Technical Details
|
||||
|
||||
Im Standard wird jedes Zeichen beschrieben duch
|
||||
- Each character is assigned a `codepoint`, which is simply a sequential number written hexadecimally
|
||||
- either with 4 digit as `U+XXXX` (zeroth plane)
|
||||
- or with 6 digit as `U+XXXXXX` (further planes)
|
||||
- Each plane ranges from `U+XY0000` to `U+XYFFFF`, thus containing $2^{16}=65\;534$ characters.
|
||||
- 17 planes `XY=00` to `XY=10` are provided, giving a 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 have been assigned only from these planes:
|
||||
- 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`.
|
||||
- `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 (simplified, only codepoint and name):
|
||||
```
|
||||
...
|
||||
U+0041 LATIN CAPITAL LETTER A
|
||||
@@ -118,45 +118,47 @@ U+21B4 RIGHTWARDS ARROW WITH CORNER DOWNWARDS
|
||||
...
|
||||
```
|
||||
|
||||
Wie sieht 'RIGHTWARDS ARROW WITH CORNER DOWNWARDS' aus?
|
||||
What does 'RIGHTWARDS ARROW WITH CORNER DOWNWARDS' look like?
|
||||
|
||||
Julia verwendet `\U...` zur Eingabe von Unicode Codepoints.
|
||||
Julia uses `\U...` for input of Unicode codepoints.
|
||||
|
||||
```{julia}
|
||||
'\U21b4'
|
||||
```
|
||||
|
||||
|
||||
### Eine Auswahl an Schriften
|
||||
### A Selection of Scripts
|
||||
|
||||
::: {.content-visible when-format="html"}
|
||||
|
||||
:::{.callout-note}
|
||||
Falls im Folgenden einzelne Zeichen oder Schriften in Ihrem Browser nicht darstellbar sind, müssen Sie geeignete
|
||||
Fonts auf Ihrem Rechner installieren.
|
||||
If individual characters or scripts are not displayable in your browser, you must install appropriate
|
||||
fonts on your computer.
|
||||
|
||||
Alternativ können Sie die PDF-Version dieser Seite verwenden. Dort sind alle Fonts eingebunden.
|
||||
Alternatively, you can use the PDF version of this page. There, all fonts are embedded.
|
||||
:::
|
||||
|
||||
:::
|
||||
|
||||
Eine kleine Hilfsfunktion:
|
||||
A small helper function:
|
||||
```{julia}
|
||||
function printuc(c, n)
|
||||
for i in 0:n-1
|
||||
print(c + i)
|
||||
for i in 1:n
|
||||
print(c + i -1)
|
||||
if i%70 == 0 print("\n") end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
__Kyrillisch__
|
||||
__Cyrillic__
|
||||
|
||||
|
||||
```{julia}
|
||||
printuc('\U0400', 100)
|
||||
```
|
||||
|
||||
__Tamilisch__
|
||||
__Tamil__
|
||||
|
||||
|
||||
:::{.cellmerge}
|
||||
```{julia}
|
||||
@@ -177,21 +179,21 @@ printuc('\U0be7',20)
|
||||
|
||||
:::
|
||||
|
||||
__Schach__
|
||||
__Chess__
|
||||
|
||||
|
||||
```{julia}
|
||||
printuc('\U2654', 12)
|
||||
```
|
||||
|
||||
__Mathematische Operatoren__
|
||||
__Mathematical Operators__
|
||||
|
||||
|
||||
```{julia}
|
||||
printuc('\U2200', 255)
|
||||
```
|
||||
|
||||
__Runen__
|
||||
__Runes__
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -200,12 +202,11 @@ printuc('\U16a0', 40)
|
||||
|
||||
:::{.cellmerge}
|
||||
|
||||
__Scheibe (Diskus) von Phaistos__
|
||||
|
||||
- Diese Schrift ist nicht entziffert.
|
||||
- Es ist unklar, welche Sprache dargestellt wird.
|
||||
- Es gibt nur ein einziges Dokument in dieser Schrift: die Tonscheibe von Phaistos aus der Bronzezeit
|
||||
__Phaistos Disc__
|
||||
|
||||
- This script is not deciphered.
|
||||
- It is unclear what language it represents.
|
||||
- There is only one single document in this script: the Phaistos Disc from the Bronze Age.
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -226,55 +227,53 @@ 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 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, you 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) is:
|
||||
- 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.
|
||||
|
||||
- If the 17 planes (equivalent to 21 bits, resulting in approximately 1.1 million possible characters) currently defined in Unicode are ever depleted, UTF-8 can be extended to include 5- and 6-byte code sequences.
|
||||
|
||||
## Zeichen und Zeichenketten in Julia
|
||||
## Characters and Strings in Julia
|
||||
|
||||
### Zeichen: `Char`
|
||||
### Characters
|
||||
|
||||
Der Datentyp `Char` kodiert ein einzelnes Unicode-Zeichen.
|
||||
The `Char` type encodes a single Unicode character.
|
||||
|
||||
- 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.
|
||||
- Julia uses single quotes for characters: `'a'`.
|
||||
- A `Char` occupies 4 bytes of memory and
|
||||
- represents a Unicode codepoint.
|
||||
- `Char`s can be converted to/from `UInt`s and
|
||||
- the integer value is equal to the Unicode codepoint.
|
||||
|
||||
|
||||
`Char`s können von/zu `UInt`s umgewandelt werden.
|
||||
|
||||
`Char`s can be converted to/from `UInt`s:
|
||||
```{julia}
|
||||
UInt('a')
|
||||
```
|
||||
@@ -284,10 +283,10 @@ UInt('a')
|
||||
b = Char(0x2656)
|
||||
```
|
||||
|
||||
### Zeichenketten: `String`
|
||||
### Strings
|
||||
|
||||
- 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.
|
||||
- In Julia, strings are denoted with double quotes: `"a"`.
|
||||
- These strings are encoded in UTF-8, where a single character may consist of 1 to 4 bytes.
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -297,21 +296,20 @@ b = Char(0x2656)
|
||||
|
||||
|
||||
|
||||
__Bei einem Nicht-ASCII-String unterscheiden sich Anzahl der Bytes und Anzahl der Zeichen:__
|
||||
__For a non-ASCII string, the number of bytes and the number of characters differ:__
|
||||
|
||||
|
||||
```{julia}
|
||||
asciistr = "Hello World!"
|
||||
@show length(asciistr) ncodeunits(asciistr);
|
||||
```
|
||||
(Das Leerzeichen zählt natürlich auch.)
|
||||
|
||||
```{julia}
|
||||
str = "😄 Hellö 🎶"
|
||||
@show length(str) ncodeunits(str);
|
||||
```
|
||||
|
||||
__Iteration über einen String iteriert über die Zeichen:__
|
||||
__Iterating over a string iterates over the characters:__
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -320,76 +318,71 @@ 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
|
||||
|
||||
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:
|
||||
### String Interpolation
|
||||
|
||||
The dollar sign serves a special purpose in strings, frequently utilized within `print()` statements. It enables the interpolation of variables or expressions.
|
||||
|
||||
```{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, 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
|
||||
|
||||
Man kann Strings auch mit Triple-Quotes begrenzen.
|
||||
In dieser Form bleiben Zeilenumbrüche und Anführungszeichen erhalten:
|
||||
### Triple Quotes
|
||||
|
||||
Strings may also be enclosed in triple quotes, preserving line breaks and embedded quotes:
|
||||
|
||||
```{julia}
|
||||
s = """
|
||||
Das soll
|
||||
ein "längerer"
|
||||
'Text' sein.
|
||||
This should
|
||||
be a "longer"
|
||||
'text'.
|
||||
"""
|
||||
|
||||
print(s)
|
||||
```
|
||||
|
||||
### Raw strings
|
||||
|
||||
In einem `raw string` sind alle backslash-Codierungen außer `\"` abgeschaltet:
|
||||
### Raw Strings
|
||||
|
||||
In a `raw string`, all backslash escape sequences except for `\"` are disabled:
|
||||
|
||||
```{julia}
|
||||
s = raw"Ein $ und ein \ und zwei \\ und ein 'bla'..."
|
||||
s = raw"A $ and a \ and two \\ and a 'bla'..."
|
||||
print(s)
|
||||
```
|
||||
|
||||
## Weitere Funktionen für Zeichen und Strings (Auswahl)
|
||||
## Further Functions for Characters and Strings (Selection)
|
||||
|
||||
### Tests für Zeichen
|
||||
### Tests for Characters
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -397,9 +390,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 be used on strings with `all()`, `any()`, or `count()`:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -408,7 +401,7 @@ all(ispunct, ";.:")
|
||||
|
||||
|
||||
```{julia}
|
||||
any(isdigit, "Es ist 3 Uhr! 🕒" )
|
||||
any(isdigit, "It is 3 o'clock! 🕒" )
|
||||
```
|
||||
|
||||
|
||||
@@ -416,7 +409,7 @@ any(isdigit, "Es ist 3 Uhr! 🕒" )
|
||||
count(islowercase, "Hello, du!!")
|
||||
```
|
||||
|
||||
### Weitere String-Funktionen
|
||||
### Other String Functions
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -438,50 +431,49 @@ 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, with a few special features:
|
||||
|
||||
- Der Index nummeriert die Bytes des Strings.
|
||||
- Bei einem nicht-ASCII-String sind nicht alle Indizes gültig, denn
|
||||
- ein gültiger Index adressiert immer ein Unicode-Zeichen.
|
||||
- The index numbers the bytes of the string.
|
||||
- For a non-ASCII string, not all indices are valid because a valid index always addresses a Unicode character.
|
||||
|
||||
Unser Beispielstring:
|
||||
Our example string:
|
||||
```{julia}
|
||||
str
|
||||
```
|
||||
|
||||
Das erste Zeichen
|
||||
The first character
|
||||
```{julia}
|
||||
str[1]
|
||||
```
|
||||
|
||||
Dieses Zeichen ist in UTF8-Kodierung 4 Bytes lang. Damit sind 2,3 und 4 ungültige Indizes.
|
||||
This character is 4 bytes long in UTF-8 encoding. Thus, 2, 3, and 4 are invalid indices.
|
||||
```{julia}
|
||||
str[2]
|
||||
```
|
||||
|
||||
Erst das 5. Byte ist ein neues Zeichen:
|
||||
Only the 5th byte is a new character:
|
||||
|
||||
```{julia}
|
||||
str[5]
|
||||
```
|
||||
|
||||
Auch bei der Adressierung von Substrings müssen Anfang und Ende jeweils gültige Indizes sein, d.h., der Endindex muss ebenfalls das erste Byte eines Zeichens indizieren und dieses Zeichen ist das letzte des Teilstrings.
|
||||
Even when addressing substrings, start and end must always be valid indices; i.e., the end index must also index the first byte of a character, and that character is the last of the substring.
|
||||
|
||||
```{julia}
|
||||
str[1:7]
|
||||
```
|
||||
|
||||
Die Funktion `eachindex()` liefert einen Iterator über die gültigen Indizes:
|
||||
The function `eachindex()` returns an iterator over the valid indices:
|
||||
|
||||
```{julia}
|
||||
for i in eachindex(str)
|
||||
@@ -490,24 +482,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., 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 characters can be 1, 2, 3, or 4 bytes long.
|
||||
|
||||
|
||||
Einige Funktionen liefern Indizes oder Ranges als Resultat. Sie liefern immer gültige Indizes:
|
||||
Some functions return indices or ranges as results. They always return valid indices:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -529,9 +521,8 @@ str2 = "αβγδϵ"^3
|
||||
n = findfirst('γ', str2)
|
||||
```
|
||||
|
||||
So kann man ab dem nächsten nach `n=5` gültigen Index weitersuchen:
|
||||
So you can continue searching from the next valid index after `n=5`:
|
||||
|
||||
```{julia}
|
||||
findnext('γ', str2, nextind(str2, n))
|
||||
```
|
||||
|
||||
|
||||
@@ -7,17 +7,34 @@ engine: julia
|
||||
#| echo: false
|
||||
#| output: false
|
||||
using InteractiveUtils
|
||||
|
||||
#struct M a::Int end; x = M(22); @show x
|
||||
#should not print "Main.Notebook.M(22)" but only "M(22)"
|
||||
function Base.show(io::IO, x::T) where T
|
||||
if parentmodule(T) == @__MODULE__
|
||||
# Print "TypeName(fields...)" without module prefix
|
||||
print(io, nameof(T), "(")
|
||||
fields = fieldnames(T)
|
||||
for (i, f) in enumerate(fields)
|
||||
print(io, getfield(x, f))
|
||||
i < length(fields) && print(io, ", ")
|
||||
end
|
||||
print(io, ")")
|
||||
else
|
||||
invoke(Base.show, Tuple{IO, Any}, io, x)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
# Lineare Algebra in Julia
|
||||
# Linear Algebra in Julia
|
||||
|
||||
```{julia}
|
||||
using LinearAlgebra
|
||||
```
|
||||
|
||||
Das `LinearAlgebra`-Paket liefert unter anderem:
|
||||
The `LinearAlgebra` package provides, among other things:
|
||||
|
||||
- zusätzliche Subtypen von `AbstractMatrix`: genauso verwendbar, wie andere Matrizen, z.B.
|
||||
- additional subtypes of `AbstractMatrix` which are usable like other matrices, among them:
|
||||
|
||||
- `Tridiagonal`
|
||||
- `SymTridiagonal`
|
||||
@@ -25,26 +42,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
|
||||
## Special Matrix Types
|
||||
|
||||
|
||||
|
||||
@@ -57,31 +74,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 are not necessarily possible:
|
||||
```{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 using `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 required size
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -89,39 +106,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 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||
|
||||
d(x,y) := \lVert x-y\rVert
|
||||
$$
|
||||
|
||||
### $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},
|
||||
\lVert \mathbf{x} \rVert_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
|
||||
$$ |x_{\text{max}}| \le ||\mathbf{x}||_p \le n^\frac{1}{p} |x_{\text{max}}|
|
||||
Let $x_{\text{max}}$ be the component of $\mathbf{x}\in ℝ^n$ with the largest absolute value. Then always
|
||||
$$ \lvert x_{\text{max}}\rvert \le \lVert\mathbf{x}\rVert_p \le n^\frac{1}{p} \lvert x_{\text{max}}\rvert
|
||||
$$
|
||||
(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
|
||||
It follows that
|
||||
$$
|
||||
\lim_{p \rightarrow \infty} ||\mathbf{x}||_p = |x_{\text{max}}| =: ||\mathbf{x}||_\infty.
|
||||
\lim_{p \rightarrow \infty} \lVert\mathbf{x}\rVert_p = \lvert x_{\text{max}}\rvert =: \lVert\mathbf{x}\rVert_\infty.
|
||||
$$
|
||||
:::
|
||||
|
||||
|
||||
In Julia definiert das `LinearAlgebra`-Paket eine Funktion `norm(v, p)`.
|
||||
In Julia, the `LinearAlgebra` package defines a function `norm(v, p)`.
|
||||
|
||||
```{julia}
|
||||
v = [3, 4]
|
||||
@@ -130,10 +147,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 numerical container. The sum $\sum \lvert x_i\rvert^p$ extends over *all* elements of the container.
|
||||
- Thus, for a matrix `norm(A)` is equal to the _Frobenius norm_ of the matrix `A`.
|
||||
|
||||
```{julia}
|
||||
A = [1 2 3
|
||||
@@ -144,12 +161,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,
|
||||
$\lVert\lambda \mathbf{x}\rVert = |\lambda|\cdot\lVert\mathbf{x}\rVert$, they are completely determined by the specification of the unit ball. Subadditivity of the norm (triangle inequality) is equivalent to the convexity of the unit ball
|
||||
(code visible by clicking).
|
||||
```{julia}
|
||||
#| code-fold: true
|
||||
#| fig-cap: "Einheitskugeln im $ℝ^2$ für verschiedene $p$-Normen: $p$=0.8; 1; 1.5; 2; 3.001 und 1000"
|
||||
#| fig-cap: "Unit balls in $ℝ^2$ for different $p$-norms: $p$=0.8; 1; 1.5; 2; 3.001 and 1000"
|
||||
using Plots
|
||||
|
||||
colors=[:purple, :green, :red, :blue,:aqua, :black]
|
||||
@@ -163,35 +180,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.
|
||||
We see that, $p\ge 1$ must hold so that the unit ball is convex and $\lVert.\rVert_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)` also works for parameters `p<1`.
|
||||
|
||||
|
||||
### 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
|
||||
\lVert A\rVert_p = \max_{\lVert\mathbf{v}\rVert_p=1} \lVert A\mathbf{v}\rVert_p
|
||||
$$
|
||||
:::
|
||||
|
||||
Induzierte Normen lassen sich für allgemeines $p$ nur schwer berechnen. Ausnahmen sind die Fälle
|
||||
Induced norms are difficult to calculate for general $p$. Exceptions are the cases
|
||||
|
||||
- $p=1$: Spaltensummennorm
|
||||
- $p=2$: Spektralnorm und
|
||||
- $p=\infty$: Zeilensummennorm
|
||||
- $p=1$: column sum norm
|
||||
- $p=2$: spectral norm and
|
||||
- $p=\infty$: row sum norm
|
||||
|
||||
Diese 3 Fälle sind in Julia in der Funktion `opnorm(A, p)` aus dem `LinearAlgebra`-Paket implementiert, wobei wieder `opnorm(A) = opnorm(A, 2)` gilt.
|
||||
These 3 cases are implemented in Julia in the function `opnorm(A, p)` from the `LinearAlgebra` package, where again `opnorm(A) = opnorm(A, 2)` holds.
|
||||
|
||||
```{julia}
|
||||
A = [ 0 1
|
||||
@@ -200,7 +217,7 @@ A = [ 0 1
|
||||
@show opnorm(A, 1) opnorm(A, Inf) opnorm(A, 2) opnorm(A);
|
||||
```
|
||||
|
||||
Das folgende Bild zeigt die Wirkung von $A$ auf Einheitsvektoren. Vektoren gleicher Farbe werden aufeinander abgebildet. (Code durch anklicken sichtbar):
|
||||
The following picture shows the effect of $A$ on unit vectors. Vectors of the same color are mapped onto each other. (Code visible by clicking):
|
||||
|
||||
```{julia}
|
||||
#| error: false
|
||||
@@ -214,16 +231,10 @@ CairoMakie.activate!(type = "svg")
|
||||
|
||||
```{julia}
|
||||
#| code-fold: true
|
||||
#| fig-cap: "Bild der Einheitskugel unter $v \\mapsto Av$ mit $||A||\\approx 2.088$"
|
||||
#| fig-cap: "Image of the unit ball under $v \\mapsto Av$ with $\\lVert A\\rVert\\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
|
||||
tri = BezierPath([
|
||||
MoveTo(Point2f(-0.5, -1)), LineTo(0, 0), LineTo(0.5, -1), ClosePath()
|
||||
])
|
||||
|
||||
A = [ 0 1
|
||||
1.2 1.5 ]
|
||||
|
||||
@@ -241,60 +252,60 @@ Auv = A * [u,v]
|
||||
fig2 = Figure(size=(800, 400))
|
||||
lines(fig2[1, 1], xs, ys, color=t, linewidth=5, colormap=:hsv, axis=(; aspect = 1, limits=(-2,2, -2,2),
|
||||
title=L"$\mathbf{v}$", titlesize=30))
|
||||
arrows!(fig2[1,1], x, y, u, v, arrowsize=10, arrowhead=tri, colormap=:hsv, linecolor=range(0,11), linewidth=3)
|
||||
arrows2d!(fig2[1,1], x, y, u, v, tipwidth=10, colormap=:hsv, shaftcolor=range(0,11), shaftwidth=3)
|
||||
|
||||
Legend(fig2[1,2], MarkerElement[], String[], L"⟹", width=40, height=30, titlesize=30, framevisible=false)
|
||||
|
||||
lines(fig2[1,3], Axys[1], Axys[2], color=t, linewidth=5, colormap=:hsv, axis=(; aspect=1, limits=(-2,2, -2,2),
|
||||
title=L"$A\mathbf{v}$", titlesize=30))
|
||||
arrows!(fig2[1,3], x, y, Auv[1], Auv[2], arrowsize=10, arrowhead=tri, colormap=:hsv, linecolor=range(0,11),
|
||||
linewidth=3)
|
||||
arrows2d!(fig2[1,3], x, y, Auv[1], Auv[2], tipwidth=10, colormap=:hsv, shaftcolor=range(0,11),
|
||||
shaftwidth=3)
|
||||
|
||||
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
|
||||
\text{cond}_p(A) = \lVert A\rVert_p \cdot \lVert A^{-1}\rVert_p
|
||||
$$
|
||||
|
||||
```{julia}
|
||||
@show cond(A, 1) cond(A, 2) cond(A) cond(A, Inf);
|
||||
```
|
||||
|
||||
## Matrixfaktorisierungen
|
||||
## Matrix Factorizations
|
||||
|
||||
Basisaufgaben der numerischen linearen Algebra:
|
||||
The 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 $\lVert A\mathbf{x} - \mathbf{b}\rVert$.
|
||||
- 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
|
||||
- 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 Gaussian elimination:
|
||||
|
||||
:::{.content-visible unless-format="typst"}
|
||||
$$
|
||||
A=\left[
|
||||
\begin{array}{ccc}
|
||||
@@ -303,10 +314,10 @@ A=\left[
|
||||
-2 & 1 & 5
|
||||
\end{array}\right]
|
||||
~ \begin{array}{c}
|
||||
~\\
|
||||
Z_2 \mapsto Z_2 \mathbin{\color{red}-}\textcolor{red}{3} Z_1\\
|
||||
Z_3 \mapsto Z_3 + \textcolor{red}{2} Z_1
|
||||
\end{array} \quad \Longrightarrow\
|
||||
~\\
|
||||
Z_2 \mapsto Z_2 \mathbin{\color{red}-}\textcolor{red}{3} Z_1\\
|
||||
Z_3 \mapsto Z_3 + \textcolor{red}{2} Z_1
|
||||
\end{array} \quad \Longrightarrow\
|
||||
\left[
|
||||
\begin{array}{ccc}
|
||||
1 &2 &2 \\
|
||||
@@ -314,10 +325,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 \\
|
||||
@@ -325,6 +336,44 @@ A=\left[
|
||||
& & 8
|
||||
\end{array}\right] = U
|
||||
$$
|
||||
:::
|
||||
|
||||
:::{.content-hidden unless-format="typst"}
|
||||
```{=typst}
|
||||
$
|
||||
A = mat(
|
||||
1, 2, 2;
|
||||
3, -4, 4;
|
||||
-2, 1, 5; delim:"["
|
||||
)
|
||||
script(vec(
|
||||
#h(0pt),#h(0pt),#h(0pt),
|
||||
Z_2 arrow.bar Z_2 text(fill:#red, -) text(fill:#red, 3) Z_1,
|
||||
Z_3 arrow.bar Z_3 + text(fill:#red, 2) Z_1, delim:#none
|
||||
))
|
||||
&arrow.double.long
|
||||
mat(
|
||||
1, 2, 2;
|
||||
, -10, -2;
|
||||
, 5, 9
|
||||
)
|
||||
script(vec(
|
||||
#h(0pt),
|
||||
#h(0pt),
|
||||
#h(0pt),#h(0pt),
|
||||
Z_3 arrow.bar Z_3 + text(fill:#red, 1/2) Z_2, delim:#none
|
||||
))
|
||||
&arrow.double.long
|
||||
mat(
|
||||
1, 2, 2;
|
||||
, -10, -2;
|
||||
, , 8
|
||||
) = U
|
||||
$
|
||||
```
|
||||
:::
|
||||
|
||||
:::{.content-visible unless-format="typst"}
|
||||
$$
|
||||
A = \left[
|
||||
\begin{array}{ccc}
|
||||
@@ -340,13 +389,31 @@ A = \left[
|
||||
& & 8
|
||||
\end{array}\right]
|
||||
$$
|
||||
:::
|
||||
|
||||
:::{.content-hidden unless-format="typst"}
|
||||
```{=typst}
|
||||
$
|
||||
A = mat(
|
||||
1,,;
|
||||
text(fill:#red, +3),1,;
|
||||
text(fill:#red, -2),text(fill:#red, -1/2),1
|
||||
) dot.c
|
||||
mat(
|
||||
1,2,3;
|
||||
,-10,-2;
|
||||
,,8
|
||||
)
|
||||
$
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
- 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$.
|
||||
- In practice, it is often necessary to solve $A\mathbf{x}=\mathbf{b}$ for a fixed matrix $A$ and multiple right-hand sides $\mathbf{b}$.
|
||||
- The factorization of $A$, which has a cubic complexity $\sim n^3$ relative to the size $n$ of the matrix, needs to be performed only once.
|
||||
- For each subsequent right-hand side $\mathbf{b}$, the forward and backward substitution steps have quadratic complexity $\sim n^2$.
|
||||
|
||||
Das `LinearAlgebra`-Paket von Julia enthält zur Berechnung einer LU-Zerlegung die Funktion `lu(A, options)`:
|
||||
The `LinearAlgebra` package of Julia contains the function `lu(A, options)` for calculating an LU decomposition:
|
||||
```{julia}
|
||||
A = [ 1 2 2
|
||||
3 -4 4
|
||||
@@ -361,7 +428,9 @@ display(U)
|
||||
|
||||
#### Pivoting
|
||||
|
||||
Sehen wir uns einen Schritt der Gauß-Elimination an:
|
||||
Let's look at one step of Gaussian elimination:
|
||||
|
||||
:::{.content-visible unless-format="typst"}
|
||||
$$
|
||||
\left[
|
||||
\begin{array}{cccccc}
|
||||
@@ -375,37 +444,64 @@ $$
|
||||
\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.
|
||||
:::
|
||||
|
||||
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:
|
||||
:::{.content-hidden unless-format="typst"}
|
||||
```{=typst}
|
||||
$
|
||||
mat(
|
||||
*, dots.c, *, *, dots.c, *;
|
||||
, dots.down, dots.v, dots.v, , dots.v;
|
||||
, , *, *, dots.c, *;
|
||||
, , , text(fill: #red, a_(i j)), dots.c, a_(i n);
|
||||
, , , text(fill: #blue, a_(i+1, j)), dots.c, a_(i+1, n);
|
||||
, , , text(fill: #blue, dots.v), , dots.v;
|
||||
, , , text(fill: #blue, a_(m j)), dots.c, a_(m n)
|
||||
)
|
||||
$
|
||||
```
|
||||
:::
|
||||
|
||||
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* ${\color{red}a_{ij}}$ is not zero. If ${\color{red}a_{ij}}=0$, we must exchange rows to fix this.
|
||||
|
||||
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 to ensure that
|
||||
|
||||
:::{.content-visible unless-format="typst"}
|
||||
$$
|
||||
|\textcolor{red}{a_{ij}}|=\max_{k=i,...,m} |\textcolor{blue}{a_{kj}}|
|
||||
$$
|
||||
:::
|
||||
|
||||
:::{.content-hidden unless-format="typst"}
|
||||
```{=typst}
|
||||
$
|
||||
|text(fill:#red, a_(i j))| = max_(k=1,...,m) | text(fill:#blue, a_(k j)) |
|
||||
$
|
||||
```
|
||||
:::
|
||||
|
||||
#### 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 = P A$$
|
||||
Julia's syntax of indirect indexing allows applying the row permutation with the notation `A[p,:]`:
|
||||
```{julia}
|
||||
display(A)
|
||||
display(A[p,:])
|
||||
@@ -413,28 +509,27 @@ 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" which perfoms implicitely an appropriate matrix factorization:
|
||||
```{julia}
|
||||
A \ b
|
||||
```
|
||||
Dabei wird implizit eine geeignete Faktorisierung durchgeführt, deren Ergebnis allerdings nicht abgespeichert.
|
||||
|
||||
|
||||
### 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). Conversion to a "normal" matrix is, as always, possible with `collect()` if needed.
|
||||
```{julia}
|
||||
F = qr(A)
|
||||
@show typeof(F) typeof(F.Q)
|
||||
@@ -442,13 +537,10 @@ display(collect(F.Q))
|
||||
display(F.R)
|
||||
```
|
||||
|
||||
### Passende Faktorisierung
|
||||
|
||||
|
||||
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:
|
||||
### Appropriate Factorization
|
||||
|
||||
|
||||
The function `factorize()` returns a factorization appropriate for the given matrix type; see [documentation](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#LinearAlgebra.factorize) for details. This factorization can subsequently be utilized for multiple right-hand sides $\mathbf{b_1}, \mathbf{b_2},\ldots$.
|
||||
```{julia}
|
||||
Af = factorize(A)
|
||||
```
|
||||
@@ -462,4 +554,3 @@ Af \ [1, 2, 3]
|
||||
```{julia}
|
||||
Af \ [5, 7, 9]
|
||||
```
|
||||
|
||||
|
||||
@@ -2,7 +2,23 @@
|
||||
engine: julia
|
||||
---
|
||||
|
||||
# Ein- und Ausgabe
|
||||
```{julia}
|
||||
#| error: false
|
||||
#| echo: false
|
||||
#| output: false
|
||||
using InteractiveUtils
|
||||
import QuartoNotebookWorker
|
||||
Base.stdout = QuartoNotebookWorker.with_context(stdout)
|
||||
```
|
||||
|
||||
```{julia}
|
||||
#| error: false
|
||||
#| echo: false
|
||||
#| output: false
|
||||
flush(stdout)
|
||||
```
|
||||
|
||||
# Input and Output
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -22,51 +38,49 @@ Base.active_module() = myactive_module()
|
||||
```
|
||||
|
||||
|
||||
## Konsole
|
||||
## Console
|
||||
|
||||
Das Betriebssystem stellt für ein Programm üblicherweise 3 Kanäle _(streams)_ zur Verfügung:
|
||||
The operating system typically provides three channels (_streams_) for a program:
|
||||
|
||||
- Standardeingabekanal `stdin`
|
||||
- Standardausgabekanal `stdout` und
|
||||
- Standardfehlerausgabekanal `stderr`.
|
||||
- Standard input (`stdin`)
|
||||
- Standard output (`stdout`)
|
||||
- Standard error (`stderr`)
|
||||
|
||||
Wenn das Programm in einem Terminal (oder Konsole bzw. Shell) gestartet wird, kann das Programm über `stdin` die Tastatureingaben
|
||||
einlesen und Ausgaben über `stdout` sowie `stdout` erscheinen im Terminal.
|
||||
When executed in a terminal, console, or shell, the program reads keyboard input through `stdin` and outputs to the terminal via `stdout` and `stderr`.
|
||||
|
||||
|
||||
- Schreiben nach `stdout`: `print()`,`println()`,`printstyled()`
|
||||
- Schreiben nach `stderr`: `print(strerr,...)`, `println(stderr,...)`, `printstyled(stderr,...)`
|
||||
- Lesen von `stdin`: `readline()`
|
||||
- Writing to `stdout`: `print()`, `println()`, `printstyled()`
|
||||
- Writing to `stderr`: `print(stderr,...)`, `println(stderr,...)`, `printstyled(stderr,...)`
|
||||
- Reading from `stdin`: `readline()`
|
||||
|
||||
|
||||
### Eingaben
|
||||
### Input
|
||||
|
||||
Die Sprache _Python_ stellt eine Funktion `input()` zur Verfügung:
|
||||
The _Python_ language provides an `input()` function:
|
||||
```{.python}
|
||||
ans = input("Bitte eine positive Zahl eingeben!")
|
||||
ans = input("Please enter a positive number!")
|
||||
```
|
||||
Die Funktion gibt den Prompt aus, wartet auf eine Eingabe und liefert die
|
||||
Eingabe als `string` zurück.
|
||||
It prints the prompt, waits for input, and returns a `string`.
|
||||
|
||||
|
||||
In Julia kann man diese Funktion so implementieren:
|
||||
In Julia, you can implement this function as follows:
|
||||
|
||||
```{julia}
|
||||
function input(prompt = "Eingabe:")
|
||||
function input(prompt = "Input:")
|
||||
println(prompt)
|
||||
flush(stdout)
|
||||
return chomp(readline())
|
||||
end
|
||||
```
|
||||
|
||||
**Anmerkungen**
|
||||
**Comments**
|
||||
|
||||
- Schreibanweisungen werden von modernen Betriebssystemen gebuffert. Mit `flush(stdout)` wird die Leerung des Buffers und sofortige Schreiboperation erzwungen.
|
||||
- `readline()` liefert einen String zurück, der mit einer Newline `\n` endet. Die Funktion `chomp()` entfernt einen eventuellen Zeilenumbruch vom Ende eines Strings.
|
||||
- Write operations are buffered by modern operating systems. `flush(stdout)` empties the buffer and forces the write operation to complete immediately.
|
||||
- `readline()` returns a string ending with a newline (`\n`). The function `chomp()` removes a trailing line break from the string.
|
||||
|
||||
```{julia}
|
||||
#| eval: false
|
||||
a = input("Bitte 2 Zahlen eingeben!")
|
||||
a = input("Please enter two numbers!")
|
||||
```
|
||||
```{julia}
|
||||
#| echo: false
|
||||
@@ -74,73 +88,61 @@ a = "34 56"
|
||||
```
|
||||
|
||||
|
||||
### Verarbeitung der Eingabe
|
||||
### Processing the Input
|
||||
|
||||
> `split(str)` zerlegt einen String in "Wörter" und liefert einen _(array of strings)_:
|
||||
> `split(str)` splits a string into "words", returning a string array:
|
||||
|
||||
```{julia}
|
||||
av = split(a)
|
||||
```
|
||||
|
||||
|
||||
> `parse(T, str)` versucht, `str` in den Typ `T` umzuwandeln:
|
||||
> `parse(T, str)` tries to convert `str` to type `T`:
|
||||
|
||||
|
||||
```{julia}
|
||||
v = parse.(Int, av)
|
||||
```
|
||||
|
||||
`parse()` erzeugt einen Fehler, wenn der String sich nicht als Wertangabe von Typ `T` parsen lässt. Man kann den Fehler mit
|
||||
`try/catch` abfangen oder die Funktion `tryparse(T, str)` verwenden, die in so einem Fall `nothing` zurückgibt - worauf man dann
|
||||
z.B. mit `isnothing()` testen kann.
|
||||
`parse()` throws an error if the string cannot be parsed as type `T`. You can catch the error with
|
||||
`try/catch`, or use `tryparse(T, str)`, which returns `nothing` in such cases. Test the result with `isnothing()`.
|
||||
|
||||
|
||||
|
||||
### Einzelne Tastenanschläge einlesen
|
||||
## Formatted Output with the `Printf` Macro
|
||||
|
||||
- `readline()` u.ä. warten auf den Abschluss der Eingabe durch Drücken der `Enter`-Taste.
|
||||
- Techniken zum Einlesen einzelner _keystrokes_ findet man hier:
|
||||
|
||||
- [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)
|
||||
|
||||
You often need to output numbers or strings with strict formatting: total length, decimal places, alignment, etc.
|
||||
|
||||
|
||||
|
||||
## Formatierte Ausgabe mit dem `Printf`-Makro
|
||||
|
||||
Oft möchte man Zahlen oder Strings mit einer strikten Formatvorgabe - Gesamtlänge, Nachkommastellen, rechts/linksbündig usw - ausgeben.
|
||||
|
||||
Dazu definiert das Paket `Printf` die Makros `@sprintf` und `@printf`, welche sehr ähnlich wie die gleichnamigen C-Funktionen arbeiten.
|
||||
For this purpose, the `Printf` package defines the macros `@sprintf` and `@printf`, which work similarly to the corresponding C functions.
|
||||
|
||||
```{julia}
|
||||
using Printf
|
||||
|
||||
x = 123.7876355638734
|
||||
|
||||
@printf("Ausgabe rechtsbündig mit max. 10 Zeichen Platz und 3 Nachkommastellen: x= %10.3f", x)
|
||||
@printf("Output right-aligned with max. 10 character width and 3 decimal places: x = %10.3f", x)
|
||||
```
|
||||
|
||||
|
||||
Das erste Argument ist ein String, der Platzhalter (hier: `%10.3`) für auszugebende Variablen enthält; gefolgt von diesen Variablen als weitere Argumente.
|
||||
The first argument is a string containing placeholders (here: `%10.3f`) for the variables, followed by the variables themselves.
|
||||
|
||||
Platzhalter haben die Form
|
||||
Placeholders have the form:
|
||||
```
|
||||
%[flags][width][.precision]type
|
||||
%[flags][width][.precision]type
|
||||
```
|
||||
wobei die Angaben in eckigen Klammern alle optional sind.
|
||||
where entries in square brackets are optional.
|
||||
|
||||
**Typangaben im Platzhalter**
|
||||
**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`|
|
||||
|`%o`| `integer, octal (base 8)`|
|
||||
|`%x, %X`| `integer, hexadecimal (base 16), digits 0-9a-f or 0-9A-F`|
|
||||
|`%f`| `floating point`|
|
||||
|`%e`| `floating point, scientific notation`|
|
||||
|`%g`| `floating point, %f or %e as appropriate`|
|
||||
|
||||
: {.striped .hover}
|
||||
|
||||
@@ -149,9 +151,9 @@ wobei die Angaben in eckigen Klammern alle optional sind.
|
||||
|
||||
| | |
|
||||
|:----|:-----|
|
||||
|Pluszeichen| rechtsbündig (Standard)|
|
||||
|Minuszeichen| linksbündig|
|
||||
|Null| mit führenden Nullen|
|
||||
|Plus sign| right-aligned (default) |
|
||||
|Minus sign| left-aligned |
|
||||
|Zero| adds leading zeros |
|
||||
|
||||
: {.striped .hover}
|
||||
|
||||
@@ -159,37 +161,37 @@ wobei die Angaben in eckigen Klammern alle optional sind.
|
||||
**Width**
|
||||
|
||||
```
|
||||
Anzahl der minimal verwendeten Zeichen (wenn nötig, werden auch mehr genommen)
|
||||
Minimum number of characters used (more will be taken if necessary)
|
||||
```
|
||||
|
||||
|
||||
### Beispiele:
|
||||
### Examples
|
||||
|
||||
|
||||
```{julia}
|
||||
using Printf # Paket laden nicht vergessen!
|
||||
using Printf # Load the package first
|
||||
```
|
||||
|
||||
|
||||
```{julia}
|
||||
@printf("|%s|", "Hallo") # string mit Platzhalter für String
|
||||
@printf("|%s|", "Hello") # string with placeholder for string
|
||||
```
|
||||
Die senkrechten Striche sind nicht Teil des Platzhalters. Sie sollen die Begrenzung des Ausgabefeldes anzeigen.
|
||||
The vertical bars are not part of the placeholder; they indicate the output field boundaries.
|
||||
|
||||
|
||||
```{julia}
|
||||
@printf("|%10s|", "Hallo") # Minimallänge, rechtsbündig
|
||||
@printf("|%10s|", "Hello") # Minimum length, right-aligned
|
||||
```
|
||||
|
||||
|
||||
```{julia}
|
||||
@printf("|%-10s|", "Hallo") # linksbündig
|
||||
@printf("|%-10s|", "Hello") # left-aligned
|
||||
```
|
||||
|
||||
|
||||
```{julia}
|
||||
@printf("|%3s|", "Hallo") # Längenangabe kann überschritten werden
|
||||
# besser eine 'kaputt formatierte' Tabelle als falsche Werte!
|
||||
@printf("|%3s|", "Hello") # Length specification can be exceeded
|
||||
# Better a badly formatted table than wrong values!
|
||||
```
|
||||
|
||||
|
||||
@@ -198,37 +200,34 @@ j = 123
|
||||
k = 90019001
|
||||
l = 3342678
|
||||
|
||||
@printf("j= %012i, k= %-12i, l = %12i", j, k, l) # 0-Flag für führende Nullen
|
||||
@printf("j = %012i, k = %-12i, l = %12i", j, k, l) # 0-flag for leading zeros
|
||||
```
|
||||
|
||||
`@printf` und `@sprintf` können wie alle Makros wie Funktionen aufgerufen werden:
|
||||
|
||||
`@printf` and `@sprintf` can be called like functions:
|
||||
|
||||
```{julia}
|
||||
@printf("%i %i", 22, j)
|
||||
```
|
||||
|
||||
-- oder wie Makros, also ohne Funktionsklammern und ohne Komma:
|
||||
or as macros, i.e., without parentheses or commas:
|
||||
|
||||
|
||||
```{julia}
|
||||
@printf "%i %i" 22 j
|
||||
```
|
||||
|
||||
`@printf` kann als erstes Argument noch einen Stream übergeben bekommen.
|
||||
`@printf` can take a stream as its first argument; otherwise, the argument list consists of:
|
||||
|
||||
Ansonsten besteht die Argumentliste aus
|
||||
|
||||
- Formatstring mit Platzhaltern
|
||||
- Variablen in der Reihenfolge der Platzhalter, in Anzahl und Typ zu den Platzhaltern passend
|
||||
- format string with placeholders
|
||||
- variables matching the placeholders in number and type
|
||||
|
||||
|
||||
```{julia}
|
||||
@printf(stderr, "Erstes Resultat: %i %s\nZweites Resultat %i",
|
||||
j, "(geschätzt)" ,k)
|
||||
@printf(stderr, "First result: %i %s\nSecond result %i",
|
||||
j, "(estimated)", k)
|
||||
```
|
||||
|
||||
Das Makro `@sprintf` druckt nichts, sondern liefert den ausgefüllten formatierten String zurück:
|
||||
The macro `@sprintf` does not print; it returns the formatted string:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -240,55 +239,54 @@ str = @sprintf("x = %10.6f", π );
|
||||
str
|
||||
```
|
||||
|
||||
### Formatierung der Gleitkommazahlen:
|
||||
### Formatting Floating-Point Numbers
|
||||
|
||||
Bedeutung des _Precision_-Wertes:
|
||||
The _precision_ value specifies:
|
||||
|
||||
- `%f` und `%e`-Format: maximale Anzahl der Nachkommastellen
|
||||
- `%g`-Format: maximale Anzahl von ausgegebenen Ziffern (Vor- + Nachkommastellen)
|
||||
- `%f` and `%e` formats: maximum decimal places
|
||||
- `%g` format: maximum total digits (integer part + decimal places)
|
||||
|
||||
|
||||
```{julia}
|
||||
x = 123456.7890123456
|
||||
|
||||
@printf("%20.4f %20.4e", x, x) # 4 Nachkommastellen
|
||||
@printf("%20.4f %20.4e", x, x) # 4 decimal places
|
||||
```
|
||||
|
||||
|
||||
```{julia}
|
||||
@printf("%20.7f %20.7e", x, x) # 7 Nachkommastellen
|
||||
@printf("%20.7f %20.7e", x, x) # 7 decimal places
|
||||
```
|
||||
|
||||
|
||||
```{julia}
|
||||
@printf("%20.7g %20.4g", x, x) # insgesamt 7 bzw. 4 Stellen
|
||||
@printf("%20.7g %20.4g", x, x) # 7 and 4 digits total, respectively
|
||||
```
|
||||
|
||||
## Dateioperationen
|
||||
## File Operations
|
||||
|
||||
Dateien werden
|
||||
Files are handled by:
|
||||
|
||||
- geöffnet $\Longrightarrow$ dabei ensteht ein neues _stream_-Objekt (zusätzlich zu `stdin, stdout, stderr`)
|
||||
- dann kann dieser _stream_ gelesen und geschrieben werden
|
||||
- geschlossen $\Longrightarrow$ _stream_-Objekt wird von Datei getrennt
|
||||
|
||||
```{.julia}
|
||||
stream = open(path, mode)
|
||||
```
|
||||
|
||||
- path: Dateiname/pfad
|
||||
- mode:
|
||||
- Opening $\Longrightarrow$ creation of a new _stream_ object (in addition to `stdin`, `stdout`, `stderr`)
|
||||
- Reading from and writing to this _stream_
|
||||
- Closing $\Longrightarrow$ detachment of the _stream_ object from the file
|
||||
|
||||
```
|
||||
"r" read, öffnet am Dateianfang
|
||||
"w" write, öffnet am Dateianfang (Datei wird neu angelegt oder überschrieben)
|
||||
"a" append, öffnet zum Weiterschreiben am Dateiende
|
||||
```
|
||||
```
|
||||
stream = open(path, mode)
|
||||
```
|
||||
|
||||
- path: filename or 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
|
||||
```
|
||||
|
||||
Schreiben wir mal eine Datei:
|
||||
Let's write a file:
|
||||
|
||||
```{julia}
|
||||
file = open("datei.txt", "w")
|
||||
file = open("myfile.txt", "w")
|
||||
```
|
||||
|
||||
|
||||
@@ -298,7 +296,7 @@ file = open("datei.txt", "w")
|
||||
|
||||
|
||||
```{julia}
|
||||
println(file, " zweite Zeile")
|
||||
println(file, " second line")
|
||||
```
|
||||
|
||||
|
||||
@@ -306,59 +304,58 @@ println(file, " zweite Zeile")
|
||||
close(file)
|
||||
```
|
||||
|
||||
Schauen wir uns die Datei an:
|
||||
Let's look at the file:
|
||||
|
||||
```{julia}
|
||||
;cat datei.txt
|
||||
;cat myfile.txt
|
||||
```
|
||||
|
||||
...und jetzt öffnen wir sie wieder zum Einlesen:
|
||||
...and now we open it again for reading:
|
||||
|
||||
```{julia}
|
||||
stream = open("datei.txt", "r")
|
||||
stream = open("myfile.txt", "r")
|
||||
```
|
||||
|
||||
`readlines(stream)` liefert alle Zeilen einer Textdatei als Vector von Strings.
|
||||
`readlines(stream)` returns all lines of a text file as a string vector.
|
||||
|
||||
`eachline(stream)` liefert einen Iterator über die Zeilen der Datei.
|
||||
`eachline(stream)` returns an iterator over the file lines.
|
||||
|
||||
|
||||
```{julia}
|
||||
n = 0
|
||||
for line in eachline(stream) # Lese zeilenweise
|
||||
for line in eachline(stream) # Read line by line
|
||||
n += 1
|
||||
println(n, line) # Drucke mit Zeilennummer
|
||||
println(n, line) # Print with line number
|
||||
end
|
||||
close(stream)
|
||||
```
|
||||
|
||||
## Pakete für Dateiformate
|
||||
## Packages for File Formats
|
||||
|
||||
Für die Ein- und Ausgabe in den verschiedensten Dateiformaten existieren Julia-Pakete, z.B.
|
||||
Julia packages for various file formats include:
|
||||
|
||||
- [PrettyTables.jl](https://ronisbr.github.io/PrettyTables.jl/stable/) Ausgabe von formatierten Tabellen
|
||||
- [DelimitedFiles.jl](https://docs.julialang.org/en/v1/stdlib/DelimitedFiles/) Ein- und Ausgabe von Matrizen u.ä.
|
||||
- [CSV.jl](https://csv.juliadata.org/stable/) Ein- und Ausgabe von Dateien mit "comma-separated values" u.ä.
|
||||
- [XLSX.jl](https://felipenoris.github.io/XLSX.jl/stable/tutorial/) Ein- und Ausgabe von Excel-Dateien
|
||||
- [PrettyTables.jl](https://ronisbr.github.io/PrettyTables.jl/stable/) Output formatted tables
|
||||
- [DelimitedFiles.jl](https://docs.julialang.org/en/v1/stdlib/DelimitedFiles/) Read and write matrices
|
||||
- [CSV.jl](https://csv.juliadata.org/stable/) Read and write CSV files
|
||||
- [XLSX.jl](https://felipenoris.github.io/XLSX.jl/stable/tutorial/) Read and write Excel files
|
||||
|
||||
und viele andere mehr...
|
||||
and many more...
|
||||
|
||||
### DelimitedFiles.jl
|
||||
|
||||
Dieses Paket ermöglicht das bequeme Abspeichern/Einlesen von Matrizen. Dazu stellt es die Funktionen `writedlm()` und `readdlm()` zur
|
||||
Verfügung.
|
||||
This package offers convenient functions for saving and reading matrices using `writedlm()` and `readdlm()`.
|
||||
|
||||
```{julia}
|
||||
using DelimitedFiles
|
||||
```
|
||||
|
||||
|
||||
Wir erzeugen eine 200×3-Matrix von Zufallszahlen
|
||||
Generate a 200×3 matrix of random numbers:
|
||||
```{julia}
|
||||
A = rand(200,3)
|
||||
```
|
||||
|
||||
und speichern diese
|
||||
and save it:
|
||||
```{julia}
|
||||
f = open("data2.txt", "w")
|
||||
writedlm(f, A)
|
||||
@@ -366,23 +363,21 @@ close(f)
|
||||
```
|
||||
|
||||
|
||||
Die geschriebene Datei fängt so an:
|
||||
The written file starts like this:
|
||||
|
||||
```{julia}
|
||||
;head data2.txt
|
||||
```
|
||||
|
||||
|
||||
Das Wiedereinlesen ist noch einfacher:
|
||||
Reading it back is simple:
|
||||
```{julia}
|
||||
B = readdlm("data2.txt")
|
||||
```
|
||||
|
||||
|
||||
Noch ein Punkt: Beim Umgang mit Dateien wird in Julia oft die `do`-Notation verwendet, s. @sec-do.
|
||||
Dazu nutzt man, dass `open()` auch Methoden hat, bei denen das 1. Argument eine `function(iostream)` ist.
|
||||
Diese wird dann auf den _stream_ angewendet und dieser abschliessend automatisch geschlossen. Die `do`-Notation erlaubt es,
|
||||
diese Funktion anonym nach dem `do` zu definieren:
|
||||
|
||||
In Julia, the `do` notation is frequently utilized for file handling (see @sec-do). The `open()` function includes methods where the first argument is a `function(iostream)`. This function is applied to the stream, which is automatically closed afterward. The `do` notation allows to define this function anonymously:
|
||||
|
||||
```{julia}
|
||||
open("data2.txt", "w") do io
|
||||
@@ -390,18 +385,16 @@ open("data2.txt", "w") do io
|
||||
end
|
||||
```
|
||||
|
||||
### CSV und DataFrames
|
||||
|
||||
- Das CSV-Format wird oft benutzt, um Tabellen in einer nicht nur mit MS Excel lesbaren Form zur Verfügung zu stellen.
|
||||
- Ein Beispiel ist die Wetter- und Klimadatenbank _Meteostat_.
|
||||
- Das Paket [DataFrames.jl](https://dataframes.juliadata.org/stable/) stellt Funktionen zum bequemen Umgang mit tabellarischen Daten
|
||||
zur Verfügung.
|
||||
### CSV and DataFrames
|
||||
|
||||
- The CSV format provides tables readable by MS Excel and other applications.
|
||||
- Example: the weather and climate database _Meteostat_.
|
||||
- The [DataFrames.jl](https://dataframes.juliadata.org/stable/) package handles tabular data conveniently.
|
||||
|
||||
|
||||
```{julia}
|
||||
using CSV, DataFrames, Downloads
|
||||
# Wetterdaten von Westerland, s. https://dev.meteostat.net/bulk/hourly.html
|
||||
# Weather data from Westerland (see https://dev.meteostat.net/bulk/hourly.html)
|
||||
|
||||
url = "https://bulk.meteostat.net/v2/hourly/10018.csv.gz"
|
||||
http_response = Downloads.download(url)
|
||||
@@ -409,25 +402,26 @@ file = CSV.File(http_response, header=false);
|
||||
```
|
||||
|
||||
|
||||
Die Daten sehen so aus:
|
||||
The data looks like this:
|
||||
|
||||
|
||||
```{julia}
|
||||
# https://dev.meteostat.net/bulk/hourly.html#endpoints
|
||||
#
|
||||
# Spalte 1 Datum
|
||||
# 2 Uhrzeit (Stunde)
|
||||
# 3 Temp
|
||||
# 5 Luftfeuchtigkeit
|
||||
# 6 Niederschlag
|
||||
# 8 Windrichtung
|
||||
# 9 Windstärke
|
||||
# Column 1 Date
|
||||
# 2 Time (hour)
|
||||
# 3 Temperature
|
||||
# 5 Humidity
|
||||
# 6 Precipitation
|
||||
# 8 Wind direction
|
||||
# 9 Wind speed
|
||||
|
||||
df = DataFrame(file)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
```{julia}
|
||||
#| error: false
|
||||
#| echo: false
|
||||
@@ -438,18 +432,18 @@ describe(df)
|
||||
|
||||
|
||||
|
||||
Zum bequemen Plotten und zum Umgang mit den Datums- und Zeitformaten in der Wettertabelle
|
||||
laden wir noch 2 Helferlein:
|
||||
|
||||
For convenient plotting and date/time handling, we load two packages:
|
||||
|
||||
```{julia}
|
||||
using StatsPlots, Dates
|
||||
```
|
||||
|
||||
|
||||
Wir erzeugen eine neue Spalte, die Datum (aus Spalte 1) und Uhrzeit (aus Spalte 2) kombiniert:
|
||||
We create a new column that combines date (from column 1) and time (from column 2):
|
||||
|
||||
```{julia}
|
||||
# neue Spalte mit Sp.1 und 2 (date & time) kombiniert
|
||||
# new column combining col. 1 and 2 (date & time)
|
||||
|
||||
df[!, :datetime] = DateTime.(df.Column1) .+ Hour.(df.Column2);
|
||||
```
|
||||
@@ -466,14 +460,12 @@ df[!, :datetime] = DateTime.(df.Column1) .+ Hour.(df.Column2);
|
||||
@df df plot(:datetime, :Column3)
|
||||
```
|
||||
|
||||
Und nun zum Plot:
|
||||
The resulting plot:
|
||||
|
||||
```{julia}
|
||||
@df df plot(:datetime, [:Column9, :Column6, :Column3],
|
||||
xlims = (DateTime(2023,9,1), DateTime(2024,5,30)),
|
||||
layout=(3,1), title=["Wind" "Regen" "Temp"],
|
||||
layout=(3,1), title=["Wind" "Rain" "Temp"],
|
||||
legend=:none, size=(800,800))
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,41 +10,41 @@ using InteractiveUtils
|
||||
```
|
||||
|
||||
|
||||
# Plots und Datenvisualisierung in Julia: _Plots.jl_
|
||||
# Plots and Data Visualization in Julia: _Plots.jl_
|
||||
|
||||
Es gibt zahlreiche Grafikpakete für Julia. Zwei oft genutzte sind [Makie.jl](https://docs.makie.org/stable/) und
|
||||
[Plots.jl](https://docs.juliaplots.org/latest/). Bevor wir diese genauer vorstellen, seien noch einige andere Pakete aufgelistet.
|
||||
Julia has numerous graphics packages. Two frequently used ones are [Makie.jl](https://docs.makie.org/stable/) and
|
||||
[Plots.jl](https://docs.juliaplots.org/latest/). Before presenting `Plots.jl` in detail, we list some others.
|
||||
|
||||
## Kurze Übersicht: einige Grafikpakete
|
||||
## Brief Overview: Some Graphics Packages
|
||||
|
||||
| Paket/Doku | Tutorial | Beispiele | Bemerkungen |
|
||||
| Package/Documentation | Tutorial | Examples | Remarks |
|
||||
|:----|:--|:--|:--------|
|
||||
|[Plots.jl](https://docs.juliaplots.org/latest/) | [Tutorial](https://docs.juliaplots.org/latest/tutorial/) | [Galerie](https://goropikari.github.io/PlotsGallery.jl/) | konzipiert als einheitliches Interface zu verschiedenen _backends_ (Grafikbibliotheken) |
|
||||
| [Makie.jl](https://docs.makie.org/stable/) | [Basic tutorial](https://docs.makie.org/v0.21/tutorials/basic-tutorial) | [Beautiful Makie](https://beautiful.makie.org/) | "data visualization ecosystem for Julia", Backends: Cairo (Vektorgrafik), OpenGL, WebGL |
|
||||
|[PlotlyJS.jl](http://juliaplots.org/PlotlyJS.jl/stable/) | [Getting started](https://plotly.com/julia/getting-started/)| [Examples](https://plotly.com/julia/plotly-fundamentals/)| Interface zur [Plotly](https://plotly.com/graphing-libraries/) Javascript-Grafikbibliothek |
|
||||
| [Gadfly.jl](https://gadflyjl.org/stable/)| [Tutorial](https://gadflyjl.org/stable/tutorial/) | [Galerie](https://github.com/GiovineItalia/Gadfly.jl?tab=readme-ov-file#gallery)| "a plotting and data visualization system written in Julia, influenced by R's [ggplot2](https://ggplot2.tidyverse.org/)" |
|
||||
| [Bokeh.jl](https://cjdoris.github.io/Bokeh.jl/stable/) | | [Galerie](https://cjdoris.github.io/Bokeh.jl/stable/gallery/)| Julia-Frontend für [Bokeh](https://bokeh.org/) |
|
||||
|[VegaLite.jl](https://www.queryverse.org/VegaLite.jl/stable/) | [Tutorial](https://www.queryverse.org/VegaLite.jl/stable/gettingstarted/tutorial/)| [Examples](https://www.queryverse.org/VegaLite.jl/stable/examples/examples_barcharts/)| Julia-Frontend für [Vega-Lite](https://vega.github.io/vega-lite/)|
|
||||
| [Luxor.jl](http://juliagraphics.github.io/Luxor.jl/stable/) |[Tutorial](https://juliagraphics.github.io/Luxor.jl/stable/tutorial/helloworld/)|[Examples](https://juliagraphics.github.io/Luxor.jl/stable/example/moreexamples/)| Allgemeine Vektorgrafik/Illustrationen |
|
||||
| [Javis.jl](https://juliaanimators.github.io/Javis.jl/stable/) |[Tutorials](https://juliaanimators.github.io/Javis.jl/stable/tutorials/)| [Examples](https://juliaanimators.github.io/Javis.jl/stable/examples/)| *Animierte* Vektorgrafik
|
||||
|[Plots.jl](https://docs.juliaplots.org/latest/) | [Tutorial](https://docs.juliaplots.org/latest/tutorial/) | [Gallery](https://docs.juliaplots.org/latest/gallery/gr/) | 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](https://juliagraphics.github.io/LuxorManual/stable/) |[Tutorial](https://juliagraphics.github.io/LuxorManual/stable/tutorial/helloworld/)|[Examples](https://juliagraphics.github.io/LuxorManual/stable/example/moreexamples/)| General vector graphics/illustrations |
|
||||
| [Javis.jl](https://juliaanimators.github.io/Javis.jl/stable/) |[Tutorials](https://juliaanimators.github.io/Javis.jl/stable/tutorials/)| [Examples](https://juliaanimators.github.io/Javis.jl/stable/examples/)| *Animated* vector graphics
|
||||
| [TidierPlots.jl](https://github.com/TidierOrg/TidierPlots.jl)| [Reference](https://tidierorg.github.io/TidierPlots.jl/latest/) || "is a 100% Julia implementation of the R package ggplot2 powered by Makie.jl"|
|
||||
|[PythonPlot.jl](https://github.com/JuliaPy/PythonPlot.jl)| |[Examples (in Python)](https://matplotlib.org/stable/gallery/index.html)| Interface zu Matplotlib (Python), 1:1-Übertragung der Python-API, deswegen s. [Matplotlib-Dokumentation](https://matplotlib.org/stable/api/pyplot_summary.html)
|
||||
|[PythonPlot.jl](https://github.com/JuliaPy/PythonPlot.jl)| |[Examples (in Python)](https://matplotlib.org/stable/gallery/index.html)| Interface to Matplotlib (Python), 1:1 transfer of the Python API, therefore see [Matplotlib documentation](https://matplotlib.org/stable/api/pyplot_summary.html)
|
||||
|
||||
: {.striped .hover}
|
||||
|
||||
<!--
|
||||
| [PyPlot.jl](https://github.com/JuliaPy/PyPlot.jl) | | [Examples](https://gist.github.com/gizmaa/7214002)| Interface zu Matplotlib (Python), 1:1-Übertragung der Python-API, deswegen s. [Matplotlib-Dokumentation](https://matplotlib.org/stable/) |
|
||||
| [PyPlot.jl](https://github.com/JuliaPy/PyPlot.jl) | | [Examples](https://gist.github.com/gizmaa/7214002)| Interface to Matplotlib (Python), 1:1 transfer of the Python API, therefore see [Matplotlib documentation](https://matplotlib.org/stable/) |
|
||||
-->
|
||||
|
||||
## Plots.jl
|
||||
|
||||
### Einfache Plots
|
||||
### Simple Plots
|
||||
|
||||
Die `plot()`-Funktion erwartet im einfachsten Fall:
|
||||
The `plot()` function expects, in the simplest case:
|
||||
|
||||
- als erstes Argument einen Vektor von $x$-Werten der Länge $n$ und
|
||||
- als zweites Argument einen gleichlangen Vektor mit den dazugehörigen $y$-Werten.
|
||||
- Das zweite Argument kann auch eine $n\times m$-Matrix sein. Dann wird jeder Spaltenvektor als eigener Graph (in der Docu `series` genannt) angesehen und es werden $m$ Kurven geplottet:
|
||||
- as the first argument a vector of $x$-values of length $n$ and
|
||||
- as the second argument a vector of the same length with the corresponding $y$-values.
|
||||
- The second argument can also be an $n\times m$ matrix. Each column is treated as a separate graph (called a `series` in the documentation), plotting $m$ curves:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -57,16 +57,16 @@ cx = @. cos(2x^(1/2))
|
||||
plot(x, [sx cx])
|
||||
```
|
||||
|
||||
- Die Funktionen des _Plots.jl_-Paketes wie `plot(), scatter(), contour(), heatmap(), histogram(), bar(),...` usw. starten alle einen neuen Plot.
|
||||
- Die Versionen `plot!(), scatter!(), contour!(), heatmap!(), histogram!(), bar!(),...` erweitern einen existierenden Plot:
|
||||
- Functions like `plot()`, `scatter()`, `contour()`, `heatmap()`, `histogram()`, `bar()`, etc. from _Plots.jl_ all start a new plot.
|
||||
- The versions `plot!()`, `scatter!()`, `contour!()`, `heatmap!()`, `histogram!()`, `bar!()`, etc. extend an existing plot:
|
||||
|
||||
```{julia}
|
||||
plot(x, sx) # plot only sin(x)
|
||||
plot!(x, cx) # add second graph
|
||||
plot!(x, sqrt.(x)) # add a thirth one
|
||||
plot!(x, sqrt.(x)) # add a third one
|
||||
```
|
||||
|
||||
Plots sind Objekte, die zugewiesen werden können. Dann kann man sie später weiterverwenden, kopieren und insbesondere mit den `!`-Funktionen erweitern:
|
||||
Plots are objects that can be assigned. Then they can be used later, copied, and in particular extended with the `!` functions:
|
||||
|
||||
```{julia}
|
||||
plot1 = plot(x, [sx cx])
|
||||
@@ -74,7 +74,7 @@ plot1a = deepcopy(plot1) # plot objects are quite deep structures
|
||||
scatter!(plot1, x, sx) # add scatter plot, i.e. unconnected data points
|
||||
```
|
||||
|
||||
Die kopierte Version `plot1a` ist durch die `scatter!`-Anweisung nicht modifiziert worden und kann unabhängig weiterverwendet werden:
|
||||
The copied version `plot1a` remains unchanged by the `scatter!` call and can be used independently:
|
||||
|
||||
```{julia}
|
||||
plot!(plot1a, x, 2 .* sx)
|
||||
@@ -82,7 +82,7 @@ plot!(plot1a, x, 2 .* sx)
|
||||
|
||||
|
||||
|
||||
Plot-Objekte kann man als Grafikdateien (PDF, SVG, PNG,...) abspeichern:
|
||||
Plot objects can be saved as graphics files (PDF, SVG, PNG, etc.):
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -94,13 +94,13 @@ savefig(plot1, "plot.png")
|
||||
;ls -l plot.png
|
||||
```
|
||||
|
||||
Plot-Objekte können auch als Teilplot in andere Plots eingefügt werden, siehe Abschnitt @sec-subplot.
|
||||
Plot objects can also be inserted as subplots into other plots, see section @sec-subplot.
|
||||
|
||||
|
||||
|
||||
### Funktionsplots
|
||||
### Function Plots
|
||||
|
||||
Man kann `plot()` auch eine Funktion und einen Vektor mit $x$-Werten übergeben:
|
||||
`plot()` can also be passed a function and a vector of $x$-values:
|
||||
|
||||
```{julia}
|
||||
# https://mzrg.com/math/graphs.shtml
|
||||
@@ -109,9 +109,9 @@ f(x) = abs(sin(x^x)/2^((x^x-π/2)/π))
|
||||
|
||||
plot(f, 0:0.01:3)
|
||||
```
|
||||
|
||||
|
||||
|
||||
Die parametrische Form $x = x(t),\ y = y(t)$ kann durch die Übergabe von zwei Funktionen und einen Vektor von $t$-Werten an `plot()` gezeichnet werden.
|
||||
The parametric form $x = x(t),\ y = y(t)$ is plotted by passing two functions and a vector of $t$-values to `plot()`.
|
||||
|
||||
```{julia}
|
||||
# https://en.wikipedia.org/wiki/Butterfly_curve_(transcendental)
|
||||
@@ -123,16 +123,15 @@ plot(xt, yt, 0:0.01:12π)
|
||||
```
|
||||
|
||||
|
||||
### Plot-Themen
|
||||
### Plot Themes
|
||||
|
||||
> "PlotThemes is a package to spice up the plots made with Plots.jl."\
|
||||
Hier geht es zur illustrierten [Liste der Themen](https://docs.juliaplots.org/stable/generated/plotthemes/)
|
||||
> "PlotThemes is a package to spice up plots made with Plots.jl."\
|
||||
See the illustrated [list of themes](https://docs.juliaplots.org/stable/generated/plotthemes/)
|
||||
|
||||
oder:
|
||||
```{julia}
|
||||
using PlotThemes
|
||||
|
||||
# Liste der Themen
|
||||
# list of themes
|
||||
keys(PlotThemes._themes)
|
||||
```
|
||||
|
||||
@@ -149,48 +148,48 @@ plot(x, [sx cx 1 ./ (1 .+ x)])
|
||||
```
|
||||
|
||||
|
||||
### Plot-Attribute
|
||||
### Plot Attributes
|
||||
|
||||
Die Funktionen des `Plots.jl`-Paketes haben eine große Anzahl von Optionen.
|
||||
`Plots.jl` teilt die Attribute in 4 Gruppen ein:
|
||||
The `Plots.jl` functions have numerous options.
|
||||
Attributes are divided into 4 groups:
|
||||
|
||||
::::{.cell}
|
||||
```{julia}
|
||||
#| output: asis
|
||||
plotattr(:Plot) # Attribute für den Gesamtplot
|
||||
plotattr(:Plot) # attributes for the overall plot
|
||||
```
|
||||
::::
|
||||
|
||||
::::{.cell}
|
||||
```{julia}
|
||||
#| output: asis
|
||||
plotattr(:Subplot) # Attribute für einen Teilplot
|
||||
plotattr(:Subplot) # attributes for a subplot
|
||||
```
|
||||
::::
|
||||
|
||||
::::{.cell}
|
||||
```{julia}
|
||||
#| output: asis
|
||||
plotattr(:Axis) # Attribute für eine Achse
|
||||
plotattr(:Axis) # attributes for an axis
|
||||
```
|
||||
::::
|
||||
|
||||
::::{.cell}
|
||||
```{julia}
|
||||
#| output: asis
|
||||
plotattr(:Series) # Attribute für eine Serie, also zB ein Linienzug im Plot
|
||||
plotattr(:Series) # attributes for a series, e.g., a line in the plot
|
||||
```
|
||||
::::
|
||||
|
||||
Man kann auch nachfragen, was die einzelnen Attribute bedeuten und welche Werte zulässig sind:
|
||||
You can also query what individual attributes mean and which values are allowed:
|
||||
```{julia}
|
||||
plotattr("linestyle")
|
||||
```
|
||||
|
||||
|
||||
Ein Beispiel:
|
||||
An example:
|
||||
```{julia}
|
||||
theme(:default) # zurück zum Standardthema
|
||||
theme(:default) # return to default theme
|
||||
|
||||
x = 0:0.05:1
|
||||
y = sin.(2π*x)
|
||||
@@ -200,9 +199,9 @@ plot(x, y, seriestype = :sticks, linewidth = 4, seriescolor = "#00b300",
|
||||
)
|
||||
```
|
||||
|
||||
Viele Angaben können auch sehr weit abgekürzt werden, siehe z.B. die Angabe `Aliases:` in der obigen Ausgabe des Kommandos `plotattr("linestyle")`.
|
||||
Many specifications can be abbreviated significantly; see, e.g., the `Aliases:` in the output of `plotattr("linestyle")`.
|
||||
|
||||
Das folgende `plot()`-Kommando is äquivalent zum vorherigen:
|
||||
The following `plot()` command is equivalent to the previous one:
|
||||
|
||||
```{julia}
|
||||
#| eval: false
|
||||
@@ -210,61 +209,61 @@ plot(x, y, t = :sticks, w = 4, c = "#00b300", m = (:circle, 8, :green ))
|
||||
```
|
||||
|
||||
|
||||
### Weitere Extras
|
||||
### Additional Extras
|
||||
|
||||
```{julia}
|
||||
using Plots # Wiederholung schadet nicht
|
||||
using Plots.PlotMeasures # für Maßangaben in mm, cm,...
|
||||
using LaTeXStrings # für LaTeX-Konstrukte in Plot-Beschriftungen
|
||||
using PlotThemes # vorgefertigte Themen
|
||||
using Plots # no harm in repeating
|
||||
using Plots.PlotMeasures # for measurements in mm, cm,...
|
||||
using LaTeXStrings # for LaTeX constructs in plot labels
|
||||
using PlotThemes # predefined themes
|
||||
```
|
||||
|
||||
Das Paket `LaTeXStrings.jl` stellt einen String-Konstruktor `L"..."` zur Verfügung. Diese Strings können LaTeX-Konstrukte, insbesondere Formeln, enthalten. Wenn der String keine expliziten Dollarzeichen enthält, wird er automatisch im LaTeX-Math-Modus interpretiert.
|
||||
The `LaTeXStrings.jl` package provides the `L"..."` string constructor. These strings can contain LaTeX constructs, especially formulas. Without explicit dollar signs, they are automatically interpreted in LaTeX math mode.
|
||||
|
||||
```{julia}
|
||||
xs = range(0, 2π, length = 100)
|
||||
|
||||
data = [sin.(xs) cos.(xs) 2sin.(xs) (x->sin(x^2)).(xs)] # 4 Funktionen
|
||||
data = [sin.(xs) cos.(xs) 2sin.(xs) (x->sin(x^2)).(xs)] # 4 functions
|
||||
|
||||
theme(:ggplot2)
|
||||
|
||||
plot10 = plot(xs, data,
|
||||
fontfamily="Computer Modern",
|
||||
|
||||
# LaTeX-String L"..."
|
||||
title = L"Winkelfunktionen $\sin(\alpha), \cos(\alpha), 2\sin(\alpha), \sin(\alpha^2)$",
|
||||
xlabel = L"Winkel $\alpha$",
|
||||
ylabel = "Funktionswert",
|
||||
# LaTeX string L"..."
|
||||
title = L"Trigonometric functions $\sin(\alpha), \cos(\alpha), 2\sin(\alpha), \sin(\alpha^2)$",
|
||||
xlabel = L"angle $\alpha$",
|
||||
ylabel = "value",
|
||||
|
||||
# 1x4-Matrizen mit Farben, Marker,... für die 4 'Series'
|
||||
# 1x4-matrices with colors, markers,... for the 4 'series'
|
||||
color=[:black :green RGB(0.3, 0.8, 0.2) :blue ],
|
||||
markers = [:rect :circle :utriangle :diamond],
|
||||
markersize = [2 1 0 4],
|
||||
linewidth = [1 3 1 2],
|
||||
linestyle = [:solid :dash :dot :solid ],
|
||||
|
||||
# Achsen
|
||||
# axes
|
||||
xlim = (0, 6.6),
|
||||
ylim = (-2, 2.3),
|
||||
yticks = -2:.4:2.3, # mit Schrittweite
|
||||
yticks = -2:.4:2.3, # with step size
|
||||
|
||||
# Legende
|
||||
# legend
|
||||
legend = :bottomleft,
|
||||
label = [ L"\sin(\alpha)" L"\cos(\alpha)" L"2\sin(\alpha)" L"\sin(\alpha^2)"],
|
||||
|
||||
top_margin = 5mm, # hier wird Plots.PlotMeasures gebraucht
|
||||
top_margin = 5mm, # here Plots.PlotMeasures is needed
|
||||
)
|
||||
|
||||
# Zusatztext: annotate!(x-pos, y-pos, text("...", font, fontsize))
|
||||
# additional text: annotate!(x-pos, y-pos, text("...", font, fontsize))
|
||||
|
||||
annotate!(plot10, 4.1, 1.8, text("nicht schön, aber viel","Computer Modern", 10) )
|
||||
annotate!(plot10, 4.1, 1.8, text("Some remark","Computer Modern", 10) )
|
||||
```
|
||||
|
||||
### Andere Plot-Funktionen
|
||||
### Other Plot Functions
|
||||
|
||||
Bisher haben wir vor allem Linien geplottet. Es gibt noch viele andere Typen wie _scatter plot, contour, heatmap, histogram, stick,..._
|
||||
So far, we have mainly plotted lines. Many other types exist, such as _scatter plots, contours, heatmaps, histograms, sticks_, etc.
|
||||
|
||||
Dies kann man mit dem `seriestype`-Attribut steuern:
|
||||
This can be controlled with the `seriestype` attribute:
|
||||
|
||||
```{julia}
|
||||
theme(:default)
|
||||
@@ -273,7 +272,7 @@ x = range(0, 2π; length = 50)
|
||||
plot(x, sin.(x), seriestype=:scatter)
|
||||
```
|
||||
|
||||
oder indem man die spezielle Funktion benutzt, die so heißt wie der `seriestype`:
|
||||
or by using the specific function named after the `seriestype`:
|
||||
```{julia}
|
||||
x = range(0, 2π; length = 50)
|
||||
scatter(x, sin.(x))
|
||||
@@ -281,9 +280,9 @@ scatter(x, sin.(x))
|
||||
|
||||
|
||||
|
||||
### Subplots und Layout {#sec-subplot}
|
||||
### Subplots and Layout {#sec-subplot}
|
||||
|
||||
Mehrere Plots können zu einer Abbildung zusammengefasst werden. Die Anordnung bestimmt der `layout`-Parameter. Dabei bedeutet `layout=(m,n)`, dass die Plots in einem $m\times n$-Schema angeordnet werden:
|
||||
Multiple plots can be combined into one figure. The arrangement is determined by the `layout` parameter: `layout=(m,n)` arranges plots in an $m\times n$ grid:
|
||||
|
||||
```{julia}
|
||||
x = range(0, 2π; length = 100)
|
||||
@@ -300,7 +299,7 @@ plot(plots..., layout=(4,1), legend=false, title=["sin" "cos" "tan" "sinc"])
|
||||
```
|
||||
|
||||
|
||||
Man kann Layouts auch schachteln und mit dem `@layout`-Macro explizite Breiten/Höhenanteile vorgeben:
|
||||
Layouts can also be nested and explicit width/height proportions can be specified using the `@layout` macro:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -317,50 +316,50 @@ plot(plots..., layout=mylayout, legend=false, title=["sin" "cos" "tan" "sinc"])
|
||||
|
||||
### Backends
|
||||
|
||||
`Plots.jl` ist konzipiert als ein einheitliches Interface zu verschiedenen _backends_ (Grafik-Engines). Man kann zu einem anderen Backend wechseln und dieselben Plot-Kommandos und -Attribute verwenden.
|
||||
`Plots.jl` provides a unified interface to various _backends_ (graphics engines). You can switch backends and use the same plot commands and attributes.
|
||||
|
||||
Allerdings unterstützen nicht alle _backends_ alle Plot-Typen und -Attribute. Einen Überblick gibt es [hier](https://docs.juliaplots.org/stable/generated/supported/).
|
||||
However, not all _backends_ support all plot types and attributes. An overview is available [here](https://docs.juliaplots.org/stable/generated/supported/).
|
||||
|
||||
Bisher wurde das Standard-Backend verwendet. Es heißt [GR](https://gr-framework.org/about.html) und ist eine am Forschungszentrum Jülich entwickelte und hauptsächlich in C geschriebene Grafik-Engine.
|
||||
So far, we have used the default backend: [GR](https://gr-framework.org/about.html), a graphics engine developed at the Jülich Research Center, primarily in C.
|
||||
|
||||
|
||||
```{julia}
|
||||
using Plots
|
||||
backend() # Anzeige des gewählten backends, GR ist der default
|
||||
backend() # display the selected backend, GR is the default
|
||||
```
|
||||
|
||||
|
||||
Nochmal ein Beispiel
|
||||
Another example:
|
||||
```{julia}
|
||||
x = 1:30
|
||||
y = rand(30)
|
||||
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Wasserstand")
|
||||
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Water level")
|
||||
```
|
||||
|
||||
und hier derselbe Plot mit dem `PlotlyJS`-Backend.
|
||||
The same plot with the `PlotlyJS` backend:
|
||||
|
||||
|
||||
```{julia}
|
||||
plotlyjs() # change plots backend
|
||||
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Wasserstand")
|
||||
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Water level")
|
||||
```
|
||||
|
||||
Dieses Backend ermöglich mit Hilfe von Javascript eine gewisse Interaktivität. Wenn man die Maus in das Bild bewegt, kann man mit der Maus zoomen, verschieben und 3D-Plots auch drehen.
|
||||
This backend enables interactivity via JavaScript. Hovering over the image allows zooming and panning; 3D plots can also be rotated.
|
||||
|
||||
|
||||
```{julia}
|
||||
gr() # zurück zu GR als backend
|
||||
gr() # return to GR as backend
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 3D Plots
|
||||
|
||||
Die Funktionen `surface()` und `contour()` ermöglichen den Plot einer Funktion $f(x,y)$. Als Argumente werden benötigt:
|
||||
The `surface()` and `contour()` functions plot a function $f(x,y)$. Required arguments are:
|
||||
|
||||
- eine Menge (Vektor) $X$ von $x$-Werten,
|
||||
- eine Menge (Vektor) $Y$ von $y$-Werten und
|
||||
- eine Funktion von zwei Variablen, die dann auf $X \times Y$ ausgewertet und geplottet wird.
|
||||
- a set (vector) $X$ of $x$-values,
|
||||
- a set (vector) $Y$ of $y$-values and
|
||||
- a function of two variables that is then evaluated on $X \times Y$ and plotted.
|
||||
|
||||
```{julia}
|
||||
f(x,y) = (1 - x/2 + x^5 + y^3) * exp(-x^2 - y^2)
|
||||
@@ -372,8 +371,8 @@ surface( -3:0.02:3, -3:0.02:3, f)
|
||||
contour( -3:0.02:3, -3:0.02:3, f, fill=true, colormap=:summer, levels=20, contour_labels=false)
|
||||
```
|
||||
|
||||
Kurven (oder auch einfach Punktmengen) in drei Dimensionen lassen sich plotten, indem man `plot()` mit 3 Vektoren
|
||||
aufruft, die jeweils die $x$, $y$ und $z$-Koordinaten der Datenpunkte enthalten.
|
||||
Curves (or point sets) in three dimensions are plotted by calling `plot()` with three vectors
|
||||
containing the $x$, $y$, and $z$ coordinates of the data points.
|
||||
|
||||
```{julia}
|
||||
plotlyjs()
|
||||
@@ -387,25 +386,23 @@ plot(x, y, z, zcolor=reverse(z), markersize=3, markershape= :circle,
|
||||
|
||||
```
|
||||
|
||||
> Wir verwenden mal das `plotlyjs`-Backend, damit ist der Plot interaktiv und kann mit der Maus gedreht und gezoomt werden.
|
||||
> The `plotlyjs` backend makes the plot interactive: it can be rotated and zoomed with the mouse.
|
||||
|
||||
### Plots.jl und _recipes_
|
||||
### Plots.jl and _recipes_
|
||||
|
||||
Andere Pakete können die Möglichkeiten von `Plots.jl` erweitern, indem sie sogenannte _recipes_ für spezielle Plots und Datenstrukturen definieren, siehe [https://docs.juliaplots.org/latest/ecosystem/](https://docs.juliaplots.org/latest/ecosystem/), z.B.:
|
||||
Other packages can extend `Plots.jl` by defining so-called _recipes_ for special plots and data structures (see [https://docs.juliaplots.org/latest/ecosystem/](https://docs.juliaplots.org/latest/ecosystem/)), e.g.:
|
||||
|
||||
- `StatsPlots.jl` direktes Plotten von _Dataframes_, spezielle statistische Plots usw. oder
|
||||
- `GraphRecipes.jl` [Plotten von Graphstrukturen](https://docs.juliaplots.org/latest/GraphRecipes/examples/)
|
||||
- `StatsPlots.jl`: direct plotting of _DataFrames_, special statistical plots, etc.
|
||||
- `GraphRecipes.jl`: [plotting of graph structures](https://docs.juliaplots.org/latest/GraphRecipes/examples/)
|
||||
|
||||
|
||||
### Ein Säulendiagramm
|
||||
### A Bar Chart
|
||||
|
||||
Für das letzte Beispiel laden wir ein Paket, das über 700 freie (_"public domain"_) Datensätze, darunter z.B:
|
||||
For the last example, we load a package providing over 700 free (_"public domain"_) datasets, including:
|
||||
|
||||
- die Passagierliste der _Titanic_,
|
||||
- Verbrauchsdaten amerikanischer Autos aus den 70ern oder
|
||||
- historische Währungskurse
|
||||
|
||||
bereitstellt:
|
||||
- the _Titanic_ passenger list,
|
||||
- fuel consumption data for American cars from the 70s, or
|
||||
- historical exchange rates:
|
||||
|
||||
```{julia}
|
||||
using RDatasets
|
||||
@@ -419,13 +416,13 @@ using RDatasets
|
||||
#RDatasets.datasets()
|
||||
```
|
||||
|
||||
Der Datensatz ["Motor Trend Car Road Tests"](https://rdrr.io/r/datasets/mtcars.html)
|
||||
The dataset ["Motor Trend Car Road Tests"](https://rdrr.io/r/datasets/mtcars.html)
|
||||
|
||||
```{julia}
|
||||
cars = dataset("datasets", "mtcars")
|
||||
```
|
||||
|
||||
Wir brauchen für den Plot nur die beiden Spalten `cars.Model` und `cars.MPG`, den Benzinverbrauch in _miles per gallon_ (Mehr heißt sparsamer!)
|
||||
We only need two columns for the plot: `cars.Model` and `cars.MPG`, the fuel consumption in _miles per gallon_ (higher is more economical).
|
||||
|
||||
```{julia}
|
||||
theme(:bright)
|
||||
@@ -443,10 +440,10 @@ bar(cars.Model, cars.MPG,
|
||||
```
|
||||
|
||||
|
||||
### Was noch fehlt: Animation
|
||||
### What is Missing: Animation
|
||||
|
||||
Hier sei auf die [Dokumentation](https://docs.juliaplots.org/latest/animations/) verwiesen und nur ein Beispiel
|
||||
(von <https://www.juliafordatascience.com/animations-with-plots-jl/>) angegeben:
|
||||
See the [documentation](https://docs.juliaplots.org/latest/animations/); here is an example
|
||||
(from <https://www.juliafordatascience.com/animations-with-plots-jl/>):
|
||||
|
||||
```{julia}
|
||||
#| error: false
|
||||
@@ -465,7 +462,7 @@ gif(anim, fps=50)
|
||||
```
|
||||
|
||||
|
||||
:::: {.content-visible when-format="pdf"}
|
||||
:::: {.content-visible when-format="typst"}
|
||||
```{julia}
|
||||
#| echo: false
|
||||
Random.seed!(123)
|
||||
|
||||
@@ -1,8 +1,34 @@
|
||||
---
|
||||
engine: julia
|
||||
julia:
|
||||
exeflags: ["--color=yes"]
|
||||
---
|
||||
|
||||
# Arbeit mit Julia: REPL, Pakete, Introspection
|
||||
```{julia}
|
||||
#| error: false
|
||||
#| echo: false
|
||||
#| output: false
|
||||
using InteractiveUtils
|
||||
|
||||
#struct M a::Int end; x = M(22); @show x
|
||||
#should not print "Main.Notebook.M(22)" but only "M(22)"
|
||||
function Base.show(io::IO, x::T) where T
|
||||
if parentmodule(T) == @__MODULE__
|
||||
# Print "TypeName(fields...)" without module prefix
|
||||
print(io, nameof(T), "(")
|
||||
fields = fieldnames(T)
|
||||
for (i, f) in enumerate(fields)
|
||||
print(io, getfield(x, f))
|
||||
i < length(fields) && print(io, ", ")
|
||||
end
|
||||
print(io, ")")
|
||||
else
|
||||
invoke(Base.show, Tuple{IO, Any}, io, x)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
# Working with Julia: The REPL, Packages, and Introspection
|
||||
|
||||
```{julia}
|
||||
#| error: false
|
||||
@@ -17,50 +43,49 @@ Base.active_module() = myactive_module()
|
||||
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L3073-L3077
|
||||
```
|
||||
|
||||
## Dokumentation
|
||||
## Official Documentation
|
||||
|
||||
Die offizielle Julia-Dokumentation [https://docs.julialang.org/](https://docs.julialang.org/) enthält zahlreiche Übersichten, darunter:
|
||||
|
||||
- [https://docs.julialang.org/en/v1/base/punctuation/](https://docs.julialang.org/en/v1/base/punctuation/) Verzeichnis der Symbole
|
||||
- [https://docs.julialang.org/en/v1/manual/unicode-input/](https://docs.julialang.org/en/v1/manual/unicode-input/) Verzeichnis spezieller Unicode-Symbole und deren Eingabe in Julia via Tab-Vervollständigung
|
||||
- [https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions) Liste mathematischer Funktionen
|
||||
The official Julia documentation [https://docs.julialang.org/](https://docs.julialang.org/) contains several 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 | Action |
|
||||
| :----------------------------| :------------------------ |
|
||||
| `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 supports 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 `|
|
||||
| Help | `help?>` | `?`| `backspace`|
|
||||
|Shell | `shell>` | `;` | `backspace`|
|
||||
|
||||
:::
|
||||
|
||||
|
||||
## Jupyter-Notebooks (IJulia)
|
||||
## Jupyter Notebooks (IJulia)
|
||||
|
||||
|
||||
In einem Jupyter-Notebook sind die Modi sind als Einzeiler in einer eigenen Input-Zelle nutzbar:
|
||||
In a Jupyter notebook, the modes are usable as single-line commands in their own input cells:
|
||||
|
||||
(i) ein Kommando des Paket-Managers:
|
||||
(i) a package manager command:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -68,7 +93,7 @@ In einem Jupyter-Notebook sind die Modi sind als Einzeiler in einer eigenen Inpu
|
||||
] status
|
||||
```
|
||||
|
||||
(ii) eine Help-Abfrage:
|
||||
(ii) a help query:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -76,7 +101,7 @@ In einem Jupyter-Notebook sind die Modi sind als Einzeiler in einer eigenen Inpu
|
||||
?sin
|
||||
```
|
||||
|
||||
(iii) Ein Shell-Kommando:
|
||||
(iii) a shell command:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -84,71 +109,71 @@ 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 extensive collection of packages that extend Julia's functionality.
|
||||
|
||||
- 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 `using Packagename`.
|
||||
- They form the so-called _standard library_, which includes
|
||||
- `LinearAlgebra`, `Statistics`, `SparseArrays`, `Printf`, `Pkg`, and others.
|
||||
- Over 10000 packages are officially registered, see [https://julialang.org/packages/](https://julialang.org/packages/).
|
||||
- These can be downloaded and installed with just a few keystrokes using the _package manager_ `Pkg`.
|
||||
- `Pkg` can be called in two ways:
|
||||
- as normal Julia statements that can also be in a `.jl` program file:
|
||||
```{.Julia}
|
||||
using Pkg
|
||||
Pkg.add("PaketXY")
|
||||
Pkg.add("PackageXY")
|
||||
```
|
||||
- im speziellen pkg-Modus des Julia-REPLs:
|
||||
- in the special pkg-mode of the Julia REPL:
|
||||
```{.julia}
|
||||
] add PackageXY
|
||||
```
|
||||
] add PaketXY
|
||||
```
|
||||
- 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 |
|
||||
| `Pkg.add("PackageXY")` | `pkg> add PackageXY` | add to current environment |
|
||||
| `Pkg.rm("PackageXY")` | `pkg> remove PackageXY` | remove from current environment |
|
||||
| `Pkg.update()` | `pkg> update` | update packages in current environment |
|
||||
| `Pkg.activate("mydir")` | `pkg> activate mydir` | activate directory as current environment |
|
||||
| `Pkg.status()` | `pkg> status` | list packages |
|
||||
| `Pkg.instantiate()` | `pg> instantiate` | install all packages according to `Project.toml` |
|
||||
| `Pkg.instantiate()` | `pkg> instantiate` | install all packages according to `Project.toml` |
|
||||
|
||||
: {tbl-colwidths="[35,40,25]"}
|
||||
|
||||
### 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's package manager maintains:
|
||||
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`.
|
||||
- Without an expplicit project environment, this looks as follows:
|
||||
|
||||
```
|
||||
(@v1.10) pkg> status
|
||||
Status `~/.julia/environments/v1.10/Project.toml`
|
||||
[6e4b80f9] BenchmarkTools v1.5.0
|
||||
[5fb14364] OhMyREPL v0.5.24
|
||||
[91a5bcdd] Plots v1.40.4
|
||||
[295af30f] Revise v3.5.14
|
||||
Status `~/.julia/environments/v1.12/Project.toml`
|
||||
[6e4b80f9] BenchmarkTools v1.6.3
|
||||
[5fb14364] OhMyREPL v0.5.29
|
||||
[91a5bcdd] JuliaFormatter v2.3.0
|
||||
[295af30f] Revise v3.13.2
|
||||
```
|
||||
|
||||
- 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` and `Manifest.toml` files 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`:
|
||||
### 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:
|
||||
- A central repository already contains all packages mentioned in this course.
|
||||
- You have no write permissions there.
|
||||
- However, you can install additional packages in your `HOME`. As a first command, you need to activate the current directory:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -156,26 +181,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.
|
||||
Package installation can take a significant amount of 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.
|
||||
The Julia compiler is based on the _LLVM Compiler Infrastructure Project_.
|
||||
|
||||
:::{.narrow}
|
||||
Stages of Compilation
|
||||
@@ -201,7 +227,7 @@ end
|
||||
|
||||
|
||||
```{julia}
|
||||
p = Meta.parse( "function f(x,y); z=x^2+log(y); return 2x; end ")
|
||||
p = Meta.parse( "function f(x,y); z=x^2+log(y); return 2x; end")
|
||||
```
|
||||
|
||||
|
||||
@@ -235,5 +261,3 @@ walk_tree(p)
|
||||
```{julia}
|
||||
@code_native f(2,4)
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -2,73 +2,65 @@
|
||||
engine: julia
|
||||
---
|
||||
|
||||
```{julia}
|
||||
#| error: false
|
||||
#| echo: false
|
||||
#| output: false
|
||||
using InteractiveUtils
|
||||
```
|
||||
# Containers
|
||||
|
||||
Julia offers a wide selection of container types with largely similar interfaces.
|
||||
This chapter introduces `Tuple`, `Range`, and `Dict`; the next chapter covers `Array`, `Vector`, and `Matrix`.
|
||||
|
||||
# Container
|
||||
These containers are:
|
||||
|
||||
Julia bietet eine große Auswahl von Containertypen mit weitgehend ähnlichem Interface an.
|
||||
Wir stellen hier `Tuple`, `Range` und `Dict` vor, im nächsten Kapitel dann `Array`, `Vector` und `Matrix`.
|
||||
|
||||
Diese Container sind:
|
||||
|
||||
- **iterierbar:** Man kann über die Elemente des Containers iterieren:
|
||||
- **iterable:** You can iterate over the elements of the container:
|
||||
```julia
|
||||
for x ∈ container ... end
|
||||
```
|
||||
- **indizierbar:** Man kann auf Elemente über ihren Index zugreifen:
|
||||
- **indexable:** You can access elements via their index:
|
||||
```julia
|
||||
x = container[i]
|
||||
```
|
||||
und einige sind auch
|
||||
```
|
||||
and some are also
|
||||
|
||||
- **mutierbar**: Man kann Elemente hinzufügen, entfernen und ändern.
|
||||
- **mutable:** You can add, remove, and modify elements.
|
||||
|
||||
Weiterhin gibt es eine Reihe gemeinsamer Funktionen, z.B.
|
||||
Furthermore, there are several common functions, e.g.,
|
||||
|
||||
- `length(container)` --- Anzahl der Elemente
|
||||
- `eltype(container)` --- Typ der Elemente
|
||||
- `isempty(container)` --- Test, ob Container leer ist
|
||||
- `empty!(container)` --- leert Container (nur wenn mutierbar)
|
||||
- `length(container)` --- number of elements
|
||||
- `eltype(container)` --- element type
|
||||
- `isempty(container)` --- test if container is empty
|
||||
- `empty!(container)` --- empties the container (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. You cannot add new elements or change existing values.
|
||||
|
||||
|
||||
|
||||
```{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:
|
||||
# Assign quotient and remainder 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:
|
||||
Parentheses can be omitted in certain constructs.
|
||||
This *implicit tuple packing/unpacking* is commonly used in multiple assignments:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -80,56 +72,54 @@ 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.
|
||||
|
||||
Das notiert man so:
|
||||
Some functions require tuples as arguments or always return tuples. A single-element tuple 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. `UnitRange`, for example, is a *range* with step size 1. Their constructors are typically all 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 iterable, immutable, and 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` does **not** mean 'increment the loop variable `i` by one each iteration'; **rather**, it means 'successively assign the values 1, 2, 3, ..., 1000 to the loop variable from the container'.
|
||||
|
||||
Allerdings wäre es sehr ineffektiv, diesen Container tatsächlich explizit anzulegen.
|
||||
Creating this container explicitly would be very inefficient.
|
||||
|
||||
- _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`.
|
||||
- _Ranges_ are "lazy" vectors never stored as concrete lists. This makes them ideal as `for` loop iterators: 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`.
|
||||
|
||||
Das Macro `@allocated` gibt aus, wieviel Bytes an Speicher bei der Auswertung eines Ausdrucks alloziert wurden.
|
||||
The macro `@allocated` outputs how many bytes of memory were allocated during the evaluation of an expression.
|
||||
|
||||
```{julia}
|
||||
@allocated r = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
|
||||
@@ -142,198 +132,196 @@ Das Macro `@allocated` gibt aus, wieviel Bytes an Speicher bei der Auswertung ei
|
||||
|
||||
|
||||
|
||||
Zum Umwandeln in einen 'richtigen' Vektor dient die Funktion `collect()`.
|
||||
|
||||
The `collect()` function converts a range to a concrete 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 `n` equidistant values from start to stop. Use `collect()` to 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_ (also known as associative arrays or lookup tables) are special containers.
|
||||
- Whereas vector entries are addressed by integer indices: `v[i]`; dictionary entries are addressed by more general _keys_.
|
||||
- A dictionary is a collection of _key-value_ pairs with parameterized type `Dict{S,T}`, where `S` is the key type and `T` is the value type.
|
||||
|
||||
|
||||
Man kann sie explizit anlegen:
|
||||
Create a dictionary explicitly:
|
||||
```{julia}
|
||||
# Einwohner 2020 in Millionen, Quelle: wikipedia
|
||||
# Population in 2020 in millions, source: wikipedia
|
||||
|
||||
EW = Dict("Berlin" => 3.66, "Hamburg" => 1.85,
|
||||
Ppl = Dict("Berlin" => 3.66, "Hamburg" => 1.85,
|
||||
"München" => 1.49, "Köln" => 1.08)
|
||||
```
|
||||
|
||||
|
||||
```{julia}
|
||||
typeof(EW)
|
||||
typeof(Ppl)
|
||||
```
|
||||
|
||||
und mit den _keys_ indizieren:
|
||||
and indexed with the _keys_:
|
||||
|
||||
```{julia}
|
||||
EW["Berlin"]
|
||||
Ppl["Berlin"]
|
||||
```
|
||||
|
||||
Das Abfragen eines nicht existierenden _keys_ ist natürlich ein Fehler.
|
||||
Querying a non-existent _key_ throws an error.
|
||||
```{julia}
|
||||
EW["Leipzig"]
|
||||
Ppl["Leipzig"]
|
||||
```
|
||||
|
||||
Man kann ja auch vorher mal anfragen...
|
||||
Check beforehand with `haskey()`...
|
||||
```{julia}
|
||||
haskey(EW, "Leipzig")
|
||||
haskey(Ppl, "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 `get(dict, key, default)`, which returns the default value instead of throwing an error.
|
||||
|
||||
```{julia}
|
||||
@show get(EW, "Leipzig", -1) get(EW, "Berlin", -1);
|
||||
@show get(Ppl, "Leipzig", -1) get(Ppl, "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)
|
||||
keys(Ppl)
|
||||
```
|
||||
|
||||
|
||||
```{julia}
|
||||
values(EW)
|
||||
values(Ppl)
|
||||
```
|
||||
|
||||
|
||||
Man kann über die `keys` iterieren...
|
||||
Iterate over the `keys`...
|
||||
```{julia}
|
||||
for i in keys(EW)
|
||||
n = EW[i]
|
||||
println("Die Stadt $i hat $n Millionen Einwohner.")
|
||||
for i in keys(Ppl)
|
||||
n = Ppl[i]
|
||||
println("The city $i has $n million inhabitants.")
|
||||
end
|
||||
```
|
||||
|
||||
odere gleich über `key-value`-Paare.
|
||||
Or iterate directly over `key-value` pairs.
|
||||
```{julia}
|
||||
for (stadt, ew) ∈ EW
|
||||
println("$stadt : $ew Mill.")
|
||||
for (city, pop) ∈ Ppl
|
||||
println("$city : $pop Million.")
|
||||
end
|
||||
```
|
||||
|
||||
### Erweitern und Modifizieren
|
||||
### Extending and Modifying
|
||||
|
||||
Man kann in ein `Dict` zusätzliche `key-value`-Paare eintragen...
|
||||
Add `key-value` pairs to a `Dict`...
|
||||
```{julia}
|
||||
EW["Leipzig"] = 0.52
|
||||
EW["Dresden"] = 0.52
|
||||
EW
|
||||
Ppl["Leipzig"] = 0.52
|
||||
Ppl["Dresden"] = 0.52
|
||||
Ppl
|
||||
```
|
||||
|
||||
|
||||
und einen `value` ändern.
|
||||
Change a `value`:
|
||||
```{julia}
|
||||
# Oh, das war bei Leipzig die Zahl von 2010, nicht 2020
|
||||
# Update: Leipzig data was from 2010, not 2020
|
||||
|
||||
EW["Leipzig"] = 0.597
|
||||
EW
|
||||
Ppl["Leipzig"] = 0.597
|
||||
Ppl
|
||||
```
|
||||
|
||||
Ein Paar kann über seinen `key` auch gelöscht werden.
|
||||
Delete a pair by its `key`:
|
||||
```{julia}
|
||||
delete!(EW, "Dresden")
|
||||
delete!(Ppl, "Dresden")
|
||||
```
|
||||
|
||||
Zahlreiche Funktionen können mit `Dicts` wie mit anderen Containern arbeiten.
|
||||
Many functions work with `Dicts` like other containers.
|
||||
|
||||
```{julia}
|
||||
maximum(values(EW))
|
||||
maximum(values(Ppl))
|
||||
```
|
||||
|
||||
### Anlegen eines leeren Dictionaries
|
||||
### Creating an Empty Dictionary
|
||||
|
||||
Ohne Typspezifikation ...
|
||||
Without explicit types:
|
||||
```{julia}
|
||||
d1 = Dict()
|
||||
```
|
||||
|
||||
und mit Typspezifikation:
|
||||
With explicit types:
|
||||
```{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)` return special container types.
|
||||
- `collect()` converts them to `Vector`s.
|
||||
- `collect(dict)` returns a `Vector{Pair{S,T}}`.
|
||||
|
||||
|
||||
```{julia}
|
||||
collect(EW)
|
||||
collect(Ppl)
|
||||
```
|
||||
|
||||
|
||||
```{julia}
|
||||
collect(keys(EW)), collect(values(EW))
|
||||
collect(keys(Ppl)), collect(values(Ppl))
|
||||
```
|
||||
|
||||
### 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. ")
|
||||
for k in sort(collect(keys(Ppl)), rev = true)
|
||||
n = Ppl[k]
|
||||
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.
|
||||
Let's sort `collect(dict)`, a vector of pairs. Use `by` to specify the sort key: the second element of each pair.
|
||||
|
||||
```{julia}
|
||||
for (k,v) in sort(collect(EW), by = pair -> last(pair), rev=false)
|
||||
println("$k hat $v Mill. EW")
|
||||
for (k,v) in sort(collect(Ppl), by = pair -> last(pair), rev=false)
|
||||
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:
|
||||
Let's do "experimental stochastics" 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.
|
||||
Let `l` be a vector containing 100,000 sums of two dice rolls (numbers from 2 to 12).
|
||||
|
||||
Wie häufig sind die Zahlen 2 bis 12?
|
||||
How frequently does each number from 2 to 12 occur?
|
||||
|
||||
|
||||
Wir (lassen) würfeln:
|
||||
Roll the dice:
|
||||
|
||||
```{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`.
|
||||
Count event frequencies using a dictionary. Use 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, a simple vector would also work.
|
||||
# A better use case for dictionaries is word frequency in texts,
|
||||
# where keys are strings instead of integers.
|
||||
|
||||
d = Dict{Int,Int}() # das Dict zum 'reinzählen'
|
||||
d = Dict{Int,Int}() # dictionary for counting
|
||||
|
||||
for i in l # für jedes i wird d[i] erhöht.
|
||||
for i in l # for each i, increment d[i]
|
||||
d[i] = get(d, i, 0) + 1
|
||||
end
|
||||
d
|
||||
```
|
||||
|
||||
Das Ergebnis:
|
||||
Result:
|
||||
|
||||
```{julia}
|
||||
using Plots
|
||||
@@ -341,7 +329,6 @@ using Plots
|
||||
plot(collect(keys(d)), collect(values(d)), seriestype=:scatter)
|
||||
```
|
||||
|
||||
##### Das Erklär-Bild dazu:
|
||||
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
@@ -2,52 +2,62 @@
|
||||
engine: julia
|
||||
---
|
||||
|
||||
# Funktionen und Operatoren
|
||||
# Functions and Operators
|
||||
|
||||
```{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
|
||||
|
||||
#struct M a::Int end; x = M(22); @show x
|
||||
#should not print "Main.Notebook.M(22)" but only "M(22)"
|
||||
function Base.show(io::IO, x::T) where T
|
||||
if parentmodule(T) == @__MODULE__
|
||||
# Print "TypeName(fields...)" without module prefix
|
||||
print(io, nameof(T), "(")
|
||||
fields = fieldnames(T)
|
||||
for (i, f) in enumerate(fields)
|
||||
print(io, getfield(x, f))
|
||||
i < length(fields) && print(io, ", ")
|
||||
end
|
||||
print(io, ")")
|
||||
else
|
||||
invoke(Base.show, Tuple{IO, Any}, io, x)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
Funktionen verarbeiten ihre Argumente zu einem Ergebnis, das sie beim Aufruf zurückliefern.
|
||||
Functions process their arguments to produce and return a result when called.
|
||||
|
||||
## Formen
|
||||
## Forms of function definitions
|
||||
|
||||
Funktionen können in verschiedenen Formen definiert werden:
|
||||
|
||||
I. Als `function ... end`-Block
|
||||
I. Block form: `function ... end`
|
||||
```{julia}
|
||||
function hyp(x,y)
|
||||
sqrt(x^2+y^2)
|
||||
end
|
||||
```
|
||||
II. Als "Einzeiler"
|
||||
II. Single-line form
|
||||
```{julia}
|
||||
hyp(x, y) = sqrt(x^2 + y^2)
|
||||
```
|
||||
III. Als anonyme Funktionen
|
||||
III. Anonymous functions
|
||||
|
||||
```{julia}
|
||||
(x, y) -> sqrt(x^2 + y^2)
|
||||
```
|
||||
|
||||
|
||||
### Block-Form und `return`
|
||||
|
||||
### Block Form and `return` Statement
|
||||
|
||||
|
||||
- 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 terminates and control returns to the calling context.
|
||||
- Without `return`, the value of the last expression is returned as the function value.
|
||||
|
||||
Die beiden Definitionen
|
||||
The two definitions
|
||||
|
||||
```julia
|
||||
function xsinrecipx(x)
|
||||
@@ -57,7 +67,7 @@ function xsinrecipx(x)
|
||||
return x * sin(1/x)
|
||||
end
|
||||
```
|
||||
und ohne das zweite explizite `return` in der letzten Zeile:
|
||||
and the equivalent version without explicit `return` in the last line:
|
||||
|
||||
```julia
|
||||
function xsinrecipx(x)
|
||||
@@ -68,11 +78,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 C) returns a `nothing` value of type `Nothing`. (Just as a `Bool` object has two values, `true` and `false`, a `Nothing` object has only one: `nothing`.)
|
||||
- An empty `return` statement is equivalent to `return nothing`.
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -95,27 +105,27 @@ a
|
||||
```
|
||||
|
||||
|
||||
### Einzeiler-Form
|
||||
### Single-liner Form
|
||||
|
||||
Die Einzeilerform ist eine ganz normale Zuweisung, bei der links eine Funktion steht.
|
||||
The single-liner form looks like a simple assignment:
|
||||
|
||||
```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 provides two ways to combine multiple statements into a block that can stand in place of a single statement:
|
||||
|
||||
- `begin ... end`-Block
|
||||
- Eingeklammerte durch Semikolon getrennte Anweisungen.
|
||||
- `begin ... end` block
|
||||
- Parenthesized statements separated by semicolons.
|
||||
|
||||
In beiden Fällen ist der Wert des Blockes der Wert der letzten Anweisung.
|
||||
In both cases, the value of the block is the value of the last statement.
|
||||
|
||||
Damit funktioniert auch
|
||||
Thus, the following also works:
|
||||
```julia
|
||||
hyp(x, y) = (z = x^2; z += y^2; sqrt(z))
|
||||
```
|
||||
|
||||
und
|
||||
and
|
||||
```julia
|
||||
hyp(x, y) = begin
|
||||
z = x^2
|
||||
@@ -124,15 +134,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 include `map(f, collection)`, which applies a function to every element of a collection. Julia also supports `map(f, collection1, collection2)` with multiple collections:
|
||||
|
||||
```{julia}
|
||||
map( (x,y) -> sqrt(x^2 + y^2), [3, 5, 8], [4, 12, 15])
|
||||
@@ -142,24 +152,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, Julia does not copy objects passed as arguments. Function arguments refer to the original objects. Julia calls this concept _pass_by_sharing_.
|
||||
- Consequently, functions can modify their arguments if they are mutable (e.g., `Vector` or `Array`).
|
||||
- By convention, functions that modify their arguments end with an exclamation mark. The modified argument is typically the first argument and is also returned.
|
||||
|
||||
```{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
|
||||
# '===' tests for identity
|
||||
@show V W V===W; # V and W refer to the same object
|
||||
```
|
||||
|
||||
```{julia}
|
||||
@@ -175,16 +185,16 @@ U = fill_first!(V, 42)
|
||||
|
||||
|
||||
|
||||
## Varianten von Funktionsargumenten
|
||||
## Function Argument Variants
|
||||
|
||||
- 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 values,
|
||||
2. Positional arguments with default values,
|
||||
3. --- semicolon ---,
|
||||
4. comma-separated list of keyword arguments (with or without default values)
|
||||
- When calling, keyword arguments can appear in any order at any position. They can be separated from positional arguments with a semicolon, but this is optional.
|
||||
|
||||
```{julia}
|
||||
fa(x, y=42; a) = println("x=$x, y=$y, a=$a")
|
||||
@@ -194,7 +204,7 @@ fa(6, 7; a=4)
|
||||
fa(a=-2, 6)
|
||||
```
|
||||
|
||||
Eine Funktion nur mit _keyword_-Argumenten wird so deklariert:
|
||||
A function with only _keyword_ arguments is declared as follows:
|
||||
|
||||
```{julia}
|
||||
fkw(; x=10, y) = println("x=$x, y=$y")
|
||||
@@ -204,9 +214,9 @@ fkw(y=2)
|
||||
|
||||
|
||||
|
||||
## Funktionen sind ganz normale Objekte
|
||||
## Functions are just Objects
|
||||
|
||||
- Sie können zugewiesen werden
|
||||
- Functions can be assigned to variables
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -215,11 +225,11 @@ f2(2)
|
||||
```
|
||||
|
||||
|
||||
- Sie können als Argumente an Funktionen übergeben werden.
|
||||
- Functions can be passed as arguments to other functions.
|
||||
|
||||
|
||||
```{julia}
|
||||
# sehr naive numerische Integration
|
||||
# naive Riemann integration example
|
||||
|
||||
function Riemann_integrate(f, a, b; NInter=1000)
|
||||
delta = (b-a)/NInter
|
||||
@@ -235,7 +245,7 @@ Riemann_integrate(sin, 0, π)
|
||||
```
|
||||
|
||||
|
||||
- Sie können von Funktionen erzeugt und als Ergebnis `return`t werden.
|
||||
- They can be created by functions and returned as results.
|
||||
|
||||
|
||||
|
||||
@@ -263,16 +273,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 local and inaccessible outside. An anonymous function can be used instead.
|
||||
|
||||
```{julia}
|
||||
generate_add_func(x) = y -> x + y
|
||||
```
|
||||
|
||||
|
||||
## Zusammensetzung von Funktionen: die Operatoren $\circ$ und `|>`
|
||||
## Function Composition: the Operators $\circ$ and `|>`
|
||||
|
||||
- Die Zusammensetzung _(composition)_ von Funktionen kann auch mit dem Operator $\circ$ (`\circ + Tab`) geschrieben werden
|
||||
- Function composition can also be written with the $\circ$ operator (`\circ + Tab`)
|
||||
|
||||
$$(f\circ g)(x) = f(g(x))$$
|
||||
|
||||
@@ -289,11 +299,11 @@ f(.2)
|
||||
|
||||
|
||||
```{julia}
|
||||
@show map(uppercase ∘ first, ["ein", "paar", "grüne", "Blätter"]);
|
||||
@show map(uppercase ∘ first, ["one", "a", "green", "leaves"]);
|
||||
```
|
||||
|
||||
|
||||
- Es gibt auch einen Operator, mit dem Funktionen "von rechts" wirken und zusammengesetzt werden können _(piping)_
|
||||
- There is also an operator with which functions can act "from the right" and be composed (_piping_)
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -306,37 +316,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:
|
||||
- These operators can also be broadcast (see @sec-broadcast). A vector of functions is applied element-wise to a vector of arguments:
|
||||
|
||||
```{julia}
|
||||
["a", "list", "of", "strings"] .|> [length, uppercase, reverse, titlecase]
|
||||
```
|
||||
|
||||
## Die `do`-Notation {#sec-do}
|
||||
## The `do` Notation {#sec-do}
|
||||
|
||||
Eine syntaktische Besonderheit zur Definition anonymer Funktionen als Argumente anderer Funktionen ist die `do`-Notation.
|
||||
A syntactic peculiarity for defining anonymous functions as arguments of other functions is the `do` notation.
|
||||
|
||||
Sei `higherfunc(f,a,...)` eine Funktion, deren 1. Argument eine Funktion ist.
|
||||
Let `higherfunc(f, a, ...)` be a function whose first argument is a function.
|
||||
|
||||
Dann kann man `higherfunc()` auch ohne erstes Argument aufrufen und statt dessen die Funktion in einem unmittelbar folgenden `do`-Block definieren:
|
||||
The function can be called without the first argument, with the function body defined in a 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 `do` notation is especially useful for complex function bodies, such as this integrand defined in multiple steps:
|
||||
```{julia}
|
||||
r = Riemann_integrate(0, π) do x
|
||||
z1 = sin(x)
|
||||
@@ -349,12 +359,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 method for a type, objects become *callable* like functions.
|
||||
|
||||
```{julia}
|
||||
# struct speichert die Koeffiziente eines Polynoms 2. Grades
|
||||
# struct stores coefficients of a second-degree polynomial
|
||||
struct Poly2Grad
|
||||
a0::Float64
|
||||
a1::Float64
|
||||
@@ -365,13 +375,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.
|
||||
Objects can now be used like functions:
|
||||
|
||||
```{julia}
|
||||
@show p2(5) p1(-0.7) p1;
|
||||
@@ -379,9 +389,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 such as `+`, `*`, `>`, `∈` are functions.
|
||||
|
||||
|
||||
|
||||
@@ -399,7 +409,7 @@ f = +
|
||||
f(3, 7)
|
||||
```
|
||||
|
||||
- Auch Konstruktionen wie `x[i]`, `a.x`, `[x; y]` werden vom Parser zu Funktionsaufrufen umgewandelt.
|
||||
- Constructions like `x[i]`, `a.x`, `[x; y]` are converted by the parser to function calls.
|
||||
|
||||
:::{.narrow}
|
||||
|
||||
@@ -410,53 +420,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, too, van be extended/overwritten by new 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: a new object created on the right is assigned to `x`.
|
||||
|
||||
Ein Speicherplatz- und Zeit-sparendes __in-place-update__ eines Arrays/Vektors/Matrix ist möglich entweder durch explizite Indizierung
|
||||
Memory- and time-efficient *in-place updates* of arrays use 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 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 like
|
||||
|
||||
```{julia}
|
||||
-2^3+500/2/10==8 && 13 > 7 + 1 || 9 < 2
|
||||
```
|
||||
|
||||
werden vom Parser in eine Baumstruktur überführt.
|
||||
are converted by the parser into a tree structure:
|
||||
```{julia}
|
||||
using TreeView
|
||||
|
||||
@@ -464,75 +474,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)
|
||||
- Expression evaluation is governed by
|
||||
- precedence and
|
||||
- associativity.
|
||||
- Precedence determines which operators bind more tightly, such as multiplication before addition.
|
||||
- Associativity determines the evaluation order for operators of equal precedence.
|
||||
- [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.
|
||||
Addition/subtraction and multiplication/division have equal precedence and are left-associative (evaluated 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.
|
||||
Julia provides functions to query associativity. These functions are not exported from `Base`, so the module name must be specified.
|
||||
|
||||
|
||||
```{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.
|
||||
Thus, 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_
|
||||
- Precedence 11 < 12 explains why multiplication/division bind tighter than addition/subtraction.
|
||||
- The power operator `^` has higher precedence.
|
||||
- Assignments have the lowest precedence.
|
||||
|
||||
|
||||
```{julia}
|
||||
# Zuweisung hat kleinsten Vorrang, daher Auswertung als x = (3 < 4)
|
||||
# assignment has smallest precedence, therefore evaluation as x = (3 < 4)
|
||||
|
||||
x = 3 < 4
|
||||
x
|
||||
@@ -540,11 +550,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:
|
||||
Returning to the example above:
|
||||
|
||||
```{julia}
|
||||
-2^3+500/2/10==8 && 13 > 7 + 1 || 9 < 2
|
||||
@@ -557,43 +567,43 @@ for i ∈ (:^, :+, :/, :(==), :&&, :>, :|| )
|
||||
println(Base.operator_precedence(i))
|
||||
end
|
||||
```
|
||||
Nach diesen Vorrangregeln wird der Beispielausdruck also wie folgt ausgewertet:
|
||||
These rules evaluate the expression as:
|
||||
|
||||
```{julia}
|
||||
((-(2^3)+((500/2)/10)==8) && (13 > (7 + 1))) || (9 < 2)
|
||||
```
|
||||
(Das entspricht natürlich dem oben gezeigten *parse-tree*)
|
||||
(as shown in the parse tree above).
|
||||
|
||||
Es gilt also für den Vorrang:
|
||||
So the precedence is:
|
||||
|
||||
> Potenz > Multiplikation/Division > Addition/Subtraktion > Vergleiche > logisches && > logisches || > Zuweisung
|
||||
> Power > Multiplication/Division > Addition/Subtraction > Comparisons > logical && > logical || > assignment
|
||||
|
||||
Damit wird ein Ausdruck wie
|
||||
Thus, an expression like
|
||||
```julia
|
||||
a = x <= y + z && x > z/2
|
||||
```
|
||||
sinnvoll ausgewertet als `a = ((x <= (y+z)) && (x < (z/2)))`
|
||||
is sensibly evaluated as `a = ((x <= (y+z)) && (x < (z/2)))`
|
||||
|
||||
|
||||
- Eine Besonderheit sind noch
|
||||
|
||||
- unäre Operatoren, also insbesondere `+` und `-` als Vorzeichen
|
||||
- _juxtaposition_, also Zahlen direkt vor Variablen oder Klammern ohne `*`-Symbol
|
||||
|
||||
Beide haben Vorrang noch vor Multiplikation und Division.
|
||||
- A special case is still
|
||||
|
||||
- unary operators, in particular `+` and `-` as signs
|
||||
- _juxtaposition_, i.e., numbers directly before variables or parentheses without `*` symbol
|
||||
|
||||
Both have precedence even before multiplication and division.
|
||||
|
||||
:::{.callout-important}
|
||||
Damit ändert sich die Bedeutung von Ausdrücken, wenn man _juxtaposition_ anwendet:
|
||||
Therefore, the meaning of expressions changes when one applies _juxtaposition_:
|
||||
```{julia}
|
||||
1/2*π, 1/2π
|
||||
```
|
||||
:::
|
||||
|
||||
- Im Vergleich zum Potenzoperator `^` gilt (s. [https://discourse.julialang.org/t/confused-about-operator-precedence-for-2-3x/8214/7](https://discourse.julialang.org/t/confused-about-operator-precedence-for-2-3x/8214/7) ):
|
||||
- Compared to the power operator `^` (see [https://discourse.julialang.org/t/confused-about-operator-precedence-for-2-3x/8214/7](https://discourse.julialang.org/t/confused-about-operator-precedence-for-2-3x/8214/7) ):
|
||||
|
||||
> Unary operators, including juxtaposition, bind tighter than ^ on the right but looser on the left.
|
||||
|
||||
Beispiele:
|
||||
Examples:
|
||||
```{julia}
|
||||
-2^2 # -(2^2)
|
||||
```
|
||||
@@ -615,28 +625,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.
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
---
|
||||
engine: julia
|
||||
julia:
|
||||
exeflags: ["--color=yes"]
|
||||
---
|
||||
|
||||
```{julia}
|
||||
@@ -9,48 +11,48 @@ engine: julia
|
||||
using InteractiveUtils
|
||||
```
|
||||
|
||||
# Erste Miniprogramme
|
||||
# A Small Example Program
|
||||
|
||||
## What Skills Are Needed for Programming?
|
||||
|
||||
|
||||
## Was sollte man zum Programmieren können?
|
||||
- **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?
|
||||
- **Implementing the algorithm in 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, finding, and fixing errors in the algorithm must now be done.
|
||||
- **Intuition for the efficiency and complexity of algorithms**
|
||||
- **Specifics of computer arithmetic**, especially floating point numbers
|
||||
|
||||
These cannot all be mastered at once. Be patient with yourself and 'play' with the language.
|
||||
|
||||
- **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
|
||||
The following examples should serve as inspiration.
|
||||
|
||||
Das erschließt sich nicht alles auf einmal. Haben Sie Geduld mit sich und 'spielen' Sie mit der Sprache.
|
||||
|
||||
Das Folgende soll eine kleine Anregung dazu sein.
|
||||
|
||||
## Project Euler
|
||||
|
||||
Eine hübsche Quelle für Programmieraufgaben mit mathematischem Charakter und sehr unterschiedlichen Schwierigkeitsgraden ist [Project Euler](https://projecteuler.net/).
|
||||
Die Aufgaben sind so gestaltet, dass keinerlei Eingaben notwendig und das gesuchte Ergebnis eine einzige Zahl ist. So kann man sich voll auf das Programmieren des Algorithmus konzentrieren.
|
||||
A nice source for programming tasks with mathematical character and very different levels of difficulty is [Project Euler](https://projecteuler.net/).
|
||||
The tasks are designed so that no inputs are necessary and the desired result is a single number. This allows you to fully concentrate on programming the algorithm.
|
||||
|
||||
---------
|
||||
|
||||
### Beispiel 1
|
||||
### Example 1
|
||||
|
||||
::::::{.content-hidden unless-format="xxx"}
|
||||
::::::::{.content-hidden unless-format="xxx"}
|
||||
|
||||
https://github.com/luckytoilet/projecteuler-solutions/blob/master/Solutions.md
|
||||
https://math.stackexchange.com/questions/3370978/iterating-sum-of-squares-of-decimal-digits-of-an-integer-how-big-can-it-grow
|
||||
aufg. 92
|
||||
Aufg. 92
|
||||
|
||||
:::
|
||||
|
||||
::: {.callout-note icon=false .titlenormal}
|
||||
## Project Euler Problem No 1
|
||||
## Project Euler Problem No. 1
|
||||
|
||||
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
|
||||
|
||||
@@ -58,36 +60,36 @@ Find the sum of all the multiples of 3 or 5 below 1000.
|
||||
|
||||
:::
|
||||
|
||||
1. Algorithmus:
|
||||
- Teste alle natürlichen Zahlen <1000 auf Teilbarkeit durch 3 oder durch 5 und
|
||||
- summiere die teilbaren Zahlen auf.
|
||||
1. Algorithm:
|
||||
- Test all natural numbers <1000 for divisibility by 3 or 5 and
|
||||
- sum the divisible numbers.
|
||||
|
||||
2. Umsetzung:
|
||||
2. Implementation:
|
||||
|
||||
Wie liefert Julia den Rest der Ganzzahldivision? Solche Funktionen heißen typischerweise `rem()` (für *remainder*) oder `mod()`. [Nachlesen in der Doku](https://docs.julialang.org/en/v1/base/math/#Base.rem) oder ausprobieren von `?rem` und `?mod` in der Julia-REPL zeigt, dass es beides gibt. Der Unterschied liegt in der Behandlung negativer ganzer Zahlen. Für natürliche Zahlen `n,m` liefern `mod(n,m)` und `rem(n,m)` dasselbe und letzteres hat auch noch die Infix-Form `n % m`.
|
||||
|
||||
Wie testet man eine Reihe von Werten durch und summiert auf? Da gibt es ein Standardmuster: `for`-Schleife und Akkumulatorvariable:
|
||||
How does Julia provide the remainder of integer division? Functions like this are typically called `rem()` (for *remainder*) or `mod()`. You can look it up in the documentation or try `?rem` and `?mod` in the Julia REPL. Both functions exist; the difference lies in the treatment of negative integers. For natural numbers `n,m`, `mod(n,m)` and `rem(n,m)` give the same result, and the latter also has the infix form `n % m`.
|
||||
|
||||
How does one test a sequence of values and sum them up? There is a standard pattern: `for` loop and accumulator variable:
|
||||
|
||||
:::{.callout-caution icon="false" collapse="true" .titlenormal}
|
||||
|
||||
## Eine Lösungsvariante:
|
||||
## One possible solution:
|
||||
|
||||
```{julia}
|
||||
s = 0 # Akkumulatorvariable initialisieren
|
||||
for i in 1:999 # Schleife
|
||||
if i % 3 == 0 || i % 5 == 0 # Test
|
||||
s += i # Zu Akkumulator addieren
|
||||
end # Ende Test
|
||||
end # Ende Schleife
|
||||
println(" Die Antwort ist: $s") # Ausgabe des Ergebnisses
|
||||
s = 0 # initialize accumulator variable
|
||||
for i in 1:999 # loop
|
||||
if i % 3 == 0 || i % 5 == 0 # test
|
||||
s += i # add to accumulator
|
||||
end # end test
|
||||
end # end loop
|
||||
println("The answer is: $s") # output result
|
||||
```
|
||||
:::
|
||||
|
||||
Natürlich geht das auch etwas kürzer:
|
||||
Of course, this can also be done a bit shorter:
|
||||
|
||||
:::{.callout-caution icon="false" collapse="true" .titlenormal}
|
||||
|
||||
## Noch eine Lösungsvariante:
|
||||
## Another solution:
|
||||
|
||||
```{julia}
|
||||
sum([i for i in 1:999 if i%3==0||i%5==0])
|
||||
@@ -98,11 +100,11 @@ sum([i for i in 1:999 if i%3==0||i%5==0])
|
||||
|
||||
-----------
|
||||
|
||||
### Beispiel 2
|
||||
### Example 2
|
||||
|
||||
|
||||
::: {.callout-note icon=false .titlenormal}
|
||||
## Project Euler Problem No 92
|
||||
## Project Euler Problem No. 92
|
||||
A number chain is created by continuously adding the square of the digits in a number to form a new number until it has been seen before.
|
||||
|
||||
For example,
|
||||
@@ -115,41 +117,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 approach works through 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
|
||||
We want to investigate how numbers behave under repeated calculation of the 'square digit sum' (sum of squares of digits). Therefore, 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 base 10:
|
||||
|
||||
```{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 n is 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:
|
||||
Let's test it now:
|
||||
```{julia}
|
||||
for i in [1, 7, 33, 111, 321, 1000, 73201]
|
||||
j = q2sum(i)
|
||||
println("Quadratquersumme von $i = $j")
|
||||
println("Square digit sum of $i = $j")
|
||||
end
|
||||
```
|
||||
|
||||
Im Sinne der Aufgabe wenden wir die Funktion wiederholt an:
|
||||
In the spirit of the task, we apply the function repeatedly:
|
||||
|
||||
```{julia}
|
||||
n = 129956799
|
||||
@@ -158,48 +160,48 @@ for i in 1:14
|
||||
println(n)
|
||||
end
|
||||
```
|
||||
... und haben hier einen der '89er Zyklen' getroffen.
|
||||
... and we have now 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 cycle
|
||||
return true # 89 cycle 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
|
||||
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)
|
||||
|
||||
125
chapters/Pi2.qmd
125
chapters/Pi2.qmd
@@ -9,72 +9,71 @@ engine: julia
|
||||
using InteractiveUtils
|
||||
```
|
||||
|
||||
```{julia}
|
||||
#| error: false
|
||||
#| echo: false
|
||||
#| output: false
|
||||
flush(stdout)
|
||||
```
|
||||
|
||||
# Ein Beispiel zur Stabilität von Gleitkommaarithmetik
|
||||
# A Case Study on Floating-Point Arithmetic Stability
|
||||
|
||||
This chapter is inspired by the example in *Christoph Überhuber*, "Computer-Numerik" Vol. 1, Springer 1995, Chap. 2.3.
|
||||
|
||||
## Calculation of $\pi$ According to Archimedes
|
||||
|
||||
## Berechnung von $\pi$ nach Archimedes
|
||||
|
||||
Eine untere Schranke für $2\pi$, den Umfang des Einheitskreises, erhält man durch die
|
||||
Summe der Seitenlängen eines dem Einheitskreis eingeschriebenen regelmäßigen $n$-Ecks.
|
||||
Die Abbildung links zeigt, wie man beginnend mit einem Viereck der Seitenlänge $s_4=\sqrt{2}$ die Eckenzahl iterativ verdoppelt.
|
||||
A lower bound for $2\pi$ -- the circumference of the unit circle -- is obtained by summing
|
||||
the side lengths of a regular $n$-gon inscribed in the unit circle.
|
||||
The figure on the left illustrates the iterative doubling of the number of vertices starting from a square with side length $$s_4=\sqrt{2}$$.
|
||||
|
||||
:::{.narrow}
|
||||
|
||||
| Abb. 1 | Abb.2 |
|
||||
| Fig. 1 | Fig. 2 |
|
||||
| :-: | :-: |
|
||||
|  |  |
|
||||
: {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{and } \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|
|
||||
$$
|
||||
|
||||
## Two Iteration Formulas
|
||||
|
||||
## Zwei Iterationsvorschriften^[nach: Christoph Überhuber, „Computer-Numerik“ Bd. 1, Springer 1995, Kap. 2.3]
|
||||
Die Gleichung
|
||||
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!)
|
||||
|
||||
|
||||
|
||||
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 approximation for $\pi$ for both formulae iteration.
|
||||
|
||||
```{julia}
|
||||
using Printf
|
||||
@@ -82,16 +81,16 @@ 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
|
||||
@@ -102,77 +101,67 @@ 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 to a value accurate within machine precision, Iteration A is unstable and diverges. 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 numerical 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 computing $s_{2n}=\sqrt{2-a_n}$ leads to a catastrophic cancellation.
|
||||
|
||||
```{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.
|
||||
This demonstrates the loss of significant digits. It also shows that using `BigFloat` with 80 bits of precission (mantissa length) 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.
|
||||
|
||||
:::
|
||||
:::
|
||||
|
||||
@@ -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)
|
||||
## Installing on Your Own 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:
|
||||
Getting started:
|
||||
|
||||
- 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: the 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 from the command line, the [Julia-REPL](https://docs.julialang.org/en/v1/stdlib/REPL/) (*read-eval-print* loop) opens, allowing interactive work.
|
||||
|
||||
|
||||
```default
|
||||
$ julia
|
||||
_
|
||||
_ _ _(_)_ | Documentation: https://docs.julialang.org
|
||||
(_) | (_) (_) |
|
||||
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
|
||||
| | | | | | |/ _` | |
|
||||
| | |_| | | | (_| | | Version 1.11.4 (2025-03-10)
|
||||
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|
||||
_
|
||||
_ _ _(_)_ | Documentation: https://docs.julialang.org
|
||||
(_) | (_) (_) |
|
||||
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
|
||||
| | | | | | |/ _` | |
|
||||
| | |_| | | | (_| | | Version 1.12.5 (2026-02-09)
|
||||
_/ |\__'_|_|_|\__'_| | 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
|
||||
- Originally written for and in Python, but now supports many programming languages
|
||||
- In Jupyter, one works with so-called *notebooks*: structured text files (JSON) with 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"}
|
||||

|
||||
:::
|
||||
|
||||
::: {.content-visible when-format="pdf"}
|
||||
{width=50%}
|
||||
::: {.content-visible when-format="typst"}
|
||||
{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 your local computer,
|
||||
- log out when finished (Please don't forget this!)
|
||||
|
||||
### Jupyter notebooks
|
||||
|
||||
@@ -77,37 +75,37 @@ Mit diesem kann man:
|
||||

|
||||
:::
|
||||
|
||||
::: {.content-visible when-format="pdf"}
|
||||
::: {.content-visible when-format="typst"}
|
||||
{width=50%}
|
||||
:::
|
||||
|
||||
|
||||
*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` topics 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` |
|
||||
| *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` |
|
||||
| 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` |
|
||||
|
||||
: {.striped}
|
||||
|
||||
@@ -117,30 +115,28 @@ Die Zelle, die man gerade bearbeitet, kann im `command mode` oder `edit mode` se
|
||||

|
||||
:::
|
||||
|
||||
::: {.content-visible when-format="pdf"}
|
||||
{width=50%}
|
||||
::: {.content-visible when-format="typst"}
|
||||
{width=50%}
|
||||
:::
|
||||
|
||||
|
||||
When a cell is working, its cell number becomes a `*` and
|
||||
the `kernel busy` indicator appears (solid black dot at the top right next to the
|
||||
Julia version). If this takes too long (an *infinite loop*
|
||||
can easily happen):
|
||||
|
||||
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 doesn't work,
|
||||
- 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 each session, please always:**
|
||||
|
||||
- `Menu -> File -> Save & Checkpoint`
|
||||
- `Menu -> File -> Close & Halt`
|
||||
- `Logout`
|
||||
- `Menu -> File -> Save & Checkpoint`
|
||||
- `Menu -> File -> Close & Halt`
|
||||
- `Logout`
|
||||
:::
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
---
|
||||
engine: julia
|
||||
julia:
|
||||
exeflags: ["--color=yes"]
|
||||
---
|
||||
|
||||
```{julia}
|
||||
@@ -11,10 +13,10 @@ using InteractiveUtils
|
||||
|
||||
# First Contact
|
||||
|
||||
Dieses Kapitel soll beim 'Loslegen' helfen. Es läßt viele Details weg und die Codebeispiele sind oft eher suboptimal.
|
||||
This chapter helps you get started. It omits many details, and the code examples are often not optimal.
|
||||
|
||||
|
||||
## Julia als Taschenrechner
|
||||
## Julia as a Calculator
|
||||
|
||||
```{julia}
|
||||
#| eval: true
|
||||
@@ -33,7 +35,7 @@ function Tab(s)
|
||||
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
|
||||
return # return nothing, since broadcasting println produces an empty vector
|
||||
end
|
||||
|
||||
▷ = |>
|
||||
@@ -41,23 +43,23 @@ 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 the following: $\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 operator `*` can be omitted after a number when followed by a variable, function, or opening 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, press the Tab key as soon as you've typed 2–3 letters of a word. Potential completions are then displayed or completed if the completion is unique. This saves time and you learn a lot about Julia.
|
||||
|
||||
```{julia}
|
||||
lo = "lo" #| hide_line
|
||||
@@ -69,33 +71,41 @@ pri = "pri" #| hide_line
|
||||
pri ▷ Tab
|
||||
```
|
||||
|
||||
Die eingebaute Julia-Hilfe `?name` zu allen Funktionen und Konstrukten ist sehr umfassend. Hier ein eher kurzes Beispiel:
|
||||
Julia's built-in help system `?name` provides comprehensive documentation for all functions and constructs. Here is a relatively brief example:
|
||||
|
||||
:::{.content-visible unless-format="typst"}
|
||||
|
||||
```{julia}
|
||||
?for
|
||||
```
|
||||
:::
|
||||
|
||||
:::{.content-hidden unless-format="xxx"}
|
||||
:::{.content-hidden unless-format="typst"}
|
||||
|
||||
::: {.cell }
|
||||
``` {.julia .cell-code}
|
||||
```{.julia .cell-code}
|
||||
?for
|
||||
```
|
||||
|
||||
::: {.cell-output .cell-output-stdout}
|
||||
```
|
||||
search: for foreach foldr floor mapfoldr factorial EOFError OverflowError
|
||||
search: for nor xor foldr floor Core sort
|
||||
|
||||
for loops repeatedly evaluate a block of statements while iterating over a sequence of values.
|
||||
for
|
||||
|
||||
Examples
|
||||
for loops repeatedly evaluate a block of statements while iterating over a sequence of values.
|
||||
|
||||
julia> for i in [1, 4, 0]
|
||||
println(i)
|
||||
end
|
||||
1
|
||||
4
|
||||
0
|
||||
The iteration variable is always a new variable, even if a variable of the same name exists in the enclosing scope. Use outer to reuse an existing local variable for iteration.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
julia> for i in [1, 4, 0]
|
||||
println(i)
|
||||
end
|
||||
1
|
||||
4
|
||||
0
|
||||
|
||||
```
|
||||
:::
|
||||
@@ -103,101 +113,104 @@ 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 `=`.
|
||||
|
||||
```{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
|
||||
where every object has a type. Among the fundamental types are:
|
||||
|
||||
- Ganze Zahlen *(integers)*,
|
||||
- Gleitkommazahlen *(floating point numbers)*,
|
||||
- Zeichenketten *(strings)* und
|
||||
- Wahrheitswerte *(booleans)*.
|
||||
|
||||
Den Typ einer Variablen kann man mit der Funktion `typeof()` ermitteln.
|
||||
- Integers
|
||||
- Floating-point numbers
|
||||
- Strings
|
||||
- Booleans.
|
||||
|
||||
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 typed 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 adds a line break at the end; `print()` does not.
|
||||
```{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 string literals 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 escape it with a *backslash*. To print a *backslash* itself, 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 a `return` statement.
|
||||
```{julia}
|
||||
function hypotenuse(a, b) # heute besonders umständlich
|
||||
function hypotenuse(a, b) # a bit cumbersome
|
||||
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 definition, the function can be used (called). The variables `a,b,c,c2` used in the definition are local and not available outside the function definition.
|
||||
```{julia}
|
||||
#| error: true
|
||||
x = 3
|
||||
@@ -206,72 +219,71 @@ println("z = $z")
|
||||
println("c = $c")
|
||||
```
|
||||
|
||||
Sehr einfache Funktionen können auch als Einzeiler definiert werden.
|
||||
Very simple functions can also be defined as one-liners:
|
||||
```{julia}
|
||||
hypotenuse(a, b) = sqrt(a^2+b^2)
|
||||
```
|
||||
|
||||
|
||||
## Tests
|
||||
Tests liefern einen Wahrheitswert zurück.
|
||||
Tests return a Boolean value (`true` or `false`).
|
||||
```{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. 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
|
||||
|
||||
## Conditional Statements
|
||||
|
||||
A simple `if` statement has the form
|
||||
```default
|
||||
if <Test>
|
||||
<Anweisung1>
|
||||
<Anweisung2>
|
||||
if <test>
|
||||
<statement1>
|
||||
<statement2>
|
||||
...
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
Ein `else`-Zweig und `elseif`-Zweige sind möglich.
|
||||
There can be one or more `elseif` blocks and an optional final `else` block.
|
||||
```{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 enhances readability but is optional. Line breaks separate statements, as do semicolons. The code above is equivalent to the following single 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!
|
||||
|
||||
|
||||
## Einfache `for`-Schleifen
|
||||
## Simple `for` loops
|
||||
|
||||
zum wiederholten Abarbeiten von Anweisungen haben die Form
|
||||
`for` loops for repeating the execution of statements have the form
|
||||
```default
|
||||
for <Zähler> = Start:Ende
|
||||
<Anweisung1>
|
||||
<Anweisung2>
|
||||
for <counter> = start:end
|
||||
<statement1>
|
||||
<statement2>
|
||||
...
|
||||
end
|
||||
```
|
||||
Beispiel:
|
||||
Example:
|
||||
|
||||
```{julia}
|
||||
sum = 0
|
||||
@@ -281,9 +293,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.
|
||||
One-dimensional arrays (vectors) are a simple container type. They can be created with square brackets
|
||||
and accessed by index, with indexing starting at 1.
|
||||
|
||||
```{julia}
|
||||
v = [12, 33.2, 17, 19, 22]
|
||||
@@ -298,17 +311,18 @@ v[1] = v[4] + 10
|
||||
v
|
||||
```
|
||||
|
||||
Man kann leere Vektoren anlegen und sie verlängern.
|
||||
Empty vectors can be created and extended with `push!()`.
|
||||
```{julia}
|
||||
v = [] # leerer Vektor
|
||||
v = [] # empty vector
|
||||
push!(v, 42)
|
||||
push!(v, 13)
|
||||
v
|
||||
```
|
||||
|
||||
|
||||
:::{.callout-note icon="false" .titlenormal collapse="true" font-variant-ligatures="no-contextual" }
|
||||
|
||||
## Nachtrag: wie die Wirkung der Tab-Taste auf dieser Seite simuliert wurde...
|
||||
## Appendix: how the effect of the Tab key was simulated on this page
|
||||
|
||||
```{julia}
|
||||
using REPL
|
||||
|
||||
@@ -1,8 +1,34 @@
|
||||
---
|
||||
engine: julia
|
||||
julia:
|
||||
exeflags: ["--color=yes"]
|
||||
---
|
||||
|
||||
# Maschinenzahlen
|
||||
```{julia}
|
||||
#| error: false
|
||||
#| echo: false
|
||||
#| output: false
|
||||
using InteractiveUtils
|
||||
|
||||
#struct M a::Int end; x = M(22); @show x
|
||||
#should not print "Main.Notebook.M(22)" but only "M(22)"
|
||||
function Base.show(io::IO, x::T) where T
|
||||
if parentmodule(T) == @__MODULE__
|
||||
# Print "TypeName(fields...)" without module prefix
|
||||
print(io, nameof(T), "(")
|
||||
fields = fieldnames(T)
|
||||
for (i, f) in enumerate(fields)
|
||||
print(io, getfield(x, f))
|
||||
i < length(fields) && print(io, ", ")
|
||||
end
|
||||
print(io, ")")
|
||||
else
|
||||
invoke(Base.show, Tuple{IO, Any}, io, x)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
# Machine Numbers
|
||||
|
||||
```{julia}
|
||||
#| error: false
|
||||
@@ -18,24 +44,24 @@ for x ∈ ( 3, 3.3e4, Int16(20), Float32(3.3e4), UInt16(9) )
|
||||
end
|
||||
```
|
||||
|
||||
## Ganze Zahlen *(integers)*
|
||||
## 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.
|
||||
Integers are stored as fixed-length bit patterns. 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` 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 a bit width of 8, 16, 32, 64, or 128 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 rarely in *scientific computing*. In low-level hardware programming, they are used, e.g., for handling binary data and memory addresses. By default, Julia displays them as hexadecimal numbers (with prefix `0x` and digits `0-9a-f`).
|
||||
|
||||
```{julia}
|
||||
x = 0x0033efef
|
||||
@@ -50,51 +76,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:
|
||||
By the way, the maximum value $2^{31}-1$ is 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 as follows:
|
||||
|
||||
::: {.content-visible when-format="html"}
|
||||
{width=50%}
|
||||
{width=50%}
|
||||
:::
|
||||
|
||||
::: {.content-visible when-format="pdf"}
|
||||
{width=50%}
|
||||
::: {.content-visible when-format="typst"}
|
||||
{width=50%}
|
||||
:::
|
||||
|
||||
Das höchstwertige Bit zeigt das Vorzeichen an. Sein „Umkippen“ entspricht allerdings nicht der Operation `x → -x`.
|
||||
The most significant bit indicates the sign. However, its "flipping" does not correspond to the operation `x → -x`.
|
||||
|
||||
:::{.callout-important}
|
||||
Die gesamte Ganzzahlarithmetik ist eine __Arithmetik modulo $2^n$__
|
||||
All integer arithmetic is __arithmetic modulo $2^n$__
|
||||
|
||||
```{julia}
|
||||
x = 2^62 - 10 + 2^62
|
||||
@@ -102,11 +128,11 @@ x = 2^62 - 10 + 2^62
|
||||
```{julia}
|
||||
x + 20
|
||||
```
|
||||
Keine Fehlermeldung, keine Warnung! Ganzzahlen fester Länge liegen nicht auf einer Geraden, sondern auf einem Kreis!
|
||||
No error message, no warning! Fixed-length integers do not lie on a line, but on a **circle.**
|
||||
|
||||
:::
|
||||
|
||||
Schauen wir uns ein paar *Integers* an:
|
||||
Let's look at a few *integers*:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -119,7 +145,7 @@ for i in (1, 2, 7, -7, 2^50, -1, Int16(7), Int8(7))
|
||||
end
|
||||
```
|
||||
|
||||
Julia hat Funktionen, die über die Datentypen informieren (*introspection*):
|
||||
Julia has functions that provide type information (*introspection*):
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -134,36 +160,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 `Float`.
|
||||
- `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://en.wikipedia.org/wiki/Exponentiation_by_squaring) 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 uses "rounding toward zero", so the corresponding remainder has the same sign as the dividend `a`:
|
||||
|
||||
```{julia}
|
||||
@show divrem( 27, 4)
|
||||
@@ -172,9 +198,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 these functions.
|
||||
- `?RoundingMode` shows the possible rounding modes.
|
||||
- For the rounding rule `RoundDown` ("toward minus infinity" -- so that the corresponding remainder has the same sign as the divisor `b`), there are also the functions `fld(a,b)` *(floored division)* and `mod(a,b)`:
|
||||
|
||||
```{julia}
|
||||
@show divrem(-27, 4, RoundDown)
|
||||
@@ -182,47 +208,47 @@ x = 40/5
|
||||
@show (fld( 27, -4), mod( 27, -4));
|
||||
```
|
||||
|
||||
Für alle Rundungsregeln gilt:
|
||||
For all rounding modes, the following 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 supports arbitrary-precision integers with dynamically allocated memory.
|
||||
|
||||
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:
|
||||
In most cases, you must explicitly specify 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` versus `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:
|
||||
The `@time` macro provides a rough estimate of the required time and memory:
|
||||
|
||||
```{julia}
|
||||
@time x = sum(vec_int)
|
||||
@@ -233,7 +259,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, timing a single function call is not very informative. The `BenchmarkTools` package provides the `@benchmark` macro, which calls a function multiple times and displays the execution times as a histogram.
|
||||
|
||||
:::{.ansitight}
|
||||
```{julia}
|
||||
@@ -247,13 +273,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 computes the sum of all numbers from 1 to n using arithmetic of type T.
|
||||
Due to *type promotion rules*, it is sufficient to initialize the accumulator with a value of type T (for `T ≥ Int64`).
|
||||
```{julia}
|
||||
function mysum(n, T)
|
||||
s = T(0)
|
||||
@@ -264,7 +288,7 @@ function mysum(n, T)
|
||||
end
|
||||
```
|
||||
|
||||
Einen ersten Eindruck vom Zeit- und Speicherbedarf gibt das `@time`-Macro:
|
||||
An initial impression of the time and memory requirements is provided by the `@time` macro:
|
||||
|
||||
```{julia}
|
||||
@time x = mysum(10_000_000, Int64)
|
||||
@@ -276,7 +300,7 @@ Einen ersten Eindruck vom Zeit- und Speicherbedarf gibt das `@time`-Macro:
|
||||
@show x typeof(x);
|
||||
```
|
||||
|
||||
Durch die Just-in-Time-Compilation von Julia ist die einmalige Ausführung einer Funktion wenig aussagekräftig. Das Paket `BenchmarkTools` stellt u.a. das Macro `@benchmark` bereit, das eine Funktion mehrfach aufruft und die Ausführungszeiten als Histogramm darstellt.
|
||||
Due to Julia's just-in-time compilation, a single execution of a function is not very informative. The `BenchmarkTools` package provides the `@benchmark` macro, which calls a function multiple times and displays the execution times as a histogram.
|
||||
|
||||
:::{.ansitight}
|
||||
```{julia}
|
||||
@@ -292,85 +316,83 @@ 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 milliseconds with standard 64-bit integers and over one second in *arbitrary precision arithmetic*, during which nearly 500MB of memory is also allocated.
|
||||
|
||||
:::
|
||||
:::
|
||||
|
||||
|
||||
## Gleitkommazahlen
|
||||
|
||||
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.
|
||||
|
||||
In der Numerischen Mathematik spricht man auch gerne von **Maschinenzahlen**.
|
||||
## Floating-Point Numbers
|
||||
|
||||
|
||||
### Grundidee
|
||||
In numerical mathematics, the term **machine numbers** is also commonly used.
|
||||
|
||||
- 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.
|
||||
|
||||
### Basic Idea
|
||||
|
||||
- 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$, 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$) 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 the [IEEE 754 standard](https://en.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"}
|
||||
{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 number represented is:
|
||||
$$ 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 displayed more clearly:
|
||||
|
||||
```{julia}
|
||||
function printbitsf64(x::Float64)
|
||||
@@ -383,7 +405,7 @@ end
|
||||
|
||||
printbitsf64(x)
|
||||
```
|
||||
und wir können S (in blau),E (grün) und M (rot) ablesen:
|
||||
and we can read S (blue), E (green), and M (red):
|
||||
$$
|
||||
\begin{aligned}
|
||||
S &= 0\\
|
||||
@@ -394,15 +416,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 set of machine numbers 𝕄 forms a finite, discrete subset of ℝ. There exists a smallest and a largest machine number; all other elements x∈𝕄 have both 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:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -410,13 +432,13 @@ ux = parse(UInt64, "010000000011101110010001000000000000000000000000000000000000
|
||||
reinterpret(Float64, ux)
|
||||
```
|
||||
|
||||
Das kann man in Julia allerdings auch einfacher haben:
|
||||
However, Julia can do this more simply:
|
||||
|
||||
```{julia}
|
||||
y = nextfloat(x)
|
||||
```
|
||||
|
||||
Der Vorgänger von x ist:
|
||||
The predecessor of x is:
|
||||
|
||||
```{julia}
|
||||
z = prevfloat(x)
|
||||
@@ -426,32 +448,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 measures 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 should not be confused with 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$.*
|
||||
$$
|
||||
This 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 $1+\epsilon' = 1$ still holds in machine arithmetic.*
|
||||
|
||||
Auf diese Weise kann man das Maschinenepsilon auch berechnen:
|
||||
This allows to compute machine epsilon using the floating point arithmetic:
|
||||
|
||||
:::{.ansitight}
|
||||
|
||||
@@ -464,7 +484,7 @@ end
|
||||
Eps
|
||||
```
|
||||
|
||||
oder als Bitmuster:
|
||||
or as a bit pattern:
|
||||
|
||||
```{julia}
|
||||
Eps=1
|
||||
@@ -478,19 +498,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 we have
|
||||
$$
|
||||
𝕄 = -𝕄_+ \cup \{0\} \cup 𝕄_+
|
||||
$$
|
||||
|
||||
:::
|
||||
|
||||
Die größte und die kleinste positive normalisiert darstellbare Gleitkommazahl eines Gleitkommatyps kann man abfragen:
|
||||
The largest and smallest positive representable normalized floating-point numbers of a floating-point type can be queried:
|
||||
|
||||
```{julia}
|
||||
@show floatmax(Float64)
|
||||
@@ -502,37 +522,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 map rd: ℝ $\rightarrow$ 𝕄 should round to the nearest representable number.
|
||||
- Standard rounding mode is _round to nearest, ties to even_:
|
||||
when a value falls exactly midway between two machine numbers *(tie)*, the one with 0 as its last mantissa bit is selected.
|
||||
- Justification: this way, we round up in 50% of the cases and down in 50% of the cases, 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 is generally not representable as a machine number.
|
||||
|
||||
:::{.callout-important}
|
||||
Der Standard IEEE 754 fordert, dass die Maschinenzahlarithmetik das *gerundete exakte Ergebnis* liefert:
|
||||
The IEEE 754 standard requires that machine number arithmetic produces the *rounded exact result*:
|
||||
|
||||
Das Resultat muss gleich demjenigen sein, das bei einer exakten Ausführung der entsprechenden Operation mit anschließender Rundung entsteht.
|
||||
The result must be equal to the one that would result from an exact execution of the corresponding operation followed by rounding.
|
||||
$$
|
||||
a \oplus b = \text{rd}(a + b)
|
||||
$$
|
||||
Analoges muss für die Implemetierung der Standardfunktionen wie
|
||||
wie `sqrt()`, `log()`, `sin()` ... gelten: Sie liefern ebenfalls die Maschinenzahl, die dem exakten Ergebnis am nächsten kommt.
|
||||
The same must hold for the implementation of standard functions such as
|
||||
`sqrt()`, `log()`, `sin()`, ... -- they also return the machine number closest to the exact result.
|
||||
:::
|
||||
|
||||
|
||||
Die Arithmetik ist *nicht assoziativ*:
|
||||
Arithmetic is *not associative*:
|
||||
|
||||
```{julia}
|
||||
1 + 10^-16 + 10^-16
|
||||
@@ -542,7 +560,7 @@ Die Arithmetik ist *nicht assoziativ*:
|
||||
1 + (10^-16 + 10^-16)
|
||||
```
|
||||
|
||||
Im ersten Fall (ohne Klammern) wird von links nach rechts ausgewertet:
|
||||
In the first case (without parentheses), evaluation proceeds from left to right:
|
||||
$$
|
||||
\begin{aligned}
|
||||
1 \oplus 10^{-16} \oplus 10^{-16} &=
|
||||
@@ -553,7 +571,7 @@ $$
|
||||
\end{aligned}
|
||||
$$
|
||||
|
||||
Im zweiten Fall erhält man:
|
||||
In the second case, one obtains:
|
||||
$$
|
||||
\begin{aligned}
|
||||
1 \oplus \left(10^{-16} \oplus 10^{-16}\right) &=
|
||||
@@ -564,22 +582,21 @@ $$
|
||||
$$
|
||||
|
||||
|
||||
Es sei auch daran erinnert, dass sich selbst „einfache“ Dezimalbrüche häufig nicht exakt als Maschinenzahlen darstellen lassen:
|
||||
One should also remember that even "simple" decimal fractions cannot always be represented exactly as machine numbers:
|
||||
|
||||
$$
|
||||
\begin{aligned}
|
||||
(0.1)_{10} &= (0.000110011001100110011001100...)_2 = (0.000\overline{1100})_2 \\
|
||||
(0.3)_{10} &= (0.0100110011001100110011001100..)_2 = (0.0\overline{1001})_2
|
||||
\end{aligned}
|
||||
$$
|
||||
|
||||
\end{aligned}
|
||||
$$
|
||||
|
||||
```{julia}
|
||||
printbitsf64(0.1)
|
||||
printbitsf64(0.3)
|
||||
```
|
||||
|
||||
Folge:
|
||||
Consequence:
|
||||
|
||||
```{julia}
|
||||
0.1 + 0.1 == 0.2
|
||||
@@ -593,7 +610,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. Julia can display more digits of this decimal fraction expansion:
|
||||
```{julia}
|
||||
using Printf
|
||||
@printf("%.30f", 0.1)
|
||||
@@ -602,12 +619,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. But
|
||||
one should not be misled into thinking that this 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:
|
||||
Key message: When testing `Float`s for equality, one should almost always define a realistic tolerance `epsilon` appropriate to the problem and
|
||||
test:
|
||||
|
||||
```julia
|
||||
epsilon = 1.e-10
|
||||
@@ -618,23 +635,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:
|
||||
Let's look at 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 essential that machine numbers remain normalized at each computation step. Only then is the full mantissa length utilized, maximizing accuracy.
|
||||
- The smallest positive normalized number in our model is `x = 1.000e-5`. Already `x/2` would have to be rounded to 0.
|
||||
- But for many applications, it is advantageous to allow also subnormal numbers and represent `x/2` as `0.500e-5` or `x/20` as `0.050e-5`.
|
||||
- This *gradual underflow* is of course associated with a loss of significant digits and thus accuracy.
|
||||
|
||||
|
||||
Im `Float`-Datentyp werden solche *subnormal values* dargestellt durch ein Exponentenfeld, in dem alle Bits gleich Null sind:
|
||||
In the `Float` data type, such *subnormal values* are represented by an exponent field in which all bits are equal to zero:
|
||||
|
||||
```{julia}
|
||||
#| echo: false
|
||||
@@ -647,7 +663,7 @@ flush(stdout)
|
||||
```{julia}
|
||||
using Printf
|
||||
|
||||
x = 2 * floatmin(Float64) # 2*kleinste normalisierte Gleitkommazahl > 0
|
||||
x = 2 * floatmin(Float64) # 2*smallest normalized floating-point number > 0
|
||||
|
||||
while x != 0
|
||||
x /= 2
|
||||
@@ -657,9 +673,9 @@ end
|
||||
```
|
||||
:::
|
||||
|
||||
## Spezielle Werte
|
||||
## Special Values
|
||||
|
||||
Die Gleitkommaarithmetik kennt einige spezielle Werte, z.B.
|
||||
Floating-point arithmetic defines certain special values, e.g.,
|
||||
```{julia}
|
||||
nextfloat(floatmax(Float64))
|
||||
```
|
||||
@@ -671,23 +687,22 @@ for x ∈ (NaN, Inf, -Inf, -0.0)
|
||||
end
|
||||
```
|
||||
|
||||
- Ein Exponentenüberlauf *(overflow)* führt zum Ergebnis `Inf` oder `-Inf`.
|
||||
- An exponent 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 these values:
|
||||
|
||||
```{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)* represents the result of an undefined operation. All further operations with `NaN` also result in `NaN`.
|
||||
|
||||
```{julia}
|
||||
0/0, Inf - Inf, 2.3NaN, sqrt(NaN)
|
||||
```
|
||||
|
||||
- Da `NaN` einen undefinierten Wert repräsentiert, ist es zu nichts gleich, nichtmal zu sich selbst. Das ist sinnvoll, denn wenn zwei Variablen `x` und `y` als `NaN` berechnet wurden, sollte man nicht schlußfolgern, dass sie gleich sind.
|
||||
- Zum Testen auf `NaN` gibt es daher die boolsche Funktion `isnan()`.
|
||||
- Since `NaN` represents an undefined value, it is not equal to anything, not even to itself. This is sensible, because if two variables `x` and `y` are computed as `NaN`, one should not conclude that they are equal.
|
||||
- There is therefore a boolean function `isnan()` to test for `NaN`.
|
||||
|
||||
```{julia}
|
||||
x = 0/0
|
||||
@@ -695,18 +710,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 a numerical underflow of a 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://en.wikipedia.org/wiki/Floor_and_ceiling_functions)
|
||||
|
||||
- `floor(T,x)` = $\lfloor x \rfloor$
|
||||
- `ceil(T,x)` = $\lceil x \rceil$
|
||||
@@ -719,19 +734,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 (known as `atan2` in many programming languages, see [atan2](https://en.wikipedia.org/wiki/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 Between Strings and Numbers
|
||||
|
||||
Die Umwandlung ist mit den Funktionen `parse()` und `string()` möglich.
|
||||
Use the functions `parse()` and `string()` for such conversions:
|
||||
|
||||
```{julia}
|
||||
parse(Int64, "1101", base=2)
|
||||
@@ -749,7 +764,7 @@ string(1/7)
|
||||
string(77, base=16)
|
||||
```
|
||||
|
||||
Zur Umwandlung der numerischen Typen ineinander kann man die Typnamen verwenden. Typenamen sind auch Konstruktoren:
|
||||
For conversion of numerical types into each other, one can use the type names. Type names are also constructors:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -768,7 +783,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)
|
||||
@@ -2,63 +2,72 @@
|
||||
engine: julia
|
||||
---
|
||||
|
||||
# Ein Fallbeispiel: Der parametrisierte Datentyp PComplex
|
||||
# Example: The Parametric Data Type `PComplex`
|
||||
|
||||
```{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
|
||||
|
||||
#struct M a::Int end; x = M(22); @show x
|
||||
#should not print "Main.Notebook.M(22)" but only "M(22)"
|
||||
function Base.show(io::IO, x::T) where T
|
||||
if parentmodule(T) == @__MODULE__
|
||||
# Print "TypeName(fields...)" without module prefix
|
||||
print(io, nameof(T), "(")
|
||||
fields = fieldnames(T)
|
||||
for (i, f) in enumerate(fields)
|
||||
print(io, getfield(x, f))
|
||||
i < length(fields) && print(io, ", ")
|
||||
end
|
||||
print(io, ")")
|
||||
else
|
||||
invoke(Base.show, Tuple{IO, Any}, io, x)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
Wir wollen als neuen numerischen Typen **komplexe Zahlen in Polardarstellung $z=r e^{i\phi}=(r,ϕ)$** einführen.
|
||||
We want to introduce a new numeric type **complex numbers in polar representation $z=r e^{i\phi}=(r,\phi)$**.
|
||||
|
||||
- Der Typ soll sich in die Typhierarchie einfügen als Subtyp von 'Number'.
|
||||
- $r$ und $\phi$ sollen Gleitkommazahlen sein. (Im Unterschied zu komplexen Zahlen in 'kartesischen' Koordinaten hat eine Einschränkung auf ganzzahlige Werte von r oder ϕ mathematisch wenig Sinn.)
|
||||
- The type should integrate into the type hierarchy as a subtype of 'Number'.
|
||||
- $r$ and $\phi$ should be floating point numbers. (Unlike complex numbers in 'Cartesian' coordinates, restricting to integer values of r or $\phi$ makes little mathematical sense.)
|
||||
|
||||
## Die Definition von `PComplex`
|
||||
## The Definition of `PComplex`
|
||||
|
||||
Ein erster Versuch könnte so aussehen:
|
||||
A first attempt could look like this:
|
||||
|
||||
```{julia}
|
||||
struct PComplex1{T <: AbstractFloat} <: Number
|
||||
struct PComplex{T <: AbstractFloat} <: Number
|
||||
r :: T
|
||||
ϕ :: T
|
||||
end
|
||||
|
||||
z1 = PComplex1(-32.0, 33.0)
|
||||
z2 = PComplex1{Float32}(12, 13)
|
||||
#const PComplex = Main.Notebook.PComplex #| hide_line
|
||||
#Base.show(io::IO, ::Type{PComplex}) = print(io, "PComplex") #| hide_line
|
||||
z1 = PComplex(-32.0, 33.0)
|
||||
z2 = PComplex{Float32}(12, 13)
|
||||
@show z1 z2;
|
||||
```
|
||||
|
||||
:::{.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).
|
||||
:::
|
||||
|
||||
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 `PComplex` infers type `T` from the arguments, and
|
||||
- Constructors like `PComplex{Float64}` accept explicit type specifications. Arguments are converted to the requested type.
|
||||
|
||||
------
|
||||
|
||||
Wir wollen nun, dass der Konstruktor noch mehr tut.
|
||||
In der Polardarstellung soll $0\le r$ und $0\le \phi<2\pi$ gelten.
|
||||
We now want the constructor to do even more.
|
||||
In the polar representation, we want $0\le r$ and $0\le \phi<2\pi$ to hold.
|
||||
|
||||
Wenn die übergebenen Argumente das nicht erfüllen, sollten sie entsprechend umgerechnet werden.
|
||||
If the passed arguments do not satisfy this, they should be recalculated accordingly.
|
||||
|
||||
Dazu definieren wir einen _inner constructor_, der den _default constructor_ ersetzt.
|
||||
To this end, we define an _inner constructor_ that replaces the _default constructor_.
|
||||
|
||||
- Ein _inner constructor_ ist eine Funktion innerhalb der `struct`-Definition.
|
||||
- In einem _inner constructor_ kann man die spezielle Funktion `new` verwenden, die wie der _default constructor_ wirkt.
|
||||
- An _inner constructor_ is a function within the `struct` definition.
|
||||
- In an _inner constructor_, one can use the special function `new`, which acts like the _default constructor_.
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -73,18 +82,17 @@ struct PComplex{T <: AbstractFloat} <: Number
|
||||
end
|
||||
if r==0 ϕ=0 end # normalize r=0 case to phi=0
|
||||
ϕ = mod(ϕ, 2π) # map phi into interval [0,2pi)
|
||||
new(r, ϕ) # new() ist special function,
|
||||
new(r, ϕ) # new() is special function,
|
||||
end # available only inside inner constructors
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
```{julia}
|
||||
#| echo: false
|
||||
#| output: false
|
||||
|
||||
#=
|
||||
in den ganzen quarto-runs wollen wir hier noch das default-show benutzen
|
||||
in the whole quarto-runs we want to use the default show here
|
||||
=#
|
||||
zz = @which Base.show(stdout, PComplex{Float64}(2.,3.))
|
||||
if zz.module != Base
|
||||
@@ -94,9 +102,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.
|
||||
However, explicitly specifying an *inner constructor* has a consequence: 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, which infers the type from the arguments, is also needed:
|
||||
|
||||
```{julia}
|
||||
PComplex(r::T, ϕ::T) where {T<:AbstractFloat} = PComplex{T}(r,ϕ)
|
||||
@@ -105,43 +113,53 @@ 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):
|
||||
|
||||
:::{.content-visible unless-format="typst"}
|
||||
$$
|
||||
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.
|
||||
:::
|
||||
|
||||
:::{.content-hidden unless-format="typst"}
|
||||
```{=typst}
|
||||
$ z = r angle.acute phi = 3.4 angle.acute 45 degree $
|
||||
```
|
||||
:::
|
||||
|
||||
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 a Julia operator. We use `⋖` as an alternative, entered 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` anticipates further constructors. Currently, the operator `⋖` works only with `Float64`.)
|
||||
|
||||
|
||||
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,
|
||||
# print phase in degrees, rounded to one decimal place
|
||||
p = z.ϕ * 180/π
|
||||
sp = @sprintf "%.1f" p
|
||||
print(io, z.r, "⋖", sp, '°')
|
||||
@@ -151,22 +169,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`, additional functionality is required: arithmetic operations, comparison operators, and conversions must all be defined.
|
||||
|
||||
|
||||
Wir beschränken uns auf Multiplikation und Quadratwurzeln.
|
||||
We focus on multiplication and square root operations.
|
||||
|
||||
|
||||
:::{.callout-note collapse="true"}
|
||||
## Module
|
||||
:::{.callout-note collapse="false"}
|
||||
## 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.
|
||||
- Adding methods to existing functions requires using their fully qualified names.
|
||||
- All objects belong to a namespace or `module`.
|
||||
- Most basic functions belong to `Base`, which is loaded automatically.
|
||||
- Without user-defined modules, definitions reside in `Main`.
|
||||
- The macro `@which` applied to a name shows its defining module.
|
||||
|
||||
```{julia}
|
||||
f(x) = 3x^3
|
||||
@@ -176,13 +194,13 @@ 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")
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
```{julia}
|
||||
qwurzel(z::PComplex) = PComplex(sqrt(z.r), z.ϕ / 2)
|
||||
sqrt_polar(z::PComplex) = PComplex(sqrt(z.r), z.ϕ / 2)
|
||||
```
|
||||
|
||||
```{julia}
|
||||
@@ -190,7 +208,7 @@ qwurzel(z::PComplex) = PComplex(sqrt(z.r), z.ϕ / 2)
|
||||
#| output: false
|
||||
|
||||
#=
|
||||
damit das length(methods(sqrt)) klappt
|
||||
to make length(methods(sqrt)) work
|
||||
=#
|
||||
if hasmethod(sqrt, (PComplex,))
|
||||
zz = @which Base.sqrt(PComplex{Float64}(1.,1.))
|
||||
@@ -198,14 +216,14 @@ 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:
|
||||
Adding one more method:
|
||||
```{julia}
|
||||
Base.sqrt(z::PComplex) = qwurzel(z)
|
||||
Base.sqrt(z::PComplex) = sqrt_polar(z)
|
||||
|
||||
length(methods(sqrt))
|
||||
```
|
||||
@@ -214,26 +232,26 @@ length(methods(sqrt))
|
||||
sqrt(z2)
|
||||
```
|
||||
|
||||
und nun zur Multiplikation:
|
||||
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 `:` is not a valid identifier character, it must be qualified with `Base.`)
|
||||
|
||||
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.
|
||||
However, multiplication with other numeric types is not yet supported. Many corresponding methods could be defined, but Julia provides another mechanism for *numeric types* that simplifies this:
|
||||
|
||||
|
||||
## Typ-Promotion und Konversion
|
||||
## Type Promotion and Conversion
|
||||
|
||||
In Julia kann man bekanntlich die verschiedensten numerischen Typen nebeneinander verwenden.
|
||||
Julia supports freely mixing various numeric types:
|
||||
|
||||
```{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'
|
||||
Among the numerous methods defined for `+` and `*`, we find a catch-all definition:
|
||||
|
||||
```julia
|
||||
+(x::Number, y::Number) = +(promote(x,y)...)
|
||||
@@ -242,15 +260,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 three dots form the splat operator, which decomposes the tuple returned by `promote()` into its components.)
|
||||
|
||||
Da die Methode mit den Typen `(Number, Number)` sehr allgemein ist, wird sie erst verwendet, wenn spezifischere Methoden nicht greifen.
|
||||
Since the method with the types `(Number, Number)` is very general, it is only used when more specific methods do not apply.
|
||||
|
||||
Was passiert hier?
|
||||
What happens here?
|
||||
|
||||
### Die Funktion `promote(x,y,...)`
|
||||
### The Function `promote(x,y,...)`
|
||||
|
||||
Diese Funktion versucht, alle Argumente in einen gemeinsamen Typen umzuwandeln, der alle Werte (möglichst) exakt darstellen kann.
|
||||
This function attempts to convert all arguments to a common type that can represent all values (as precisely as possible).
|
||||
|
||||
```{julia}
|
||||
promote(12, 34.555, 77/99, 0xff)
|
||||
@@ -261,15 +279,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, we can extend this mechanism with our own 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 the conversion should take place. Arguments are types, not values.
|
||||
|
||||
```{julia}
|
||||
@show promote_type(Rational{Int64}, ComplexF64, Float32);
|
||||
@@ -277,10 +295,10 @@ Sie ermittelt, zu welchem Typ umgewandelt werden soll. Argumente sind Typen, nic
|
||||
|
||||
|
||||
|
||||
### Die Funktion `convert(T,x)`
|
||||
### The Function `convert(T,x)`
|
||||
|
||||
Die Methoden von
|
||||
`convert(T, x)` wandeln `x` in ein Objekt vom Typ `T` um. Dabei sollte eine solche Umwandlung verlustfrei möglich sein.
|
||||
The methods of
|
||||
`convert(T, x)` convert `x` into an object of type `T`. Such a conversion should be lossless.
|
||||
|
||||
```{julia}
|
||||
z = convert(Float64, 3)
|
||||
@@ -294,7 +312,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()` is that it is called implicitly at various points:
|
||||
|
||||
> [The following language constructs call convert](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/#When-is-convert-called?):
|
||||
>
|
||||
@@ -304,24 +322,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 user-defined types, `convert()` can be extended with custom methods.
|
||||
|
||||
Für Datentypen innerhalb der Number-Hierarchie gibt es wieder eine 'catch-all-Definition'
|
||||
Within the `Number` hierarchy, a generic method handles conversions:
|
||||
```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.)
|
||||
Therefore: If a type `T<:Number` has a constructor `T(x)` accepting a numeric argument, this constructor is automatically used for conversions. (More specific methods for `convert()` can also be defined and will take priority.)
|
||||
|
||||
|
||||
### Weitere Konstruktoren für `PComplex`
|
||||
### Further Constructors for `PComplex`
|
||||
|
||||
|
||||
```{julia}
|
||||
|
||||
## (a) r, ϕ beliebige Reals, z.B. Integers, Rationals
|
||||
## (a) Arbitrary real types for r and ϕ (e.g., integers, rationals)
|
||||
|
||||
PComplex{T}(r::T1, ϕ::T2) where {T<:AbstractFloat, T1<:Real, T2<: Real} =
|
||||
PComplex{T}(convert(T, r), convert(T, ϕ))
|
||||
@@ -329,8 +347,8 @@ PComplex{T}(r::T1, ϕ::T2) where {T<:AbstractFloat, T1<:Real, T2<: Real} =
|
||||
PComplex(r::T1, ϕ::T2) where {T1<:Real, T2<: Real} =
|
||||
PComplex{promote_type(Float64, T1, T2)}(r, ϕ)
|
||||
|
||||
## (b) Zur Umwandlung von Reals: Konstruktor mit
|
||||
## nur einem Argument r
|
||||
## (b) For conversion from reals: constructor with
|
||||
## only one argument r
|
||||
|
||||
PComplex{T}(r::S) where {T<:AbstractFloat, S<:Real} =
|
||||
PComplex{T}(convert(T, r), convert(T, 0))
|
||||
@@ -338,7 +356,7 @@ PComplex{T}(r::S) where {T<:AbstractFloat, S<:Real} =
|
||||
PComplex(r::S) where {S<:Real} =
|
||||
PComplex{promote_type(Float64, S)}(r, 0.0)
|
||||
|
||||
## (c) Umwandlung Complex -> PComplex
|
||||
## (c) Conversion Complex -> PComplex
|
||||
|
||||
PComplex{T}(z::Complex{S}) where {T<:AbstractFloat, S<:Real} =
|
||||
PComplex{T}(abs(z), angle(z))
|
||||
@@ -349,8 +367,7 @@ PComplex(z::Complex{S}) where {S<:Real} =
|
||||
|
||||
```
|
||||
|
||||
|
||||
Ein Test der neuen Konstruktoren:
|
||||
Testing the new constructors:
|
||||
|
||||
```{julia}
|
||||
|
||||
@@ -359,9 +376,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.
|
||||
*Promotion rules* are needed to determine the result type of `promote(x::T1, y::T2)`. This mechanism extends `promote_type()` with the necessary methods.
|
||||
|
||||
### *Promotion rules* für `PComplex`
|
||||
### *Promotion rules* for `PComplex`
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -371,15 +388,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:**
|
||||
When a `PComplex{T}` and an `S<:Real` are combined, both convert to `PComplex{U}`, where `U` is the promoted type of `S` and `T`.
|
||||
|
||||
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**
|
||||
When a `PComplex{T}` and a `Complex{S}` are combined, both convert to `PComplex{U}`, where `U` is the promoted type of `S` and `T`.
|
||||
|
||||
|
||||
|
||||
Damit klappt nun die Multiplikation mit beliebigen numerischen Typen.
|
||||
|
||||
We can now multiply with arbitrary numeric types:
|
||||
|
||||
```{julia}
|
||||
z3, 3z3
|
||||
@@ -391,9 +409,10 @@ z3, 3z3
|
||||
|
||||
|
||||
|
||||
|
||||
:::{.callout-caution icon="false" collapse="true" .titlenormal}
|
||||
|
||||
## Zusammenfassung: unser Typ `PComplex`
|
||||
## Summary: our type `PComplex`
|
||||
|
||||
```julia
|
||||
struct PComplex{T <: AbstractFloat} <: Number
|
||||
@@ -407,7 +426,7 @@ struct PComplex{T <: AbstractFloat} <: Number
|
||||
end
|
||||
if r==0 ϕ=0 end # normalize r=0 case to phi=0
|
||||
ϕ = mod(ϕ, 2π) # map phi into interval [0,2pi)
|
||||
new(r, ϕ) # new() ist special function,
|
||||
new(r, ϕ) # new() is special function,
|
||||
end # available only inside inner constructors
|
||||
|
||||
end
|
||||
@@ -443,7 +462,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,
|
||||
# print phase in degrees, rounded to one decimal place
|
||||
p = z.ϕ * 180/π
|
||||
sp = @sprintf "%.1f" p
|
||||
print(io, z.r, "⋖", sp, '°')
|
||||
@@ -465,7 +484,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.
|
||||
`PComplex(1, 0)` is not yet supported. Other real types for `r` and `ϕ` should also be supported. For simplicity, all types are converted to `Float64`. Analogous handling applies for single real or complex arguments.
|
||||
|
||||
```julia
|
||||
PComplex(r::Real, ϕ::Real) = PComplex(Float64(r), Float64(ϕ))
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
---
|
||||
engine: julia
|
||||
julia:
|
||||
exeflags: ["--color=yes"]
|
||||
---
|
||||
|
||||
```{julia}
|
||||
@@ -9,67 +11,68 @@ engine: julia
|
||||
using InteractiveUtils
|
||||
```
|
||||
|
||||
# Grundlagen der Syntax
|
||||
# Fundamentals of Syntax
|
||||
|
||||
## Namen von Variablen, Funktionen, Typen etc.
|
||||
## Names of Variables, Functions, Types, etc.
|
||||
|
||||
- Namen können Buchstaben, Ziffern, den Unterstrich `_` und das Ausrufezeichen `!` enthalten.
|
||||
- Das erste Zeichen muss ein Buchstabe oder ein Unterstrich sein.
|
||||
- Groß- und Kleinbuchstaben werden unterschieden: `Nmax` und `NMAX` sind verschiedene Variablen.
|
||||
- Als Zeichensatz wird [Unicode](https://home.unicode.org/) verwendet. Damit stehen über 150 Schriften und zahlreiche Symbole zur Verfügung.
|
||||
- Es gibt eine kurze [Liste reservierter Schlüsselwörter](https://docs.julialang.org/en/v1/base/base/#Keywords): `if, then, function, true, false,...`
|
||||
- Names may contain letters, digits, underscores `_`, and exclamation marks `!`.
|
||||
- The first character must be a letter or an underscore.
|
||||
- Case is significant: `Nmax` and `NMAX` are different variables.
|
||||
- The character set used is [Unicode](https://home.unicode.org/), which covers 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, TheUnknownNumber, new_Value, 🎷, Counter_2, лічильник, yes!!!!,...`
|
||||
|
||||
unzulässig: `Uwe's_Funktion, 3achsen, A#B, $this_is_not_Perl, true,...`
|
||||
Impermissible: `Karen'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 `Base` module, which Julia loads automatically on 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, `log()` no longer works:
|
||||
```{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,
|
||||
- Usually, each line contains one statement.
|
||||
- If a statement is recognizable as incomplete at the end of a line through
|
||||
- open parentheses
|
||||
- operators,
|
||||
|
||||
dann wird die nächste Zeile als Fortsetzung aufgefasst.
|
||||
- Mehrere Anweisungen pro Zeile können durch Semikolon getrennt werden.
|
||||
- Im interaktiven Betrieb (REPL oder Notebook) unterdrückt ein Semikolon nach der letzten Anweisung die Ausgabe des Ergebnisses dieser Anweisung.
|
||||
then the next line is regarded as a continuation.
|
||||
- Multiple statements per line can be separated by semicolons.
|
||||
- In interactive mode (REPL or notebook), a semicolon after the last statement suppresses the output of the result of that statement.
|
||||
|
||||
:::{.callout-tip}
|
||||
|
||||
## Beispiel
|
||||
## Example:
|
||||
|
||||
Im interaktiven Betrieb wird der Wert der letzten Anweisung auch ohne explizites `print()` ausgegeben:
|
||||
In interactive mode, the value of the last statement is also displayed without explicit `print()`:
|
||||
```{julia}
|
||||
println("Hallo 🌍!")
|
||||
x = sum([i^2 for i=1:10])
|
||||
```
|
||||
Das Semikolon unterdrückt das:
|
||||
|
||||
The semicolon suppresses this:
|
||||
```{julia}
|
||||
println("Hallo 🌍!")
|
||||
x = sum([i^2 for i=1:10]);
|
||||
@@ -81,14 +84,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, a continued line should 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 fails, but—unfortunately—**without an error message**!
|
||||
```{julia}
|
||||
#| error: true
|
||||
#| warning: true
|
||||
@@ -96,9 +99,9 @@ x = sin(π/2)
|
||||
+ 3 * cos(0)
|
||||
println(x)
|
||||
```
|
||||
Hier wird das `+` in der zweiten Zeile als Präfix-Operator (Vorzeichen) interpretiert. Damit sind 1. und 2. Zeile jeweils für sich vollständige, korrekte Ausdrücke (auch wenn die 2. Zeile natürlich völlig nutzlos ist) und werden auch so abgearbeitet.
|
||||
Here, the `+` in the second line is interpreted as a prefix operator (sign). Thus, lines 1 and 2 are each complete, correct expressions on their own (even though line 2 is of course completely useless) and are processed as such.
|
||||
|
||||
Moral: Wenn man längere Ausdrücke auf mehrere Zeilen aufteilen will, sollte man immer eine Klammer aufmachen. Dann ist egal, wo der Zeilenumbruch ist:
|
||||
**Moral:** If you want to split longer expressions across multiple lines, you should always open a parenthesis. Then it doesn't matter where the line break occurs.
|
||||
```{julia}
|
||||
x = ( sin(π/2)
|
||||
+ 3 * cos(0) )
|
||||
@@ -107,43 +110,41 @@ 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 in `#= ... =#`. 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' doesn't support this yet, as the alternating
|
||||
gray shading of this comment shows.
|
||||
=#
|
||||
|
||||
|
||||
x #= das ist ein seltener Variablenname! =# = 3
|
||||
x #= this is a really rare name for a variable! =# = 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://en.wikipedia.org/wiki/Type_safety#Strong_and_weak_typing) language. All objects have a type. Functions and operations expect arguments of the correct type.
|
||||
- Julia is a [dynamically typed](https://en.wikipedia.org/wiki/Dynamic_programming_language) 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 call time which method is selected ([*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
|
||||
@@ -161,7 +162,7 @@ x, typeof(x), sizeof(x)
|
||||
```
|
||||
|
||||
```{julia}
|
||||
x = "Hallo!"
|
||||
x = "Hello!"
|
||||
x, typeof(x), sizeof(x)
|
||||
```
|
||||
|
||||
@@ -176,58 +177,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.
|
||||
- Character literals like `'A'` and single-character strings like `"A"` 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 or 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
|
||||
println("Alles falsch")
|
||||
end # Wert des gesamten Blocks ist der Wert der
|
||||
# letzten ausgeführten Auswertung
|
||||
else # at most one else block
|
||||
println("All wrong")
|
||||
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 be assigned:
|
||||
```{julia}
|
||||
y = 33
|
||||
z = if y > 10
|
||||
println("y is larger than 10")
|
||||
y += 1
|
||||
end
|
||||
println("y is larger than 10")
|
||||
y += 1
|
||||
end
|
||||
z
|
||||
```
|
||||
|
||||
### Auswahloperator (ternary operator) `test ? exp1 : exp2`
|
||||
### Conditional Operator (ternary operator) `test ? exp1 : exp2`
|
||||
|
||||
```{julia}
|
||||
x = 20
|
||||
y = 15
|
||||
z = x < y ? x+1 : y+1
|
||||
```
|
||||
ist äquivalent zu
|
||||
is equivalent to
|
||||
|
||||
```{julia}
|
||||
z = if x < y
|
||||
@@ -237,9 +238,9 @@ z = if x < y
|
||||
end
|
||||
```
|
||||
|
||||
## Vergleiche, Tests, Logische Operationen
|
||||
## Comparisons, Tests, Logical Operations
|
||||
|
||||
### Arithmetische Vergleiche
|
||||
### Arithmetic Comparisons
|
||||
|
||||
- `==`
|
||||
- `!=`, `≠`
|
||||
@@ -248,56 +249,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"
|
||||
3 < "four"
|
||||
```
|
||||
|
||||
Die Fehlermeldung zeigt ein paar Grundprinzipien von Julia:
|
||||
The error message shows a few fundamental principles of Julia:
|
||||
|
||||
- Operatoren sind auch nur Funktionen: `x < y` wird zum Funktionsaufruf `isless(x, y)`.
|
||||
- Funktionen (und damit Operatoren) können verschiedene *methods* für verschiedene Argumenttypen implementieren.
|
||||
- Abhängig von den konkreten Argumenttypen wird beim Aufruf der Funktion entschieden, welche Methode benutzt wird ([*dynamic dispatch*](https://en.wikipedia.org/wiki/Dynamic_dispatch)).
|
||||
- Operators are also just functions: `x < y` becomes the function call `isless(x, y)`.
|
||||
- Functions (and thus operators) can implement different *methods* for different argument types.
|
||||
- Depending on the concrete argument types, it is decided at function call which method is used ([*dynamic dispatch*](https://en.wikipedia.org/wiki/Dynamic_dispatch)).
|
||||
|
||||
Man kann sich alle Methoden zu einer Funktion anzeigen lassen. Das gibt einen Einblick in das komplexe Typssystem von Julia:
|
||||
One can display all methods for a function. This provides insight into Julia's complex type system:
|
||||
|
||||
```{julia}
|
||||
methods(<)
|
||||
```
|
||||
|
||||
Zuletzt noch: Vergleiche können gekettet werden.
|
||||
Finally: comparisons can be chained.
|
||||
|
||||
```{julia}
|
||||
10 < x ≤ 100 # das ist äquivalent zu
|
||||
10 < x ≤ 100 # this is equivalent to
|
||||
# 10 < x && x ≤ 100
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Tests
|
||||
Einge Funktionen vom Typ `f(c::Char) -> Bool`
|
||||
Some functions of type `f(c::Char) -> Bool`
|
||||
|
||||
```{julia}
|
||||
isnumeric('a'), isnumeric('7'), isletter('a')
|
||||
```
|
||||
|
||||
|
||||
und vom Typ `f(s1::String, s2::String) -> Bool`
|
||||
and of type `f(s1::String, s2::String) -> Bool`
|
||||
|
||||
```{julia}
|
||||
contains("Lampenschirm", "pensch"), startswith("Lampenschirm", "Lamb"), endswith("Lampenschirm", "rm")
|
||||
```
|
||||
|
||||
- Die Funktion `in(item, collection) -> Bool` testet, ob `item` in `collection` ist.
|
||||
- Sie hat auch das Alias ` ∈(item, collection)` und
|
||||
- sowohl `in` als auch `∈` können auch als Infix-Operatoren geschrieben werden.
|
||||
- The function `in(item, collection) -> Bool` tests whether `item` is in `collection`.
|
||||
- It also has the alias ` ∈(item, collection)` and
|
||||
- both `in` and `∈` can also be written as infix operators.
|
||||
|
||||
```{julia}
|
||||
x = 3
|
||||
@@ -307,23 +308,24 @@ x in [1, 2, 3, 4, 5]
|
||||
x ∈ [1, 2, 33, 4, 5]
|
||||
```
|
||||
|
||||
### Logische Operationen: `&&`, `||`, `!`
|
||||
### Logical Operations: `&&`, `||`, `!`
|
||||
|
||||
|
||||
```{julia}
|
||||
3 < 4 && !(2 > 8) && !contains("aaa", "b")
|
||||
```
|
||||
|
||||
#### Bedingte Auswertung (_short circuit evaluation_)
|
||||
#### Conditional Evaluation (_short-circuit evaluation_)
|
||||
|
||||
- in `a && b` wird `b` nur ausgewertet, wenn `a == true`
|
||||
- in `a || b` wird `b` nur ausgewertet, wenn `a == false`
|
||||
- In `a && b`, `b` is only evaluated if `a == true`
|
||||
- In `a || b`, `b` is only evaluated if `a == false`
|
||||
|
||||
(i) Damit kann `if test statement end` auch als `test && statement` geschrieben werden.
|
||||
(i) Thus, `if test statement end` can also be written as `test && statement`.
|
||||
|
||||
(ii) Damit kann `if !test statement end` als `test || statement` geschrieben werden.
|
||||
(ii) Thus, `if !test statement end` can be written as `test || statement`.
|
||||
|
||||
As an example^[from the [Julia documentation](https://docs.julialang.org/en/v1/manual/control-flow/#Short-Circuit-Evaluation)] here is an implementation of the factorial function:
|
||||
|
||||
Als Beispiel^[aus der [Julia-Dokumentation](https://docs.julialang.org/en/v1/manual/control-flow/#Short-Circuit-Evaluation)] hier eine Implementierung der Fakultätsfunktion *(factorial)*:
|
||||
```{julia}
|
||||
function fact(n::Int)
|
||||
n >= 0 || error("n must be non-negative")
|
||||
@@ -336,23 +338,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]
|
||||
println("Stimmt alles!")
|
||||
if z # equivalent to: if 3 < 4 && 5 in [1,2,5,7]
|
||||
println("All correct!")
|
||||
end
|
||||
```
|
||||
|
||||
- In Julia müssen alle Tests in einem logischen Ausdruck vom Typ `Bool` sein.
|
||||
- Es gibt keine implizite Konvertierung à la *"0 is false and 1 (or anything != 0) is true"*
|
||||
- Wenn `x` ein numerischer Typ ist, dann muss daher das C-Idiom `if(x)` als `if x != 0` geschrieben werden.
|
||||
- Es gibt eine Ausnahme zur Unterstützung der _short circuit evaluation_:
|
||||
- bei den Konstrukten `a && b && c...` bzw `a || b || c...` muss der letzte Teilausdruck nicht vom Typ `Bool` sein, wenn diese Konstrukte nicht als Tests in `if` oder `while` verwendet werden:
|
||||
- In Julia, all tests in a logical expression must be of type `Bool`.
|
||||
- There is no implicit conversion such as *"0 is false and 1 (or anything != 0) is true"*
|
||||
- If `x` is a numeric type, then the C idiom `if(x)` must be written as `if x != 0`.
|
||||
- There is an exception to support the _short circuit evaluation_:
|
||||
- in the constructs `a && b && c...` or `a || b || c...` the last subexpression does not need to be of type `Bool` if these constructs are not used as tests in `if` or `while`:
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -365,9 +367,9 @@ z = 3 < 4 && 10 < 50 && sqrt(3^3)
|
||||
z, typeof(z)
|
||||
```
|
||||
|
||||
## Schleifen *(loops)*
|
||||
## Loops
|
||||
|
||||
### Die `while` ("solange")-Schleife
|
||||
### The `while` loop
|
||||
|
||||
|
||||
Syntax:
|
||||
@@ -376,19 +378,19 @@ while *condition*
|
||||
*loop body*
|
||||
end
|
||||
```
|
||||
Eine Reihe von Anweisungen (der Schleifenkörper) wird immer wieder abgearbeitet, solange eine Bedingung erfüllt ist.
|
||||
A series of statements (the loop body) is repeatedly executed as long as a condition is satisfied.
|
||||
|
||||
|
||||
```{julia}
|
||||
i = 1 # typischerweise braucht der Test der
|
||||
# while-Schleife eine Vorbereitung ...
|
||||
i = 1 # typically the test of the
|
||||
# while loop needs preparation ...
|
||||
while i < 10
|
||||
println(i)
|
||||
i += 2 # ... und ein update
|
||||
i += 2 # ... and an update
|
||||
end
|
||||
```
|
||||
|
||||
Der Körper einer `while`- und `for`-Schleife kann die Anweisungen `break` und `continue` enthalten. `break` stoppt die Schleife, `continue` überspringt den Rest des Schleifenkörpers und beginnt sofort mit dem nächsten Schleifendurchlauf.
|
||||
The body of a `while` and `for` loop can contain the statements `break` and `continue`. `break` stops the loop, `continue` skips the rest of the loop body and immediately starts the next loop iteration.
|
||||
```{julia}
|
||||
i = 0
|
||||
|
||||
@@ -396,20 +398,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!")
|
||||
println("Done!")
|
||||
```
|
||||
|
||||
Mit `break` kann man auch Endlosschleifen verlassen:
|
||||
With `break` one can also exit infinite loops:
|
||||
|
||||
```{julia}
|
||||
i = 1
|
||||
@@ -421,7 +423,7 @@ while true
|
||||
end
|
||||
```
|
||||
|
||||
### `for`-Schleifen
|
||||
### `for` Loops
|
||||
|
||||
Syntax:
|
||||
|
||||
@@ -431,24 +433,24 @@ 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"]
|
||||
for i ∈ ["Mother", "Father", "Daughter"]
|
||||
println(i)
|
||||
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`.
|
||||
A numerical loop counter is often needed. For this purpose, we have the `range` construct. The simplest forms are
|
||||
`Start:End` and `Start:Step:End`.
|
||||
|
||||
```{julia}
|
||||
endwert = 5
|
||||
end_value = 5
|
||||
|
||||
for i ∈ 1:endwert
|
||||
for i ∈ 1:end_value
|
||||
println(i^2)
|
||||
end
|
||||
```
|
||||
@@ -469,9 +471,8 @@ for k = 14 : -2.5 : 1 print(" $k") end
|
||||
|
||||
|
||||
|
||||
#### Geschachtelte Schleifen _(nested loops)_
|
||||
|
||||
Ein `break` beendet die innerste Schleife.
|
||||
#### Nested Loops
|
||||
A `break` ends the innermost loop.
|
||||
|
||||
```{julia}
|
||||
for i = 1:3
|
||||
@@ -484,22 +485,22 @@ for i = 1:3
|
||||
end
|
||||
```
|
||||
|
||||
Man kann *nested loops* auch in einer `for`-Anweisung zusammenfassen. Dann beendet ein `break` die Gesamtschleife.
|
||||
Nested loops can also be combined in a single `for` statement. Then a `break` ends the entire loop.
|
||||
|
||||
```{julia}
|
||||
for i = 1:3, j=1:3 # im Prinzip dasselbe wie oben, aber:
|
||||
for i = 1:3, j=1:3 # essentially the same as above, but:
|
||||
println( (i,j) )
|
||||
if j == 2
|
||||
break # break bricht hier die Gesamtschleife ab
|
||||
break # break ends the entire loop here
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
:::{.callout-important .titlenormalxx}
|
||||
## **Wichtig:** Die Semantik ist völlig anders, als bei C-artigen `for`-Schleifen!
|
||||
## **Important:** The semantics are completely different from C-style `for` loops!
|
||||
|
||||
**Bei jedem Schleifendurchlauf wird die Laufvariable neu mit dem nächsten Element aus dem Container initialisiert.**
|
||||
**In each loop iteration, the loop variable is re-initialized with the next element from the container.**
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -512,11 +513,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:
|
||||
```{.julia}
|
||||
i = 1
|
||||
while i<5
|
||||
*loop body* # hier kann auch wirksam an i rumgepfuscht werden
|
||||
*loop body* # here one can also mess with i effectively
|
||||
i += 1
|
||||
end
|
||||
```
|
||||
@@ -524,100 +525,96 @@ 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 in 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, Wichtig!)
|
||||
Important = 21
|
||||
Important! = 42 # identifiers can also contain !
|
||||
(Important, Important!)
|
||||
```
|
||||
|
||||
|
||||
|
||||
```{julia}
|
||||
Wichtig!=88
|
||||
Important!=88
|
||||
```
|
||||
|
||||
|
||||
Julia interpretiert das als Vergleich `Wichtig != 88`.
|
||||
|
||||
Leerzeichen helfen:
|
||||
Julia interprets this as the *comparison* `Important != 88`.
|
||||
|
||||
Again, spaces around operators help:
|
||||
|
||||
```{julia}
|
||||
Wichtig! = 88
|
||||
Wichtig!
|
||||
Important! = 88
|
||||
Important!
|
||||
```
|
||||
|
||||
- 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.
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,29 +8,42 @@ engine: julia
|
||||
#| echo: false
|
||||
#| output: false
|
||||
using InteractiveUtils
|
||||
import QuartoNotebookWorker
|
||||
Base.stdout = QuartoNotebookWorker.with_context(stdout)
|
||||
myactive_module() = Main.Notebook
|
||||
Base.active_module() = myactive_module()
|
||||
|
||||
#struct M a::Int end; x = M(22); @show x
|
||||
#should not print "Main.Notebook.M(22)" but only "M(22)"
|
||||
function Base.show(io::IO, x::T) where T
|
||||
if parentmodule(T) == @__MODULE__
|
||||
# Print "TypeName(fields...)" without module prefix
|
||||
print(io, nameof(T), "(")
|
||||
fields = fieldnames(T)
|
||||
for (i, f) in enumerate(fields)
|
||||
print(io, getfield(x, f))
|
||||
i < length(fields) && print(io, ", ")
|
||||
end
|
||||
print(io, ")")
|
||||
else
|
||||
invoke(Base.show, Tuple{IO, Any}, io, x)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
# Das Typsystem von Julia
|
||||
# The Julia Type System
|
||||
|
||||
Man kann umfangreiche Programme in Julia schreiben, ohne auch nur eine einzige Typdeklaration verwenden zu müssen. Das ist natürlich Absicht und soll die Arbeit der Anwender vereinfachen.
|
||||
One can write extensive programs in Julia without using a single type declaration. This is, of course, intentional and designed to simplify users' work.
|
||||
|
||||
Wir blicken jetzt trotzdem mal unter die Motorhaube.
|
||||
However, for a deeper understanding we will now examine the underlying type system.
|
||||
|
||||
## Die Typhierarchie am Beispiel der numerischen Typen
|
||||
## The Type Hierarchy: A Case Study with Numeric Types
|
||||
|
||||
Das Typsystem hat die Struktur eines Baums, dessen Wurzel der Typ `Any` ist. Mit den Funktionen `subtypes()` und `supertype()` kann man den Baum erforschen. Sie zeigen alle Kinder bzw. die Mutter eines Knotens an.
|
||||
The type system has the structure of a tree whose root is the type `Any`. The functions `subtypes()` and `supertype()` can be used to explore the tree. `subtypes()` displays all child nodes, while `supertype()` shows the parent.
|
||||
|
||||
```{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** with 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 traverse this branch upward to the root (in computer science, trees are typically inverted).
|
||||
```{julia}
|
||||
supertype(Int64)
|
||||
```
|
||||
@@ -46,72 +59,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:
|
||||
We can now examine the nodes:
|
||||
|
||||
{{< embed ../notebooks/nb-types.ipynb#nb3 >}}
|
||||
|
||||
Mit einer kleinen rekursiven Funktion kann man schnell einen ganzen (Unter-)Baum ausdrucken:
|
||||
A simple recursive function can display the entire subtree:
|
||||
|
||||
{{< 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))
|
||||
Below is the same hierarchy as an image (made with LaTeX/[TikZ](https://tikz.dev/tikz-trees)):
|
||||
|
||||
::: {.content-visible when-format="html"}
|
||||
{width=80%}
|
||||
:::
|
||||
|
||||
::: {.content-visible when-format="pdf"}
|
||||
{width=60%}
|
||||
::: {.content-visible when-format="typst"}
|
||||
{width=60%}
|
||||
:::
|
||||
|
||||
|
||||
Natürlich hat Julia nicht nur numerische Typen. Die Anzahl der direkten Abkömmlinge (Kinder) von `Any` ist
|
||||
Beyond numeric types, Julia includes many others. 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.
|
||||
This number increases with (almost) every package loaded via `using ...`.
|
||||
|
||||
## 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; that is, no objects can have an abstract type directly.
|
||||
- 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:
|
||||
To **declare** *and* **test** the relationships in the type hierarchy, Julia provides 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 reads as the question `is x a T?`.
|
||||
|
||||
```{julia}
|
||||
x = 17.2
|
||||
@@ -120,7 +130,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, they are simple to define. Either they are derived directly from `Any`:
|
||||
|
||||
```{julia}
|
||||
abstract type MySuperType end
|
||||
@@ -128,7 +138,7 @@ abstract type MySuperType end
|
||||
supertype(MySuperType)
|
||||
```
|
||||
|
||||
oder von einem anderen abstrakten Typ:
|
||||
or from another abstract type:
|
||||
|
||||
```{julia}
|
||||
abstract type MySpecialNumber <: Integer end
|
||||
@@ -136,24 +146,24 @@ abstract type MySpecialNumber <: Integer end
|
||||
supertypes(MySpecialNumber)
|
||||
```
|
||||
|
||||
Mit der Definition werden die abstrakten Typen an einer Stelle des Typ-Baums "eingehängt".
|
||||
By this definition, the abstract type is attached at a specific 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:
|
||||
Though appearing in the numeric type tree, these types warrant brief explanation:
|
||||
|
||||
`Bool` ist numerisch im Sinne von `true=1, false=0`:
|
||||
`Bool` is numeric in the sense that `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 certain 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.
|
||||
When the tree structure is insufficient, abstract types can be defined as a union of arbitrary (abstract and concrete) types.
|
||||
|
||||
```{julia}
|
||||
IntOrString = Union{Int64,String}
|
||||
@@ -161,17 +171,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(<)` reveals over 70 methods for the comparison operator, including methods with union type arguments, such as:
|
||||
```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 comparing fixed-width machine numbers with arbitrary precision numbers.
|
||||
:::
|
||||
|
||||
## Zusammengesetzte (_composite_) Typen: `struct`
|
||||
## Composite Types: `struct`
|
||||
|
||||
Eine `struct` ist eine Zusammenstellung von mehreren benannten Feldern und definiert einen konkreten Typ.
|
||||
A `struct` defines a concrete type as a collection of named fields.
|
||||
|
||||
```{julia}
|
||||
abstract type Point end
|
||||
@@ -188,7 +198,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 seen with expressions like `x = Int8(33)`, type names can serve as constructors:
|
||||
|
||||
```{julia}
|
||||
p1 = Point2D(1.4, 3.5)
|
||||
@@ -200,20 +210,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` are accessed by name using 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.
|
||||
Because 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()`.
|
||||
The `dump()` function displays structure information for types and objects.
|
||||
|
||||
```{julia}
|
||||
dump(Point3D)
|
||||
@@ -224,28 +234,27 @@ dump(Point3D)
|
||||
dump(p1)
|
||||
```
|
||||
|
||||
## Funktionen und *Multiple dispatch*
|
||||
## Functions and *Multiple Dispatch*
|
||||
|
||||
:::{.callout-note .titlenormal}
|
||||
|
||||
## Objekte, Funktionen, Methoden
|
||||
## Objects, Functions, and Methods
|
||||
|
||||
In klassischen objektorientierten Sprachen wie C++/Java haben Objekte üblicherweise mit ihnen assoziierte Funktionen, die Methoden des Objekts.
|
||||
In classical object-oriented languages (C++, Java, Python), methods are bound to objects.
|
||||
|
||||
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.)
|
||||
Julia takes a different approach: methods belong to functions, not to objects.
|
||||
Constructors (functions sharing a type's name that create instances of that type) are the only exception.
|
||||
|
||||
Sobald man einen neuen Typ definiert hat, kann man sowohl neue als auch bestehende Funktionen um neue Methoden für diesen Typ ergänzen.
|
||||
|
||||
- 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.
|
||||
When we define a new type, we can define functions specific to that type but we can also add additional methods to existing functions.
|
||||
|
||||
- A single functions can have multiple methods for different argument types.
|
||||
- At call time, Julia selects the most specific method matching the concrete argument types *(multiple dispatch)*.
|
||||
- Core functions in Julia often have numerous predefined methods and third-party packages or user code can extend them adding additional methods.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
Den Abstand zwischen zwei Punkten implementieren wir als Funktion mit zwei Methoden:
|
||||
We define a distance function with two methods:
|
||||
|
||||
```{julia}
|
||||
function distance(p1::Point2D, p2::Point2D)
|
||||
@@ -256,97 +265,95 @@ 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 `@which` macro, applied to a function call with concrete arguments, shows which method is selected for these 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
|
||||
Calculate the angle ϕ (in degrees) of the polar coordinates (2D) or
|
||||
spherical coordinates (3D) of a point
|
||||
"""
|
||||
function phi_winkel(p::Point)
|
||||
function phi_angle(p::Point)
|
||||
atand(p.y, p.x)
|
||||
end
|
||||
|
||||
phi_winkel(p1)
|
||||
phi_angle(p1)
|
||||
```
|
||||
|
||||
:::{.callout-tip collapse="true"}
|
||||
Ein in *triple quotes* eingeschlossene Text unmittelbat vor der Funktionsdefinition
|
||||
wird automatisch in die Hilfe-Datenbank von Julia integriert:
|
||||
Text enclosed in *triple quotes* immediately before the function definition
|
||||
is automatically integrated into Julia's help database:
|
||||
|
||||
```{julia}
|
||||
?phi_winkel
|
||||
?phi_angle
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
|
||||
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 written in short [*assignment form*](https://docs.julialang.org/en/v1/manual/functions/#man-functions)):
|
||||
|
||||
```{julia}
|
||||
f(x::String, y::Number) = "Args: String + Zahl"
|
||||
f(x::String, y::Number) = "Args: String + Number"
|
||||
f(x::String, y::Int64) = "Args: String + Int64"
|
||||
f(x::Number, y::Int64) = "Args: Zahl + Int64"
|
||||
f(x::Int64, y:: Number) = "Args: Int64 + Zahl"
|
||||
f(x::Number) = "Arg: eine Zahl"
|
||||
f(x::Number, y::Int64) = "Args: Number + Int64"
|
||||
f(x::Int64, y:: Number) = "Args: Int64 + Number"
|
||||
f(x::Number) = "Arg: a Number"
|
||||
|
||||
function f(x::Number, y::Number, z::String)
|
||||
return "Arg: 2 x Zahl + String"
|
||||
return "Arg: 2 × Number + String"
|
||||
end
|
||||
```
|
||||
Hier passen die ersten beiden Methoden. Gewählt wird die zweite, da sie spezifischer ist, `Int64 <: Number`.
|
||||
The first two methods match; the second is chosen as 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.
|
||||
Ambiguities may arise if methods are defined poorly:
|
||||
|
||||
```{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 denoted `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.
|
||||
Like `Point2D`, both `Rational` and `Complex` consist of two fields: numerator and denominator or real and imaginary parts.
|
||||
|
||||
Der Typ dieser Felder ist allerdings nicht vollständig festgelegt. `Rational` und `Complex` sind _parametrisierte_ Typen.
|
||||
However, the type of these fields is not completely fixed. `Rational` and `Complex` are _parametric_ types.
|
||||
|
||||
```{julia}
|
||||
x = 2//7
|
||||
@@ -367,14 +374,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` and `Complex`, respectively.
|
||||
|
||||
|
||||
```{julia}
|
||||
Rational{BigInt} <: Rational
|
||||
```
|
||||
|
||||
Die Definitionen [sehen etwa so aus](https://github.com/JuliaLang/julia/blob/master/base/rational.jl#L6-L15):
|
||||
The definitions [look roughly like this](https://github.com/JuliaLang/julia/blob/master/base/rational.jl#L6-L15):
|
||||
|
||||
```{julia}
|
||||
struct MyComplex{T<:Real} <: Number
|
||||
@@ -388,19 +395,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:
|
||||
Since ℚ$\subset$ ℝ (or `Rational <: Real` in Julia notation), the components of a complex number can also be rational:
|
||||
|
||||
```{julia}
|
||||
z = 3//4 + 5im
|
||||
@@ -409,23 +416,24 @@ dump(z)
|
||||
|
||||
|
||||
|
||||
Diese Strukturen sind ohne das `mutable`-Attribut definiert, also *immutable*:
|
||||
|
||||
These structures are declared without the `mutable` attribute, making them *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 standard practice. The object `9` (of type `Int64`) is also 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` then references 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 type system's flexibility invites experimentation. Here we define a `struct` that can contain either a machine number or a pair of integers:
|
||||
|
||||
```{julia}
|
||||
struct MyParms{T <: Union{Float64, Tuple{Int64, Int64}}}
|
||||
@@ -441,13 +449,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. Each type is an instance of one of three "meta-types":
|
||||
|
||||
- `Union` (Union-Typen)
|
||||
- `UnionAll` (parametrisierte Typen)
|
||||
- `DataType` (alle konkreten und sonstige abstrakte Typen)
|
||||
- `Union` (union types)
|
||||
- `UnionAll` (parametric types)
|
||||
- `DataType` (all concrete and other abstract types)
|
||||
|
||||
```{julia}
|
||||
@show 23779 isa Int64 Int64 isa DataType;
|
||||
@@ -463,7 +471,7 @@ p2 = MyParms( (2, 4) )
|
||||
```
|
||||
|
||||
|
||||
Diese 3 konkreten "Meta-Typen" sind übrigens Subtypen des abstrakten "Meta-Typen" `Type`.
|
||||
These three concrete "meta-types" are, by the way, subtypes of the abstract "meta-type" `Type`.
|
||||
|
||||
```{julia}
|
||||
subtypes(Type)
|
||||
@@ -471,7 +479,7 @@ subtypes(Type)
|
||||
|
||||
-----------------
|
||||
|
||||
(2) Damit können Typen auch einfach Variablen zugewiesen werden:
|
||||
(2) Types can be assigned to a variable:
|
||||
|
||||
```{julia}
|
||||
x3 = Float64
|
||||
@@ -480,15 +488,13 @@ 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 demonstrates that [Julia's style guidelines](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 conventions, not language-enforced rules.
|
||||
|
||||
Man sollte sie trotzdem einhalten, um den Code lesbar zu halten.
|
||||
They should still be followed for readability.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
Wenn man solche Zuweisungen mit `const` für dauerhaft erklärt, entsteht ein
|
||||
*type alias*.
|
||||
Declaring such assignments with `const` creates a *type alias*.
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -500,7 +506,7 @@ typeof(z)
|
||||
|
||||
--------
|
||||
|
||||
(3) Typen können Argumente von Funktionen sein.
|
||||
(3) Types can be function arguments.
|
||||
|
||||
|
||||
```{julia}
|
||||
@@ -516,99 +522,100 @@ z = myf(43, UInt16, Real)
|
||||
@show z typeof(z);
|
||||
```
|
||||
|
||||
Wenn man diese Funktion mit Typsignaturen definieren möchte, kann man natürlich
|
||||
To define this function with type signatures, we 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 we 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 can we 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 functions with types as arguments. We have already seen `<:(T1, T2)`, `supertype(T)`, `supertypes(T)`, `subtypes(T)`. Other useful operations include `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 used as parameters in 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, such types exist. They are concrete, and objects can be instantiated.
|
||||
|
||||
```{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 composite type. Each component has an individual type `T`, for which `T<:Integer` holds.
|
||||
|
||||
Nun gilt zwar
|
||||
Note 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 theoretical computer science terminology](https://en.wikipedia.org/wiki/Type_variance), **invariant**.
|
||||
(If `S<:T` implied `ParamType{S} <: ParamType{T}`, this would be **covariance**.)
|
||||
|
||||
|
||||
|
||||
## Generische Funktionen
|
||||
## Generic Functions
|
||||
|
||||
Der übliche (und in vielen Fällen empfohlene!) Programmierstil in Julia ist das Schreiben generischer Funktionen:
|
||||
The usual (and in many cases recommended!) programming style in Julia is writing generic functions:
|
||||
|
||||
```{julia}
|
||||
function fsinnfrei1(x, y)
|
||||
function fmm(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 with any types supporting the required operations.
|
||||
|
||||
```{julia}
|
||||
fsinnfrei1( Complex(2,3), 10), fsinnfrei1("Hallo", '!')
|
||||
fmm( Complex(2,3), 10), fmm("Hello", '!')
|
||||
```
|
||||
|
||||
Man kann natürlich Typ-Annotationen benutzen, um die Verwendbarkeit einzuschränken oder um unterschiedliche Methoden für unterschiedliche Typen zu implementieren:
|
||||
|
||||
Type annotations can restrict applicability or implement different methods for different types:
|
||||
|
||||
```{julia}
|
||||
function fsinnfrei2(x::Number, y::AbstractFloat)
|
||||
function fmm2(x::Number, y::AbstractFloat)
|
||||
return x * x * y
|
||||
end
|
||||
|
||||
function fsinnfrei2(x::String, y::String)
|
||||
function fmm2(x::String, y::String)
|
||||
println("Sorry, I don't take strings!")
|
||||
end
|
||||
|
||||
|
||||
@show fsinnfrei2(18, 2.0) fsinnfrei2(18, 2);
|
||||
@show fmm2(18, 2.0) fmm2(18, 2);
|
||||
```
|
||||
|
||||
:::{.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 *advantages* 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 seamless integration across packages and support high-level 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
|
||||
@@ -638,7 +645,7 @@ Ein einfaches Beispiel: Das Paket `Measurements.jl` definiert einen neuen Datent
|
||||
|
||||
=#
|
||||
using Measurements
|
||||
zz= @which Base.show(stdout, MIME"text/latex"(), 3±2)
|
||||
zz = @which Base.show(stdout, MIME"text/latex"(), 3±2)
|
||||
Base.delete_method(zz)
|
||||
```
|
||||
|
||||
@@ -648,22 +655,22 @@ using Measurements
|
||||
x = 33.56±0.3
|
||||
y = 2.3±0.02
|
||||
|
||||
fsinnfrei1(x, y)
|
||||
fmm(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., an implementation of [prime factorization in ℤ[i]](https://en.wikipedia.org/wiki/Gaussian_integer). The definition
|
||||
|
||||
```{julia}
|
||||
#| eval: false
|
||||
function isprime(x::Complex{Integer}) ... end
|
||||
```
|
||||
|
||||
liefert nun nicht das Gewünschte, wie wir in @sec-invariance gesehen haben. Die Funktion würde für ein Argument vom Typ `Complex{Int64}` nicht funktionieren, da letzteres kein Subtyp von `Complex{Integer}` ist.
|
||||
does not give the desired result, as we saw in @sec-invariance. The function would not work for an argument of type `Complex{Int64}`, since the latter is not a subtype of `Complex{Integer}`.
|
||||
|
||||
Wir müssen eine Typ-Variable einführen. Dazu dient die `where`-Klausel.
|
||||
We must introduce a type variable. The `where` clause serves this purpose.
|
||||
|
||||
```{julia}
|
||||
#| eval: false
|
||||
@@ -672,11 +679,11 @@ function isprime(x::Complex{T}) where {T<:Integer}
|
||||
end
|
||||
```
|
||||
|
||||
Das ist zu lesen als:
|
||||
This is to be read as:
|
||||
|
||||
> „Das Argument x soll von einem der Typen `Complex{T}` sein, wobei die Typvariable `T` irgendein Untertyp von `Integer` sein kann.“
|
||||
> "The argument `x` should be one of the types `Complex{T}`, where the type variable `T` can be any subtype of `Integer`."
|
||||
|
||||
Noch ein Beispiel:
|
||||
Another example:
|
||||
```{julia}
|
||||
#| eval: false
|
||||
function kgV(x::Complex{T}, y::Complex{S}) where {T<:Integer, S<:Integer}
|
||||
@@ -684,10 +691,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, each a subtype of `Integer`.
|
||||
|
||||
|
||||
Wenn es nur eine `where`-Klausel wie im vorletzten Beispiel gibt, kann man die geschweiften Klammern weglassen und
|
||||
If there is only one `where` clause as in the last example, one can omit the curly braces and
|
||||
write
|
||||
|
||||
```{julia}
|
||||
#| eval: false
|
||||
@@ -695,7 +703,7 @@ function isprime(x::Complex{T}) where T<:Integer
|
||||
...
|
||||
end
|
||||
```
|
||||
schreiben. Das lässt sich noch weiter kürzen zu
|
||||
This can still be shortened to
|
||||
```{julia}
|
||||
#| eval: false
|
||||
function isprime(x::Complex{<:Integer})
|
||||
@@ -703,7 +711,7 @@ function isprime(x::Complex{<:Integer})
|
||||
end
|
||||
```
|
||||
|
||||
Diese verschiedenen Varianten können verwirrend sein, aber das ist nur Syntax.
|
||||
These different variants can be confusing, but it is only syntax.
|
||||
|
||||
```{julia}
|
||||
C1 = Complex{T} where {T<:Integer}
|
||||
@@ -713,24 +721,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:
|
||||
Finally, note that `where T` is shorthand for `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 both arguments have exactly the same type; otherwise, any type is accepted.
|
||||
|
||||
```{julia}
|
||||
fgl(33, 44)
|
||||
```
|
||||
|
||||
|
||||
```{julia}
|
||||
fgl(33, 44.0)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
118
index.qmd
118
index.qmd
@@ -1,12 +1,20 @@
|
||||
---
|
||||
engine: julia
|
||||
julia:
|
||||
exeflags: ["--color=yes"]
|
||||
---
|
||||
# Was ist Julia? {.unnumbered}
|
||||
|
||||
# What is Julia? {.unnumbered}
|
||||
|
||||
|
||||
Julia ist eine noch recht junge für *scientific computing* konzipierte moderne Programmiersprache.
|
||||
```{=typst}
|
||||
#set math.equation(numbering: none)
|
||||
// Some things need to be here to counter the Typst style
|
||||
```
|
||||
|
||||
Ein kleines Codebeispiel:
|
||||
Julia is a relatively new, modern programming language designed for *scientific computing*.
|
||||
|
||||
A code example:
|
||||
|
||||
```{julia}
|
||||
#| error: false
|
||||
@@ -33,25 +41,28 @@ end
|
||||
f
|
||||
```
|
||||
|
||||
## Geschichte {.unnumbered}
|
||||
## History {.unnumbered}
|
||||
|
||||
- 2009 Beginn der Entwicklung am *Computer Science and Artificial
|
||||
Intelligence Laboratory* des MIT
|
||||
- 2012 erste Release v0.1
|
||||
- 2018 Version v1.0
|
||||
- aktuell: v1.11.4 vom 10. März 2025
|
||||
- 2009: Development started at MIT's *Computer Science and Artificial
|
||||
Intelligence Laboratory*
|
||||
- 2012: First release (v0.1)
|
||||
- 2018: Version 1.0 released
|
||||
- February 2026: Version 1.12.5
|
||||
|
||||
Zum ersten Release 2012 haben die Schöpfer von Julia ihre Ziele und Motivation in dem Blogbeitrag [Why we created Julia](https://julialang.org/blog/2012/02/why-we-created-julia/)
|
||||
interessant zusammengefasst.
|
||||
|
||||
Für ein Bild von *Stefan Karpinski, Viral Shah, Jeff
|
||||
Bezanson* und *Alan Edelman* bitte hier klicken: <https://news.mit.edu/2018/julia-language-co-creators-win-james-wilkinson-prize-numerical-software-1226>.
|
||||
|
||||
In their 2012 inaugural blog post [Why we created Julia](https://julialang.org/blog/2012/02/why-we-created-julia),
|
||||
the developers provide an insightful and humorous overview of their objectives and motivations for creating Julia.
|
||||
|
||||
A photo of *Stefan Karpinski, Viral Shah, Jeff
|
||||
Bezanson*, and *Alan Edelman* can be found
|
||||
here: <https://news.mit.edu/2018/julia-language-co-creators-win-james-wilkinson-prize-numerical-software-1226>.
|
||||
|
||||
|
||||
|
||||
:::{.content-hidden unless-format="xxx"}
|
||||
|
||||
Kurzfassung:
|
||||
Short summary:
|
||||
|
||||
> We want a language that is
|
||||
>
|
||||
@@ -67,26 +78,26 @@ Bezanson* und *Alan Edelman* bitte hier klicken: <https://news.mit.edu/2018/juli
|
||||
|
||||
|
||||
|
||||
Formale Syntax
|
||||
Formal syntax
|
||||
:
|
||||
- Algorithmisches Denken
|
||||
- Gefühl für die Effizienz und Komplezität von Algorithmen
|
||||
- Besonderheiten der Computerarithmetik, insbes. Gleitkommazahlen
|
||||
- „Ökosystem“ der Sprache:
|
||||
- die Kunst des Debugging.
|
||||
- Algorithmic thinking
|
||||
- Intuition for the efficiency and complexity of algorithms
|
||||
- Special features of computer arithmetic, particularly floating-point numbers
|
||||
- The "ecosystem" of the language
|
||||
- The art of debugging.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
## Warum Julia? {.unnumbered}
|
||||
## Why Julia? {.unnumbered}
|
||||
|
||||
:::{.callout-tip .titlenormal icon=false}
|
||||
|
||||
## aus [The fast track to Julia](https://cheatsheet.juliadocs.org/)
|
||||
## from [The fast track to Julia](https://cheatsheet.juliadocs.org/)
|
||||
|
||||
"Julia is an open-source, multi-platform, high-level, high-performance programming language for technical computing.
|
||||
|
||||
Julia has an LLVM-based JIT compiler that allows it to match the performance of languages such as C and FORTRAN without the hassle of low-level code. Because the code is compiled on the fly you can run (bits of) code in a shell or REPL , which is part of the recommended workflow .
|
||||
|
||||
Julia has an LLVM-based JIT compiler that allows it to match the performance of languages such as C and FORTRAN without the hassle of low-level code. Because the code is compiled on the fly you can run (bits of) code in a shell or REPL, which is part of the recommended workflow.
|
||||
|
||||
Julia is dynamically typed, provides multiple dispatch, and is designed for parallelism and distributed computation.
|
||||
|
||||
@@ -95,40 +106,45 @@ Julia has a built-in package manager."
|
||||
:::
|
||||
|
||||
|
||||
*open source*
|
||||
: - offene Entwicklung auf [GitHub](https://github.com/JuliaLang/julia)
|
||||
- Implementierungen für alle gängigen Betriebssysteme
|
||||
***open source***
|
||||
|
||||
*high-performance programming language for technical computing*
|
||||
: - viele Funktionen für *scientific computing* eingebaut,
|
||||
- (bewusste) Ähnlichkeit zu Python, R und Matlab,
|
||||
- komplexe Berechnungen in wenigen Zeilen
|
||||
- einfaches Interface zu anderen Sprachen wie C oder Python
|
||||
- open development on [GitHub](https://github.com/JuliaLang/julia)
|
||||
- implementations for all common operating systems
|
||||
|
||||
*a JIT compiler*
|
||||
: - interaktives Arbeiten möglich: `read-eval-print loop (REPL)` mit
|
||||
- just-in-time (JIT) Compilation
|
||||
- dadurch Laufzeiten vergleichbar mit statischen Sprachen wie C/C++, Fortran oder Rust
|
||||
***high-performance programming language for technical computing***
|
||||
|
||||
*a built-in package manager*
|
||||
: - riesiges *ecosystem* an einfach installierbaren Paketen, z.B.
|
||||
- [Mathematische Optimierung](https://jump.dev/)
|
||||
- [Machine Learning](https://fluxml.ai/)
|
||||
- [Data Visualization](https://docs.makie.org/stable/)
|
||||
- [Differentialgleichungen](https://docs.sciml.ai/DiffEqDocs/stable/)
|
||||
- [Mathematische Modellierung](https://sciml.ai/)
|
||||
- many functions for *scientific computing* built-in
|
||||
- (intentional) similarity to Python, R and Matlab
|
||||
- complex calculations in a few lines
|
||||
- simple interface to other languages like C or Python
|
||||
|
||||
***JIT compilation***
|
||||
|
||||
- supports interactive workflow via the `read-eval-print loop (REPL)`
|
||||
- just-in-time (JIT) compilation
|
||||
- resulting in runtimes comparable to static languages like C/C++, Fortran, or Rust
|
||||
|
||||
***a built-in package manager***
|
||||
|
||||
- huge *ecosystem* of easily installable packages, e.g.
|
||||
|
||||
- [Mathematical Optimization](https://jump.dev/)
|
||||
- [Machine Learning](https://fluxml.ai/)
|
||||
- [Data Visualization](https://docs.makie.org/stable/)
|
||||
- [Differential Equations](https://docs.sciml.ai/DiffEqDocs/stable/)
|
||||
- [Mathematical Modeling](https://sciml.ai/)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Eine kleine Auswahl an Online-Material zu Julia {.unnumbered}
|
||||
## Selected Links {.unnumbered}
|
||||
|
||||
- [Dokumentation](https://docs.julialang.org/en/v1/) - die offizielle Dokumentation
|
||||
- [Cheat Sheet](https://cheatsheet.juliadocs.org/) - "a quick & dirty overview"
|
||||
- [Introducing Julia](https://en.wikibooks.org/wiki/Introducing_Julia)-- ein WikiBook
|
||||
- [The Julia Express](http://bogumilkaminski.pl/files/julia_express.pdf) - Kurzfassung, Julia auf 16 Seiten
|
||||
- [Think Julia](https://benlauwens.github.io/ThinkJulia.jl/latest/book.html) - Einführung in die Programmierung mit Julia als Sprache
|
||||
- Das [Julia Forum](https://discourse.julialang.org/)
|
||||
- Was fürs Auge: [Beispiele zum Julia-Grafikpaket `Makie`](https://beautiful.makie.org/)
|
||||
- [Documentation](https://docs.julialang.org/en/v1/) -- the official documentation
|
||||
- [Cheat Sheet](https://cheatsheet.juliadocs.org/) -- "a quick overview"
|
||||
- [Introducing Julia](https://en.wikibooks.org/wiki/Introducing_Julia) -- a WikiBook
|
||||
- [The Julia Express](http://bogumilkaminski.pl/files/julia_express.pdf) -- Julia in 16 pages
|
||||
- [Think Julia](https://benlauwens.github.io/ThinkJulia.jl/latest/book.html) -- introduction to programming using Julia as first language
|
||||
- The [Julia Forum](https://discourse.julialang.org/)
|
||||
- For the eyes: [Examples for the Julia graphics package `Makie`](https://beautiful.makie.org/)
|
||||
|
||||
|
||||
23
macros.typ
Normal file
23
macros.typ
Normal file
@@ -0,0 +1,23 @@
|
||||
#let Skylighting(fill: none, number: false, start: 1, sourcelines) = {
|
||||
let blocks = []
|
||||
let lnum = start - 1
|
||||
let bgcolor = rgb("#f1f3f5")
|
||||
for ln in sourcelines {
|
||||
if number {
|
||||
lnum = lnum + 1
|
||||
blocks = blocks + box(width: if start + sourcelines.len() > 999 { 30pt } else { 24pt }, text(fill: rgb("#aaaaaa"), [ #lnum ]))
|
||||
}
|
||||
blocks = blocks + ln + EndLine()
|
||||
}
|
||||
block(fill: bgcolor, width:100%, inset:(x:5pt, y:8pt), stroke:( left: 2pt + green), below:0pt, blocks)
|
||||
}
|
||||
|
||||
|
||||
#set math.mat(delim: "[")
|
||||
|
||||
// now in index.qmd
|
||||
//#set math.equation(numbering: none)
|
||||
// not enough
|
||||
//#let equation-numbering = it => {
|
||||
// numbering(none, it)
|
||||
//}
|
||||
23
opencode.json
Normal file
23
opencode.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
"llama.cpp": {
|
||||
"npm": "@ai-sdk/openai-compatible",
|
||||
"name": "llama-server (local)",
|
||||
"options": {
|
||||
"baseURL": "http://127.0.0.1:12434/v1"
|
||||
},
|
||||
"models": {
|
||||
"Qwen3.5-122B-A10B-coding": {
|
||||
"name": "Qwen3.5-122B-A10B-coding",
|
||||
"tool_call": true,
|
||||
"reasoning": true,
|
||||
"limit": {
|
||||
"context": 128000,
|
||||
"output": 65536
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user