english translation started

This commit is contained in:
2026-02-22 18:22:46 +01:00
parent 19c67a3c9b
commit 9e418381ca
17 changed files with 1915 additions and 1907 deletions

View File

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