11
Feb

Römische Zahlen

categories PHP    

In einem Internet-Wettbewerb bin ich über die Herausforderung gestolpert, in möglichst wenig Code eine saubere Funktion zur Umrechnung von römischen Zahlen ins mittlerweile doch schon etwas länger übliche Dezimalsystem zu schreiben. Da eine meiner größten Schwächen ist, solche Herausforderungen fast blind anzunehmen, konnte ich natürlich nicht widerstehen.

Zwei Stunden später war folgende PHP-Funktion fertig:

<?php 
function roman_to_decimal($roman) {
  // definie the roman values
   $a=array(0=>array("I"=>1, "V"=>5, "X"=>10, "L"=>50, "C"=>100, "D"=>500, "M"=>1000));  
  // clean up the given statement - you'll never know...!
  $roman = trim(strtoupper($roman));
  // make an array out of the given statement	
  $x=str_split($roman);
  $l=strlen($roman)-1;
  // convert letters to numbers	
  for($y=0;$y<=$l;++$y) { $x[$y]=$a[0][$x[$y]]; }
  // do the math work...
  for($y=0;$y<=$l;++$y) {
    if($x[$y]<$x[$y+1]) { $x[$y]*=-1; }
    $r+=$x[$y];	
  }
  // return calculated value 
  $decimal = "nullum";
  if ($r>0) { $decimal = $r; }
  return $decimal;  
}
// -------------------------------------------------
// how to use it...
// -------------------------------------------------
$r = "MCXXX";
echo "Roman: ".$r." --- Decimal: ".roman_to_decimal($r);  ?> 

Zusammengeschrumpft hat die Funktion dann ca. 250 Bytes – ich persönlich fand das nicht schlecht. Andere Funktionen waren jedoch lediglich nur halb so groß! Wie soll das bloß gehen? Naja, zumindest funktioniert meine Funktion einwandfrei… ist ja auch etwas wert!

Kommentare

