Umwandlung arabischer in römische Zahlen

Die römische Zahlschrift besteht aus den folgenden lateinischen Buchstaben:

römischIVXLCDM
arabisch1510501005001000

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.

Berechnung des Wertes einer römischen Zahl

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 Uhr

Bei Uhren mit römischem Ziffernblatt wird die 4 oft als IIII dargestellt,
während die Darstellung IX der 9 der Subtraktionsregel folgt.

Berechnung einer römischen Zahl

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

Programmierung

Javascript

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);
}

Java

In Java 8 ist der Algorithmus genauso definiert. Die römischen Zahlen und ihre Umrechnung habe ich in eine Enumeration verpackt:

C#

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 😏:

Test

Bitte geben Sie eine arabische Zahl zwischen 1 und 3999 ein.