Die römische Zahlschrift besteht aus den folgenden lateinischen Buchstaben:
römisch | I | V | X | L | C | D | M |
arabisch | 1 | 5 | 10 | 50 | 100 | 500 | 1000 |
Eine Darstellung der 0 war den alten Römern nicht bekannt. Darstellungen für Zahlen größer als 1000 wurden lange Zeit ebenfalls nicht benötigt. Mittlerweile gibt es auch Darstellungen für 5000 (ↁ), 10000 (ↂ), 50000 (ↇ) und 100000 (ↈ). Zu weiteren Details siehe z.B. bei Wikipedia.
Die Berechnung des Wertes einer römischen Zahl, also die Umwandlung in eine arabische Zahl, erfolgt von links nach rechts, indem Zeichen für Zeichen addiert wird:
MCCXXXVI = M + C + C + X + X + X + V + I = 1000 + 100 + 100 + 10 + 10 + 10 + 5 + 1 = 1236
Allerdings gibt es eine Ausnahme, die sogenannte Subtraktionsregel, die besagt: Steht ein Zeichen mit geringerem Wert vor einem Zeichen mit
höherem Wert, dann wird der Wert des ersten Zeichens von dem Wert des zweiten Zeichens subtrahiert:
CM = 1000 - 100 = 900, CD = 500 - 100 = 400, XC = 100 - 10 = 90, XL = 50 - 10 = 40, IX = 10 - 1 = 9 und IV = 5 - 1 = 4.
Vor den römischen Ziffern M und D kann also nur die Ziffer C geschrieben werden; vor C und L nur X und vor X und V nur I. Ich bezeichne sie in dieser Konstellation als Präfix. Die "fünfer"-Zeichen D, L und V werden einem größeren Zeichen nicht vorangestellt, sie können niemals Präfix sein.
MMCDXCIV = M + M + (D - C) + (C - X) + (V - I) = 1000 + 1000 + 400 + 90 + 4 = 2494
Bei Uhren mit römischem Ziffernblatt wird die 4 oft als IIII dargestellt,
während die Darstellung IX der 9 der Subtraktionsregel folgt.
Bei der Umrechnung einer arabischen in eine römische Zahl geht man analog vor. Zunächst wird der Wert in Zehnerpotenzen zerlegt:
1234 = 1000 + 200 + 30 + 4
Mit der größten römischen Ziffer beginnend wird deren Wert so häufig wie möglich abgezogen und notiert:
1000 = M 200 = CC 30 = XXX 4 = IIII
Stehen jetzt 4 gleiche Zeichen hintereinander, dann wird statt dessen die Subtraktionsregel angewendet:
4 = 5 - 1 = IV
In obigem Beispiel ergibt sich also:
1234 = M CC XXX IV -> MCCXXXIV
Zur Berechnung der römischen Zahlzeichen definiere ich in Javascript zunächst ein Objekt für römische Zahlen:
function RoemischeZahl(darstellung, wert, praefix) { this.Darstellung = darstellung; this.Wert = wert; this.Praefix = praefix; }
Dann definiere ich die bekannten römischen Ziffern und ein Array dieser Ziffern:
var O = new RoemischeZahl("", 0, null); var I = new RoemischeZahl("I", 1, O); var V = new RoemischeZahl("V", 5, I); var X = new RoemischeZahl("X", 10, I); var L = new RoemischeZahl("L", 50, X); var C = new RoemischeZahl("C", 100, X); var D = new RoemischeZahl("D", 500, C); var M = new RoemischeZahl("M", 1000, C); // Absteigend sortiert var RoemischeZahlen = new Array(M, D, C, L, X, V, I, O);
Die Pseudozahl "O" für die 0 definiere ich, damit jede "echte" römische Zahl - und insbesondere "I" - einen Präfix hat. Alternativ müsste vor Verwendung des Präfix getestet werden, ob dieser auch existiert.
Der Algorithmus ist in folgender Funktion definiert:
function gibRoemisch(arabisch) { for( var i = 0; i < RoemischeZahlen.length; i++ ) { if( RoemischeZahlen[i].Wert == arabisch ) return RoemischeZahlen[i].Darstellung; else if( RoemischeZahlen[i].Wert == arabisch + RoemischeZahlen[i].Praefix.Wert ) return RoemischeZahlen[i].Praefix.Darstellung + RoemischeZahlen[i].Darstellung; else if( RoemischeZahlen[i].Wert < arabisch ) return RoemischeZahlen[i].Darstellung + gibRoemisch(arabisch - RoemischeZahlen[i].Wert); } }
Jetzt muss die Zahl nur noch in Zehnerpotenzen aufgeteilt und jeweils die römische Darstellung ermittelt werden:
// Ganzzahlige Division function intDiv(x, y) { return ( x - (x % y) ) / y; } function gibRoemischeZahl(arabischeZahl) { if( 0 >= arabischeZahl ) return ""; var arabisch1000 = intDiv(arabischeZahl, M.Wert) * M.Wert; var arabisch100 = intDiv((arabischeZahl - arabisch1000), C.Wert) * C.Wert; var arabisch10 = intDiv((arabischeZahl - arabisch1000 - arabisch100), X.Wert) * X.Wert; var arabisch1 = arabischeZahl - arabisch1000 - arabisch100 - arabisch10; return ( 0 < arabisch1000 ? gibRoemisch(arabisch1000) : "" ) + ( 0 < arabisch100 ? gibRoemisch(arabisch100) : "" ) + ( 0 < arabisch10 ? gibRoemisch(arabisch10) : "" ) + gibRoemisch(arabisch1); }
In Java (ab Version 1.8) ist der Algorithmus genauso definiert. Die römischen Zahlen und ihre Umrechnung habe ich in eine Enumeration verpackt: ᐁ
Java und C# sind relativ ähnlich. Allerdings verwende ich hier keine Enumeration und spare mir die Pseudozahl "O" für 0.
Dafür muss ich dann testen, ob für eine römische Ziffer ein sog. Präfix definiert ist.
Das Array aller römischen Ziffern hätte ich natürlich sofort absteigend sortiert definieren können,
wollte aber mal ein Beispiel für die Verwendung von Lambda's ausprobieren 😏:
ᐁ
Bitte geben Sie eine arabische Zahl zwischen 1 und 3999 ein.