std.math — Mathematik
Mathematische Grundfunktionen in zwei Schichten: Ganzzahl-Mathematik (Betrag, Min/Max, Wurzel, Potenz, Interpolation, Zahlentheorie) und f64-Mathematik (Wurzel, Trigonometrie, Exponential- und Logarithmusfunktionen). Die Ganzzahl-Schicht rechnet ohne Fließkomma und ist damit auch auf Zielen ohne FPU einsetzbar; die f64-Schicht setzt auf den Gleitkomma-Builtins fAdd/fSub/fMul/fDiv/sqrt auf.
Einsatzbereiche: Geometrie, Skalierung von Messwerten, Animationen, Hashing, Speicherverwaltung (Zweierpotenzen), Statistik-Grundlagen. Basis-Unit für std.vector, std.rect, std.circle.
Autor: Andreas Röne
Copyright: 2024–2025 Andreas Röne
Quelle: std/math.lyx
<WRAP info> Seit lyxc 1.0.20F sind die früher hier verzeichneten Rechenfehler behoben (#1444–#1450). Nachgemessen:
Sin64(30°) = 500000 Hypot64(3,4) = 5
Sin64(90°) = 1000000 IsOdd(-3) = 1
Cos64(60°) = 500000 PopCount(-1) = 64
Die Winkelfunktionen rechnen in Mikrograd. Sin64(30000000) ist der Sinus von 30°, das Ergebnis ist mit 1.000.000 skaliert. Wer die alte Annahme „Grad rein, Promille raus„ übernimmt, bekommt für Sin64(30) eine 0 — das sind 30 Mikrograd, also praktisch null Grad.
</WRAP>
Import
import std.math;
Ganzzahl-Funktionen
Grundlagen
| Signatur | Beschreibung | Status |
|---|---|---|
Abs64(x: int64): int64 | Betrag | ok |
Min64(a, b: int64): int64 | Kleinerer der beiden Werte | ok |
Max64(a, b: int64): int64 | Größerer der beiden Werte | ok |
Min3(a, b, c: int64): int64 | Kleinster von drei Werten | ok |
Max3(a, b, c: int64): int64 | Größter von drei Werten | ok |
Sign64(x: int64): int64 | Vorzeichen: −1, 0 oder 1 | ok |
Clamp64(val, min, max: int64): int64 | Begrenzt val auf [min, max] | ok |
InRange64(val, min, max: int64): bool | Ob val in [min, max] liegt (Grenzen eingeschlossen) | ok |
Div64(a, b: int64): int64 | Ganzzahlige Division. Division durch 0 ist nicht abgefangen — vorher selbst prüfen | ok |
Mod64(a, b: int64): int64 | Rest der Division; Vorzeichen folgt dem Dividenden | ok |
IsEven(x: int64): bool | Ob gerade | ok |
IsOdd(x: int64): bool | Ob ungerade — auch bei negativen Zahlen | behoben |
TimesTwo(x: int64): int64 | Verdoppelt — Rest aus der Frühzeit der Unit, x * 2 ist direkter | ok |
RoundF64(x: f64): f64 | Kaufmännisches Runden | ok |
Wurzel, Potenz, Logarithmus
| Signatur | Beschreibung | Status |
|---|---|---|
Sqrt64(n: int64): int64 | floor(√n) per Newton-Verfahren; negatives n ergibt 0 | ok |
IntSqrt(n: int64): int64 | Namensgleicher Aufruf von Sqrt64 | ok |
Pow64(base, exp: int64): int64 | base^exp durch wiederholte Multiplikation. Negativer Exponent ergibt 0, exp == 0 ergibt 1. Überlauf wird nicht erkannt | ok |
Log2(x: int64): int64 | floor(log₂ x) durch fortgesetzte Halbierung; x ⇐ 0 ergibt 0 | ok |
Interpolation und Abbildung
| Signatur | Beschreibung | Status |
|---|---|---|
Lerp64(a, b, t_permille: int64): int64 | Lineare Interpolation, t in Promille (0…1000). Werte außerhalb werden geklemmt | ok |
Map64(val, in_min, in_max, out_min, out_max: int64): int64 | Überträgt val vom Eingangs- in den Ausgangsbereich. Gleiche Grenzen ergeben out_min | ok |
Hypot64(x, y: int64): int64 | √(x²+y²) | ok |
Zahlentheorie
| Signatur | Beschreibung | Status |
|---|---|---|
GCD(a, b: int64): int64 | Größter gemeinsamer Teiler (euklidisch, arbeitet mit Beträgen) | ok |
LCM(a, b: int64): int64 | Kleinstes gemeinsames Vielfaches; 0 wenn GCD 0 ist | ok |
IsPrime(n: int64): bool | Probedivision bis √n; n < 2 ergibt false | ok |
NextPrime(n: int64): int64 | Kleinste Primzahl größer n | ok |
IsPowerOfTwo(x: int64): bool | Ob Zweierpotenz (x & (x−1)), nur für x > 0 wahr | ok |
NextPowerOfTwo(x: int64): int64 | Kleinste Zweierpotenz >= x; x ⇐ 1 ergibt 1 | ok |
PopCount(x: int64): int64 | Anzahl gesetzter Bits | behoben (#1545) |
Winkel in Mikrograd
Diese Gruppe rechnet Winkel als Mikrograd (1° = 1 000 000) und Funktionswerte als Festkomma mit Faktor 1 000 000 (1,0 = 1 000 000).
| Signatur | Beschreibung | Status |
|---|---|---|
Sin64(mikrograd: int64): int64 | Sinus; Ergebnis ×1.000.000 | ok |
Cos64(mikrograd: int64): int64 | Kosinus; Ergebnis ×1.000.000 | ok |
Cos64Inverse(cos_value: int64): int64 | Arkuskosinus; Ergebnis in Mikrograd | ok |
Atan2Microdegrees(y, x: int64): int64 | Quadranten-korrekter Arkustangens | behoben |
Beide früheren Defekte dieser Seite sind repariert. Nachgemessen mit 1.0.21A:PopCount(-1)= 64,PopCount(-2)= 63;Atan2Microdegrees(1, 1)= 45 000 000 (also genau 45°),(1, 0)= 90 000 000,(-1, -1)= −135 000 000. Ältere Fassungen dieser Seite rieten deshalb zu den f64-Funktionen — das ist nicht mehr nötig.
Zufallszahlen
| Signatur | Beschreibung | Status |
|---|---|---|
RandomRange(max: int64): int64 | Liefert [0, max) | behoben |
RandomBetween(min, max: int64): int64 | Liefert [min, max] | behoben |
Nachgemessen mit 1.0.21A über je 10 000 Ziehungen:RandomRange(100)bleibt vollständig in[0, 100)(min 0, max 99),RandomBetween(10, 20)verlässt den Bereich kein einziges Mal. Der früher hier verzeichnete Defekt besteht nicht mehr.
Für kryptografische Zwecke ist dieser Generator trotzdem ungeeignet — dafürstd.crypto.rand.
Die zugrunde liegenden Random() und RandomSeed(n) sind Compiler-Builtins, keine Funktionen dieser Unit.
f64-Funktionen
Grundoperationen
| Signatur | Beschreibung | Status |
|---|---|---|
AbsF64(x: f64): f64 | Betrag | ok |
NegF64(x: f64): f64 | Vorzeichenwechsel | ok |
MinF64(a, b: f64): f64 | Kleinerer Wert | ok |
MaxF64(a, b: f64): f64 | Größerer Wert | ok |
FloorF64(x: f64): f64 | Abrunden | ok |
CeilF64(x: f64): f64 | Aufrunden | ok |
RoundF64(x: f64): f64 | Kaufmännisch runden | ok |
TruncF64(x: f64): f64 | Nachkommastellen abschneiden (Richtung Null) | ok |
SqrtF64(x: f64): f64 | Quadratwurzel (nutzt das sqrt-Builtin) | ok |
Trigonometrie
Alle Winkel im Bogenmaß.
| Signatur | Beschreibung | Genauigkeit |
|---|---|---|
SinF64(x: f64): f64 | Sinus (Taylor-Reihe nach Argumentreduktion) | ~1e−6 über den geprüften Bereich |
CosF64(x: f64): f64 | Kosinus über sin(x + π/2) | wie SinF64 |
TanF64(x: f64): f64 | Tangens als Quotient; cos(x) == 0 ergibt 0 | ~1e−6 |
AtanF64(x: f64): f64 | Arkustangens, zweistufige Argumentreduktion + 13-gliedrige Reihe | besser als 1e−6 (gemessen bis zur Anzeigegrenze) |
Atan2F64(y, x: f64): f64 | Quadranten-korrekt, Bereich −π…π | wie AtanF64 |
AsinF64(x: f64): f64 | Arkussinus über atan(x/√(1−x²)) | besser als 1e−6 |
AcosF64(x: f64): f64 | Arkuskosinus über π/2 − asin(x) | besser als 1e−6 |
Exponential und Logarithmus
| Signatur | Beschreibung | Genauigkeit |
|---|---|---|
ExpF64(x: f64): f64 | e^x | ~1e−6 |
LogF64(x: f64): f64 | Natürlicher Logarithmus; x ⇐ 0 liefert −1.0 als Fehlerkennung | ~1e−6 |
Log10F64(x: f64): f64 | ln(x)/ln(10) | ~1e−6 |
Log2F64(x: f64): f64 | Logarithmus zur Basis 2 | ~1e−6 |
PowF64(base, exp: f64): f64 | e^(exp · ln base) | ~1e−6 |
Seit dem Fix von #1449 sind alle vier über den ganzen Wertebereich brauchbar — geprüft: ExpF64(5) = 148.413159, LogF64(100) = 4.605170, PowF64(2, 10) = 1024.000000. Die verbleibende Abweichung liegt bei rund einer Millionstel.
Zu beachten bleibt: LogF64(x ⇐ 0) gibt −1.0 als Fehlerkennung zurück — das ist zugleich ein gültiges Ergebnis (ln(1/e) = −1), Fehler und Resultat sind also nicht unterscheidbar.
Beispiele
Ganzzahl-Grundlagen
import std.math;
fn main(): int64 {
// Ganzzahl-Grundlagen
PrintLn("Abs64(-42) = ", IntToStr(Abs64(-42)));
PrintLn("Sign64(-7) = ", IntToStr(Sign64(-7)));
PrintLn("Clamp64(150,0,100)= ", IntToStr(Clamp64(150, 0, 100)));
PrintLn("InRange64(50,0,100)= ", IntToStr(InRange64(50, 0, 100) as int64));
PrintLn("Min3(9,4,7) = ", IntToStr(Min3(9, 4, 7)));
PrintLn("Max3(9,4,7) = ", IntToStr(Max3(9, 4, 7)));
// Wurzel, Potenz, Logarithmus
PrintLn("Sqrt64(1000000) = ", IntToStr(Sqrt64(1000000)));
PrintLn("Sqrt64(10) = ", IntToStr(Sqrt64(10)), " (floor)");
PrintLn("Pow64(2,10) = ", IntToStr(Pow64(2, 10)));
PrintLn("Log2(1024) = ", IntToStr(Log2(1024)));
PrintLn("Log2(1000) = ", IntToStr(Log2(1000)), " (floor)");
// Skalierung
PrintLn("Lerp64(100,200,500) = ", IntToStr(Lerp64(100, 200, 500)));
PrintLn("Map64(512,0,1023,0,100) = ", IntToStr(Map64(512, 0, 1023, 0, 100)));
return 0;
}
Ausgabe:
Abs64(-42) = 42
Sign64(-7) = -1
Clamp64(150,0,100)= 100
InRange64(50,0,100)= 1
Min3(9,4,7) = 4
Max3(9,4,7) = 9
Sqrt64(1000000) = 1000
Sqrt64(10) = 3 (floor)
Pow64(2,10) = 1024
Log2(1024) = 10
Log2(1000) = 9 (floor)
Lerp64(100,200,500) = 150
Map64(512,0,1023,0,100) = 50
Lerp64 interpoliert in Promille: t = 500 sind 50 %, daher genau die Mitte zwischen 100 und 200. Map64 skaliert einen 10-Bit-Sensorwert (0…1023) auf Prozent.
Zahlentheorie
import std.math;
fn main(): int64 {
PrintLn("GCD(48,18) = ", IntToStr(GCD(48, 18)));
PrintLn("LCM(4,6) = ", IntToStr(LCM(4, 6)));
PrintLn("IsPrime(97) = ", IntToStr(IsPrime(97) as int64));
PrintLn("NextPrime(90) = ", IntToStr(NextPrime(90)));
PrintLn("IsPowerOfTwo(1024) = ", IntToStr(IsPowerOfTwo(1024) as int64));
PrintLn("NextPowerOfTwo(1000)= ", IntToStr(NextPowerOfTwo(1000)));
PrintLn("PopCount(255) = ", IntToStr(PopCount(255)));
// Primzahlen bis 30 sammeln
var n: int64 := 2;
var zeile: pchar := "Primzahlen < 30:";
while (n < 30) {
if (IsPrime(n)) { zeile := StrConcat(zeile, StrConcat(" ", IntToStr(n))); }
n := n + 1;
}
PrintLn(zeile);
return 0;
}
Ausgabe:
GCD(48,18) = 6
LCM(4,6) = 12
IsPrime(97) = 1
NextPrime(90) = 97
IsPowerOfTwo(1024) = 1
NextPowerOfTwo(1000)= 1024
PopCount(255) = 8
Primzahlen < 30: 2 3 5 7 11 13 17 19 23 29
NextPowerOfTwo ist der übliche Weg, eine Puffergröße auf die nächste Zweierpotenz aufzurunden.
f64-Mathematik
import std.io;
import std.math;
fn zeige(name: pchar, v: f64): void {
PrintLn(name, " = ", FloatToStr(v, 4)); // zweites Argument: Nachkommastellen
}
fn main(): int64 {
zeige("SqrtF64(2) ", SqrtF64(2 as f64));
zeige("SinF64(1) ", SinF64(1 as f64));
zeige("CosF64(0) ", CosF64(0 as f64));
zeige("AtanF64(1) ", AtanF64(1 as f64));
zeige("Atan2F64(1,1)", Atan2F64(1 as f64, 1 as f64));
zeige("AcosF64(0) ", AcosF64(0 as f64));
zeige("Log2F64(1024)", Log2F64(1024 as f64));
zeige("ExpF64(1) ", ExpF64(1 as f64));
// Runden und Begrenzen
var x: f64 := fDiv(7 as f64, 2 as f64); // 3.5
zeige("FloorF64(3.5)", FloorF64(x));
zeige("CeilF64(3.5) ", CeilF64(x));
zeige("RoundF64(3.5)", RoundF64(x));
zeige("TruncF64(3.5)", TruncF64(x));
zeige("AbsF64(-3.5) ", AbsF64(fNeg(x)));
zeige("MinF64(3.5,2)", MinF64(x, 2 as f64));
return 0;
}
Ausgabe:
SqrtF64(2) = 1.414213
SinF64(1) = 0.841470
CosF64(0) = 1.000000
AtanF64(1) = 0.785398
Atan2F64(1,1) = 0.785398
AcosF64(0) = 1.570796
Log2F64(1024) = 10.000000
ExpF64(1) = 2.718281
FloorF64(3.5) = 3.000000
CeilF64(3.5) = 4.000000
RoundF64(3.5) = 4.000000
TruncF64(3.5) = 3.000000
AbsF64(-3.5) = 3.500000
MinF64(3.5,2) = 2.000000
Die Genauigkeit reicht heute bis an die Anzeigegrenze von sechs Nachkommastellen: CosF64(0) liefert 1.000000, SinF64(3) das korrekte 0.141120. Bis Version 1.0.12A rechneten Sinus und Kosinus mit der Näherung π ≈ 355/113 und wichen ab der sechsten Stelle ab — diese Einschränkung gilt nicht mehr.
Gleitkommazahlen entstehen in Lyx über as f64 oder fDiv — ein Literal wie 3.5 gibt es in dieser Form nicht, daher fDiv(7 as f64, 2 as f64).
Genauigkeit und bekannte Fehler
Alle Angaben mit lyxc 1.0.20F gemessen. Die früher hier verzeichneten Rechenfehler sind behoben (#1444–#1450):
| Aufruf | Ergebnis | erwartet |
|---|---|---|
Sin64(30000000) | 500000 | 500000 |
Sin64(90000000) | 1000000 | 1000000 |
Cos64(60000000) | 500000 | 500000 |
Cos64(0) | 1000000 | 1000000 |
Hypot64(3, 4) | 5 | 5 |
Atan2Microdegrees(1000, 1000) | 45000000 | 45000000 (= 45°) |
IsOdd(-3) | 1 | 1 |
PopCount(-1) | 64 | 64 |
RoundF64(2.6) | 3.000000 | 3.000000 |
Winkel werden in Mikrograd übergeben
Das ist die wichtigste Umstellung: Sin64, Cos64 und Atan2Microdegrees rechnen in Mikrograd, das Ergebnis der Winkelfunktionen ist mit 1.000.000 skaliert.
Sin64(30000000) // Sinus von 30° → 500000 (= 0,5)
Cos64(0) // → 1000000 (= 1,0)
Wer versehentlich Grad einsetzt, bekommt kein falsches Ergebnis, sondern praktisch null: Sin64(30) sind 30 Mikrograd, also 0,00003° — der Sinus davon ist auf sechs Stellen 0. Der Fehler fällt damit leicht als „Funktion kaputt“ fehlgedeutet aus.
Round64 heißt jetzt RoundF64
Die frühere Attrappe Round64(x: int64) ist entfallen (#1450). An ihrer Stelle steht RoundF64(x: f64): f64, das tatsächlich rundet.
Exp, Log und Pow arbeiten jetzt genau (#1449 behoben)
| Aufruf | Ergebnis | korrekt |
|---|---|---|
ExpF64(1) | 2.718281 | 2.718282 |
ExpF64(3) | 20.085536 | 20.085537 |
ExpF64(5) | 148.413159 | 148.413159 |
LogF64(10) | 2.302585 | 2.302585 |
LogF64(100) | 4.605170 | 4.605170 |
Log10F64(100) | 1.999999 | 2.000000 |
PowF64(2, 10) | 1024.000000 | 1024.000000 |
Früher fehlte die Argumentreduktion, wodurch ExpF64(5) um 13 % und PowF64(2, 10) um 39 % danebenlagen. Das ist behoben; die verbleibende Abweichung von etwa 1e−6 stammt aus der Festkomma-Näherung von π und e und reicht für alles außer numerisch empfindlichen Rechnungen.
====
Round64(x: int64): int64 gibt x unverändert zurück. Da der Parameter bereits ganzzahlig ist, gibt es nichts zu runden — die Funktion kann nur aus einem abgebrochenen Umbau stammen. Sie sieht am Aufrufort nach einer Rundung aus und tut nichts. Für f64 RoundF64 verwenden.
Empfehlung
Die Warnungen früherer Fassungen dieser Seite sind hinfällig. Gegen 1.0.21A einzeln nachgemessen: PopCount(-1) = 64, IsOdd(-3) = 1, Hypot64(3, 4) = 5 und Hypot64(300, 400) = 500, Sin64(45°) = 707107, Cos64(60°) = 500000, Atan2Microdegrees(1, 1) = 45 000 000, und beide Zufallsfunktionen halten über 10 000 Ziehungen ihren Bereich ein.
- Ganzzahl-Grundlagen und Zahlentheorie sind belastbar, einschließlich
PopCountundIsOddbei negativen Argumenten. - Die Mikrograd-Gruppe ist benutzbar. Zu beachten bleibt allein die Einheit: Winkel gehen in Mikrograd hinein (1° = 1 000 000), Funktionswerte kommen mit Faktor 1 000 000 heraus.
Pow64läuft bei großen Werten still über; Argumente vorab gegenLog2plausibilisieren. Wer den vollen Bereich braucht, nimmt std.i128 oder std.bignum.
Wann eine der neuen Rechen-Units die bessere Wahl ist (→ Mathematik-Units):
^ Anliegen ^ Unit ^
|exp/log/sinmit vollerf64-Genauigkeit statt ~1e−6 | std.mathx |
| Bitmengen, Rotation in beliebiger Breite, Schieben ohne Modulo-64 | std.bits |
| Primzahltest jenseits vonint64| std.prime |
| Überlauf melden statt umschlagen lassen | std.sat |
| Fließkomma vergleichen, ULP, Rundungsarten | std.feq |
| Nullstellen, Integration, ODE | std.numeric |
Verwandte Units
- std.math.constants — Präzisionskonstanten (π, e, √2, φ, ln 2 …), Winkelkonvertierungen,
ApproxEqual - std.math_batch — SIMD-beschleunigte Batch-Operationen auf int64-Arrays
- std.vector — 2D/3D-Vektormathematik (baut auf std.math auf)
- std.stats — Mittelwert, Varianz, Standardabweichung