Comments (13) - “Römische Zahlen”

  1. Lerntipps am 12.02.2008 um %H:%M Uhr 

    Grosses Lob von meiner Seite, dein Blog gefaellt mir sehr gut
    Hoffentlich folgen noch weitere Beitraege, ich bin auf jedenfall gespannt
    Viele Gruesse, Simon

  2. LILLI am 08.06.2008 um %H:%M Uhr 

    hi ich lobe dich

  3. Arno Nym am 14.10.2009 um %H:%M Uhr 

    Hm, waere jetzt noch interessant die anderen Ergebnisse zu sehen – gibts die Contestdaten auf irgendner Website zu bestaunen?

  4. Björn am 15.10.2009 um %H:%M Uhr 

    Die Herausforderung kam damals von codegolf.com, einer Seite, die mehr oder weniger regelmäßig solchen Programmierthemen widmet.

  5. Bambuu am 16.06.2010 um %H:%M Uhr 

    Könnten sie vllt. eine vollständige erklärrung für jeden schritt einfügen, da ich nicht ganz verstehe was sie dort gemacht haben.

  6. Björn am 16.06.2010 um %H:%M Uhr 

    Hallo Bambuu,

    naja, Sinn der Übung war damals (und das ist schon zwei Jahre her), einen möglichst komprimierten Code zu haben. Prinzipiell hat der Codeblock fünf Bestandteile:
    1) Definition der Römischen Zeichen,
    2) Vorbereiten des Input und Wandeln in ein Array,
    3) Wandeln der Zeichen in die korrespondierenden Zahlen,
    4) Wert berechnen,
    5) Rückgabe.

    Wo genau verstecken sich Ihre Verständnisfragen?

    Grüße,
    Björn

  7. Bambuu am 17.06.2010 um %H:%M Uhr 

    Ja , das habe ich soweit verstanden.
    Was ich nicht ganz verstehe ist der mathetische teil.

    // do the math work…
    for($y=0;$y<=$l;++$y)
    {
    if($x[$y]<$x[$y+1]) <<- Warum +1?
    {
    $x[$y]*=-1; <<-Warum *=1? Was heißt das?
    }
    $r+=$x[$y];
    }

    Und

    $l=strlen($roman)-1; <<- warum -1?

    Tut mir leid, wenn die fragen etwas doof sind, aber ich bin nueling in den thema php und meine kenntnisse sind sehr begrenzt.

  8. Björn am 17.06.2010 um %H:%M Uhr 

    if($x[$y]<$x[$y+1]) <<- Warum +1?
    {
    $x[$y]*=-1;
    <<-Warum *=1? Was heißt das?

    Der Dezimalwert von römische Zahlen ist abhängig von der Positionierung. Um nun festzustellen, wie ich mit der Zahl zu rechnen habe, muss ich diese also mit dem Wert der nächsten Zahl vergleichen. Beispiel XI und IX. Bei XI rechne ich 10 + 1 (=11). Wenn aber nun 1 vor der 10 steht (IX) dann muss ich den Wert der vorangegangenen Ziffer abziehen. Die if-Klausel prüft, ob der vorangestellte Wert kleiner ist, das *=-1 dreht das Vorzeichen in diesem Fall, sodass in das Ergebnis $r nur noch den Wert addiert werden muss.

    $l=strlen($roman)-1; <<- warum -1?

    Die Länge der Zeichenfolge benötige ich für den Berechnungsloop (die for-Schleifen). Wenn ich -1 weglassen würde, dann müsste ich die for-Kommandos auf for($y=0;$y<$l;++$y) verändern. Warum ich das damals so gemacht habe, weiß ich nicht mehr so genau, aber es sollte beides gehen – und es gibt sicherlich noch bessere Methoden, die Länge zu ermitteln.

  9. Bambuu am 17.06.2010 um %H:%M Uhr 

    Jetzt habe ich alles verstanden.
    Danke für die schnelle antwort 🙂

  10. DomiX am 10.11.2010 um %H:%M Uhr 

    $a=array(0=>array(„I“=>1, …
    Wozu ist in diesem array noch ein array?
    Dadurch hast du in der for Schleife
    $a[0][$x[$y]]

    Ein array wie „$a=array(„I“=>1…“ würde ausreichen und in der for-Schleife dann ‚$a[$x[$y]]‘ verwenden ist viel kürzer.

    $r sollte auch vor der Schleife deklariert werden
    und in der Zeile
    if($x[$y]<$x[$y+1]) { $x[$y]*=-1; }
    wird beim letzten Element im array $x mit $x[$y+1] auf ein nicht existierendes Index zugegriffen. Sollte vorher auf Existenz geprüft werden.
    Mit return $r ? $r : $decimal; sparst du dir wieder die if Abfrage davor.

  11. Björn am 10.11.2010 um %H:%M Uhr 

    Hehe, mein Code ist drei Jahre alt, ist innerhalb von etwa 60min an einem viel zu frühen Samstag Vormittag entstanden. Vielen Dank für die guten Ergänzungen!

  12. Joscha am 30.11.2013 um %H:%M Uhr 

    Nach wieder einigen Jahren.. ein ganz anderer Ansatz und ganz ohne Mathe:
    function r($r){
    $a=array(„IV“,“IX“,“XL“,“XC“,“CD“,“CM“,“I“,“V“, „X“, „L“,“C“,“D“,“M“);
    $b=array(„4+“,“9+“,“40+“,“90+“,“400+“,“900+“,“1+“,“5+“,“10+“,“50+“,“100+“,“500+“,“1000+“);
    $b=str_ireplace($a,$b,$r).“0″;
    return eval(„return $b;“);}

    Viele Grüße,
    Joscha

  13. Björn am 02.12.2013 um %H:%M Uhr 

    Ohne Mathe stimmt nicht ganz! Aber trotzdem eine prima Lösung!

Leave a comment!