std.dist — Abstandsmaße
Abstände zwischen dichten f64-Vektoren: Euklid, Manhattan, Chebyshev, Minkowski, Kosinus, Hamming, Jaccard — durchgehend über einen überlaufsicheren hypot.
→ Mathematik-Units · std.sparse · std.grid · std.sum
import std.dist;
Schicht 0, hängt an std.math und std.alloc. 20 Funktionen. Alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt.
Darstellung
Ein Vektor ist ein Speicherblock aus nd f64-Werten — alloc(nd * 8), beschrieben mit pokef64. Eine Punktmenge ist dasselbe hintereinander: count Punkte zu je nd Werten.
Drei Units bringenEuclidundManhattanmit — das ist Absicht.std.distrechnet auf dichtenf64-Vektoren, std.sparse auf dünnbesetzten (sortierte Index/Wert-Paare), std.grid auf ganzzahligen Gitterkoordinaten. Drei Darstellungen, drei Implementierungen — wer den falschen Nachbarn wählt, zahlt mit Speicher oder Genauigkeit.
Die Maße
unit main;
import std.io;
import std.string;
import std.alloc;
import std.dist;
fn ZF(t: pchar, v: f64): void { Print(t); PrintF64(v); }
fn main(): int64 {
var nd: int64 := 3;
var a: int64 := alloc(nd * 8);
var b: int64 := alloc(nd * 8);
pokef64(a, 0.0); pokef64(a + 8, 3.0); pokef64(a + 16, 4.0);
pokef64(b, 0.0); pokef64(b + 8, 0.0); pokef64(b + 16, 0.0);
ZF("Euclid(a,0) : ", DistEuclid(a, b, nd));
ZF("Manhattan(a,0) : ", DistManhattan(a, b, nd));
ZF("Chebyshev(a,0) : ", DistChebyshev(a, b, nd));
ZF("Minkowski p=3 : ", DistMinkowski(a, b, nd, 3.0));
ZF("Norm(a) : ", DistNorm(a, nd));
return 0;
}
Euclid(a,0) : 5.000000
Manhattan(a,0) : 7.000000
Chebyshev(a,0) : 4.000000
Minkowski p=3 : 4.497941
Norm(a) : 5.000000
Für (0, 3, 4): Euklid 5, Manhattan 3+4 = 7, Chebyshev max(3,4) = 4. Minkowski mit p verbindet die drei — p=1 ist Manhattan, p=2 ist Euklid, große p nähern sich Chebyshev.
| Funktion | Maß |
|---|---|
DistEuclid / DistEuclidSq | euklidisch, mit und ohne Wurzel |
DistManhattan | Summe der Beträge |
DistChebyshev | größte Einzelabweichung |
DistMinkowski(a, b, nd, p) | verallgemeinert, p frei |
DistNorm / DistNormSq | Länge eines einzelnen Vektors |
DistHamming | Anzahl abweichender Stellen |
DistHammingBits | dasselbe auf Bitmustern |
DistJaccard | Mengenähnlichkeit |
DistEuclidSq spart die Wurzel — für Vergleiche genügt das quadrierte Maß, und die Reihenfolge bleibt dieselbe.
Überlaufsicherheit: der eigentliche Punkt
Die naheliegende Formel √(x² + y²) überläuft, lange bevor das Ergebnis es täte. std.dist rechnet durchgehend über DistHypot:
unit main;
import std.io;
import std.string;
import std.feq;
import std.dist;
fn main(): int64 {
var h: f64 := DistHypot(1.0e200, 1.0e200);
Print("Bits(hypot(1e200,1e200)) = "); PrintLn(IntToStr(FeqBits(h)));
Print("hypot ist endlich : "); PrintLn(IntToStr(FeqIsFinite(h) as int64));
var big: f64 := 1.0e200;
var naive: f64 := big * big + big * big;
Print("Bits(naiv x*x + y*y) = "); PrintLn(IntToStr(FeqBits(naive)));
Print("naiv ist unendlich : "); PrintLn(IntToStr(FeqIsInf(naive) as int64));
var q: f64 := h / 1.0e200;
Print("hypot / 1e200 = "); PrintF64(q);
return 0;
}
Bits(hypot(1e200,1e200)) = 7601389629357644631
hypot ist endlich : 1
Bits(naiv x*x + y*y) = 9218868437227405312
naiv ist unendlich : 1
hypot / 1e200 = 1.414213
DistHypot liefert ein endliches Ergebnis, die naive Formel inf. Das Bitmuster 7601389629357644631 entspricht 1,4142135623730951e200 — bitgleich mit der Referenzrechnung. 9218868437227405312 ist das Bitmuster von +inf.
<WRAP alert>
PrintF64 zeigt für dieses Ergebnis overflow. Das ist eine Grenze der Ausgabe, nicht der Rechnung — ab etwa 1e19 kann PrintF64 den Wert nicht mehr darstellen. Wer große Zwischenergebnisse prüft, gibt das Bitmuster über FeqBits aus oder teilt vorher herunter (oben h / 1e200). Andernfalls sieht eine korrekte Rechnung wie ein Fehler aus.
</WRAP>
DistHypot3(x, y, z) macht dasselbe für drei Achsen.
Kosinus: Ähnlichkeit oder Abstand
ZF("CosineSimilarity(x, 2x) : ", DistCosineSimilarity(c, d, nd));
ZF("Cosine(x, 2x) : ", DistCosine(c, d, nd));
CosineSimilarity(x,2x) : 1.000000
Cosine(x,2x) : 0.000000
Für zwei Vektoren, die in dieselbe Richtung zeigen und sich nur in der Länge unterscheiden: Ähnlichkeit 1, Abstand 0.
| Funktion | Wertebereich | Bedeutung |
|---|---|---|
DistCosineSimilarity | −1 … 1 | 1 = gleiche Richtung |
DistCosine | 0 … 2 | 1 − Ähnlichkeit |
DistAngular | 0 … π | der Winkel selbst |
Die Verwechslung der ersten beiden ist der häufigste Fehler bei Ähnlichkeitssuchen: wer nach dem kleinsten Wert sortiert, will DistCosine; wer nach dem größten sortiert, DistCosineSimilarity. DistAngular ist im Gegensatz zu beiden eine echte Metrik und erfüllt die Dreiecksungleichung — nötig, sobald ein Suchbaum darauf aufsetzt.
Über Punktmengen
| Funktion | Zweck |
|---|---|
DistNearest(point, set, count, nd, …) | nächster Punkt der Menge |
DistFarthest(point, set, count, nd, …) | entferntester |
DistMatrix(set, count, nd, out) | alle paarweisen Abstände |
DistCentroid(set, count, nd, out) | Schwerpunkt |
DistWithin(a, b, nd, radius) | liegt b im Radius um a? |
DistMatrix schreibt count × count Werte — der Zielpuffer muss entsprechend groß sein. Bei 10 000 Punkten sind das 800 MB; für große Mengen ist DistNearest der richtige Weg.
DistWithin vergleicht ohne Wurzelziehen und ist damit billiger als DistEuclid(…) ⇐ radius.
Letzte Aktualisierung: 2026-08-16 · alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt; die Überlaufsicherheit von DistHypot bitgenau gegen eine unabhängige Referenzrechnung geprüft.
