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.
<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.
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.
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.
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.
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.
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.
| 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.