std.money — Geldbeträge
Beträge als skalierte Ganzzahlen: sieben Rundungsarten, Mehrwertsteuer vor- und rückwärts, Aufteilen ohne verlorene Cents, Formatieren nach Landesart.
→ Mathematik-Units · std.sat · std.rat · KassenSichV
import std.money;
Schicht 1, hängt an std.sat und std.alloc. 27 Funktionen, elf Konstanten. Alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt.
Geld ist keine Fließkommazahl
<WRAP alert>
0,10 + 0,20 ist in f64 nicht 0,30 (→ std.feq). Für eine Rechnung, die stimmen muss, ist das disqualifizierend.
std.money rechnet deshalb in Ganzzahlen — der Betrag ist ein int64 in der kleinsten Einheit, die Skala sagt, wo das Komma steht. 1050 bei Skala 2 sind 10,50. Alle Grundrechenarten sind damit exakt; gerundet wird nur dort, wo es unvermeidlich ist, und dann ausdrücklich.
</WRAP>
MONEY_INVALID ist der kleinste int64-Wert und markiert ein ungültiges Ergebnis; MoneyIsValid(v) fragt danach. Die Grundrechenarten setzen auf std.sat auf und melden einen Überlauf, statt ihn umschlagen zu lassen.
Runden: sieben Arten, und warum das nötig ist
unit main;
import std.io;
import std.string;
import std.alloc;
import std.money;
fn ZI(t: pchar, v: int64): void { Print(t); PrintLn(IntToStr(v)); }
fn main(): int64 {
ZI("Add(1050, 299) : ", MoneyAdd(1050, 299));
ZI("DivRound(100, 3, HALF_UP) : ", MoneyDivRound(100, 3, MONEY_HALF_UP));
ZI("DivRound(250, 100, HALF_UP) : ", MoneyDivRound(250, 100, MONEY_HALF_UP));
ZI("DivRound(250, 100, HALF_EVEN): ", MoneyDivRound(250, 100, MONEY_HALF_EVEN));
ZI("DivRound(350, 100, HALF_EVEN): ", MoneyDivRound(350, 100, MONEY_HALF_EVEN));
ZI("DivRound(-250, 100, FLOOR) : ", MoneyDivRound(-250, 100, MONEY_FLOOR));
return 0;
}
Add(1050, 299) : 1349
DivRound(100, 3, HALF_UP) : 33
DivRound(250, 100, HALF_UP) : 3
DivRound(250, 100, HALF_EVEN): 2
DivRound(350, 100, HALF_EVEN): 4
DivRound(-250, 100, FLOOR) : -3
Bei 2,5 gehen die Verfahren auseinander, bei 3,5 nicht. HALF_EVEN rundet zur geraden Nachbarzahl — über viele Beträge hebt sich der Rundungsfehler damit auf, statt sich zu summieren. Das ist der Grund, warum es im Bankwesen und in der Statistik die Vorgabe ist.
| Konstante | Verhalten bei x,5 |
|---|---|
MONEY_HALF_UP | von der Null weg (Schulregel) |
MONEY_HALF_EVEN | zur geraden Zahl (kaufmännisch, bankers' rounding) |
MONEY_HALF_DOWN | zur Null hin |
MONEY_UP | immer von der Null weg |
MONEY_DOWN | immer zur Null hin (abschneiden) |
MONEY_FLOOR | immer nach unten |
MONEY_CEIL | immer nach oben |
MONEY_DOWN und MONEY_FLOOR unterscheiden sich nur bei negativen Beträgen: −2,5 wird zu −2 beziehungsweise −3.
MoneyRoundTo(v, scale, places, mode) rundet auf eine Stellenzahl, MoneyRoundToMultiple(v, mult, mode) auf ein Vielfaches — für die Fünf-Rappen-Rundung in der Schweiz oder Preisenden auf 0,99.
Mehrwertsteuer in beide Richtungen
var brutto: int64 := MoneyAddTax(10000, 1900, 4, MONEY_HALF_UP);
var steuer: int64 := MoneyTaxOfGross(11900, 1900, 4, MONEY_HALF_UP);
var netto: int64 := MoneyNetOfGross(11900, 1900, 4, MONEY_HALF_UP);
AddTax(10000, 19%) : 11900
TaxOfGross(11900, 19%): 1900
NetOfGross(11900, 19%): 10000
Der Satz wird als skalierte Ganzzahl übergeben: 1900 bei rateScale 4 sind 19 %. Damit lassen sich auch krumme Sätze wie 8,25 % exakt darstellen (825 bei Skala 4).
Rückwärts ist nicht dasselbe wie vorwärts. Aus dem Bruttobetrag den Steueranteil zu ziehen ist eine andere Rechnung als den Nettobetrag zu erhöhen — deshalb gibt es dafür eigene Funktionen. Werbrutto − brutto/1,19selbst rechnet, bekommt bei manchen Beträgen einen Cent Abweichung gegenüber dem, was das Finanzamt erwartet.
MoneyMulRate und MoneyPercent sind die allgemeinen Formen für Kurse und Prozentsätze.
Aufteilen ohne Centverlust
var out: int64 := alloc(3 * 8);
MoneySplit(1000, 3, out);
Split(1000, 3) : 334 333 333 Summe=1000
Die Summe der Teile ist wieder der Ausgangsbetrag. 10,00 € durch drei geteilt ergibt nicht dreimal 3,33 (das wären 9,99), sondern 3,34 + 3,33 + 3,33. Der Rest wird auf die vorderen Teile verteilt, statt zu verschwinden.
MoneyAllocate(total, weights, n, out) macht dasselbe gewichtet — für Rabatte, Umlagen und Skonti, die anteilig auf Positionen verteilt werden müssen, ohne dass am Ende ein Cent fehlt.
Formatieren und Einlesen
var buf: int64 := alloc(64);
MoneyFormat(123456, 2, buf, 64, MONEY_FMT_DE);
Format(123456, DE) : 1.234,56
Format(123456, CH) : 1'234.56
| Konstante | Ergebnis |
|---|---|
MONEY_FMT_PLAIN | 1234.56 |
MONEY_FMT_DE | 1.234,56 |
MONEY_FMT_EN | 1,234.56 |
MONEY_FMT_CH | 1'234.56 |
MoneyParse(s, scale, mode) liest zurück und liefert MONEY_INVALID, wenn die Zeichenkette nicht passt.
Währungen
MoneyCurrencyScale("EUR"c) // 2
MoneyCurrencyScale("JPY"c) // 0
MoneyCurrencyScale("KWD"c) // 3
CurrencyScale(EUR) : 2
CurrencyScale(JPY) : 0
CurrencyScale(KWD) : 3
<WRAP alert>
Der Parameter ist die Adresse einer Zeichenkette, kein Zahlencode. MoneyCurrencyScale(„EUR“c) — wer eine beliebige Zahl übergibt, liest an dieser Adresse und bekommt einen Speicherzugriffsfehler. Die Funktion fängt nur den Fall 0 ab.
</WRAP>
Yen und Won haben keine Nachkommastellen, die Golfwährungen (KWD, BHD, OMR) drei. Genau diese Ausreißer sind der Grund, warum die Skala überhaupt ein Parameter ist — wer fest mit Cents rechnet, liegt bei jedem Yen-Betrag um den Faktor 100 daneben. Unbekannte Codes bekommen 2.
Erfasst sind derzeit nur die Ausreißer; eine vollständige ISO-4217-Tabelle gibt es nicht.
Funktionsübersicht
| Gruppe | Funktionen |
|---|---|
| Grundrechenarten | MoneyAdd · MoneySub · MoneyNeg · MoneyAbs · MoneyMulInt · MoneyDivInt · MoneySum |
| Vergleichen | MoneyCmp · MoneySign · MoneyMin · MoneyMax · MoneyIsValid |
| Runden | MoneyDivRound · MoneyRoundTo · MoneyRoundToMultiple · MoneyPow10 |
| Skala wechseln | MoneyRescale |
| Sätze und Steuern | MoneyMulRate · MoneyPercent · MoneyAddTax · MoneyTaxOfGross · MoneyNetOfGross |
| Verteilen | MoneySplit · MoneyAllocate |
| Text | MoneyParse · MoneyFormat · MoneyCurrencyScale |
Letzte Aktualisierung: 2026-08-16 · alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt; Rundungsarten, Steuerrechnung in beide Richtungen und die Summenerhaltung beim Aufteilen einzeln nachgemessen.
