Lothar Schmitz, Universität der Bundeswehr München
Diese Woche geht es um das Aussprechen von Zahlen, wie das zum Beispiel ein Auto-Navigationssystem für jede benötigte Entfernungsangabe fertigbringt.
Die freundliche Stimme unseres Auto-Navis sagt dabei nicht wie ein alter Blech-Roboter:
Nein, sie spricht die Zahl genauso aus wie wir:
Ein "weltraumtaugliches" Navigationssystem müsste noch viel größere Zahlen aussprechen können, z.B. die Zahl
-
zwölf Billiarden
dreihundertfünfundvierzig Billionen
sechshundertachtundsiebzig Milliarden
neunhundertsiebenundachtzig Millionen
sechshundertvierundfünfzigtausend
dreihunderteinundzwanzig
Sowas kann eigentlich jeder von uns. Aber wie sieht ein entsprechendes Programm aus? Da steckt der Teufel wie so oft im Detail! Wir präzisieren zuerst die Aufgabenstellung.
Aufgabe: Gegeben eine Zahl x mit 1 ≤ x ≤ 1024. Erzeuge den Text, wie die Zahl auf Deutsch ausgesprochen wird! Wir gehen davon aus, dass Zahlen dieser Größe in der verwendeten Programmiersprache dargestellt werden können und dass Grundrechenarten wie Addition, Subtraktion, Multiplikation und Division (ganzzahlig mit Rest) zur Verfügung stehen.
Lösungsidee: Wie im Beispiel oben teilt man eine Zahl von rechts beginnend in Gruppen zu je 3 Ziffern auf:
-
Einer
Tausender
Millionen
Milliarden
Billionen
Billiarden
u.s.w.
Eine Zahl lässt sich wie folgt von rechts beginnend in Dreierzifferngruppen zerlegen (Kommentare in grün):
Anschließend enthält das Array gruppe die Zifferngruppen: die Einer in gruppe[0], die Tausender in gruppe[1], die Millionen in gruppe[2], die Milliarden in gruppe[3] ... Und in der Variablen i steht der Index der zuletzt gefundenen Gruppe.
Welche Namen es für große Zahlen gibt, kann man auf der Wikipedia-Seite Zahlennamen nachlesen. Dort erfährt man z.B., dass auf die Billiarden die Trillionen und Trilliarden folgen und dass eine Oktillion der Zahl 1048 enstpricht: das ist eine 1 mit 48 Nullen!
Der Rest des Verfahrens besteht nun darin, die Texte zu den Dreiergruppen zu erzeugen, und zwar beginnend mit der, die sich am weitesten links befindet. Wenn wir wissen, wie man den Zahltext zu einer Dreiergruppe erzeugt, dann ist die Aufgabe im Prinzip gelöst. Wenden wir uns also dieser Teilaufgabe zu!
Der Textanteil einer Dreiergruppe ist leer, wenn die Dreiergruppe den Wert 0 hat. Das zeigt ein Beispiel:
Spätestens an dieser Stelle muss man den Text zu jeder Ziffer kennen, um ihn ausgeben zu können. Da die Zahlen kleiner als 20 ziemlich unregelmäßig gebildet werden - z.B. "siebzehn" statt "siebenzehn" -, merken wir uns für jede dieser Zahlen den Text in einem Array:
kleiner20 : array [1..19] of String := [ "ein", "zwei", "drei", "vier", ... , "achtzehn", "neunzehn" ]
Für eine Zahl i zwischen 1 und 19 findet man den Text also in kleiner20[i]. Entsprechend verfahren wir mit den Zehnern (wobei für i zwischen 2 und 9 zehner[i] der Text zu i*10 ist):
zehner : array [2..9] of String := [ "zwanzig", "dreißig", "vierzig", ... , "achtzig", "neunzig" ]
Wir kommen nun zum Kern des Verfahrens, der Funktion sprichDreier, die den Text zu einer höchstens dreistelligen Zahl erzeugt. Der Text wird in der String-Variablen erg aufgesammelt: erg ist anfangs leer; Text anfügen kann man mit "&". Zuerst wird die Hunderterstelle angefügt, dann der Rest. Ist der Rest < 20, dann entnimmt man den Text direkt dem Array kleiner20. Andernfalls fügt man an: Einerstelle - "und" - Zehnerstelle (in dieser Reihenfolge!). Beachte, dass praktisch alles fehlen kann! So wird z.B. das "und" zwischen Einern und Zehnern nur dann gebraucht, wenn sowohl Einer als auch Zehner vorhanden sind.
Wandeln wir nach diesem Verfahren dreistellige Zahlen um, dann ergibt sich für viele Zahlen das gewünschte Resultat:
-
Für 111 ergibt sich "einhundertelf"
Für 627 ergibt sich "sechshundertsiebenundzwanzig"
Für 308 ergibt sich "dreihundertacht"
-
Für 1 ergibt sich "ein"
Für 901 ergibt sich "neunhundertein"
Tatsächlich gibt es immer dann Probleme, wenn die Dreiergruppe mit "01" endet. Die naheliegende Reparatur, in dem Array kleiner20 den String "ein" durch "eins" zu ersetzen, funktioniert leider nicht: Z.B. für 41 ergäbe sich dann nämlich "einsundvierzig". Noch mehr Fälle sind bezüglich der Endziffer 1 bei großen Zahlen zu berücksichtigen. Wir sagen ja:
-
"eintausend" für 1 000
"eine Million" für 1 000 000
"neunhunderteins Millionen" für 901 000 000
Die Lösung besteht aus zwei Maßnahmen:
- In Dreiergruppen unterscheidet man zwischen Singular (für die 1), Plural und dem Sonderfall, dass die Dreiergruppe auf "01" endet (z.B. in 901).
-
Die Anhänge an die Dreiergruppe unterscheidet man je nach dem, ob Singular oder
Plural vorliegt und nach der Art der Dreiergruppe (Einer, Tausender, Millionen):
- "eins" und "neunhunderteins"
- "eintausend" und "neunhunderteinstausend"
- "eine Million" und "neunhunderteins Millionen"
Für die Anhänge verwenden wir dazu drei Arrays von Strings mit den unterschiedlichen Anhängen:
singular : array [1..8] of String := ["s", "tausend", "e Million", "e Milliarde", ... ,"e Trilliarde"]
plural : array [1..8] of String := [ "", "tausend ", " Millionen", " Milliarden", ... ," Trilliarden" ]
nulleins : array [1..8] of String := [ "s", "stausend ", "s Millionen", "s Milliarden", ... ,"s Trilliarden" ]
Damit kann man das allererste Programmstück wie folgt fortsetzen (in i steht immer noch der Index der höchstwertigen Dreiergruppe):
Danach enthält text wunschgemäß den Zahltext, wie man ihn im Deutschen spricht! Wer mag, kann probieren, das Programm z.B. an französische oder spanische Zahldarstellungen anzupassen.
- zusätzliche Informationsseite des Autors (dort ist der komplette Programmcode zu finden)
- Zahlennamen bei Wikipedia