#!/usr/bin/perl -w # This program is based on Ozawa Sakuro 's program available on the # web. He wrote it in 1995. I have added extensive comments to # make it comprehendable. # Search on his name to find it with "Roman Numerals Arabic". # use strict; #Domain of valid Roman numerals is limited to less than 4000, since #proper Roman digits for the rest are not available in ASCII. # Declare Sub/Functions sub Roman; # returns a Roman Numeral String from an Arabic Number # String as input. # Declare Variables # This is the hash table for translating an arabic number to a roman # numeral string. my %arabic2roman = qw(1 IV 10 XL 100 CD 1000 MMMMMM); # Following is an array which represents the sort keys of the # hash table in reverse order, the first key is 1000. my @figure = reverse sort keys %arabic2roman;# This will be used # extensively for sub Roman; # my @figure = qw(1000 100 10 1); # is another way of getting this. # We will now change the hash table so the value part becomes # a value array. That is the string "IV", will become array # ("I", "V"). Uncomment what is below to see the original hash table. # my $key ; # my $val ; # print " Original Hash Table \n\n"; # while (($key,$val) = each %arabic2roman) { # print "key is: $key\t\t value is: ($val) \n"; # # print original hash table. # } foreach (@figure) { # split the value string into an array of # two elements. Note, the key for the hash # remains the same. The split is done after # the first byte, with the remainder being the # second element. $arabic2roman{$_} = [split(//, $arabic2roman{$_}, 2)]; } # To see what happened we can simply walk the hash table again. # by uncommenting the lines below. # # print " \n\n New Hash Table with an array for Value \n\n"; # while (($key,$val) = each %arabic2roman) { # print "key is: $key\t\t array value is: (@$val) \n"; # # notice its @$val now because it is an array! # } # This new hash table makes the algorithm, very easy for converting # an Arabic Number to a Roman Numeral. This is Ozawa Sakuro's genius # not mine! sub Roman { # Input Arabic Number, Return Roman Numeral as string. # Note we use the "x" operator here to denote repetition # when concatenating. # We loop through the @figure array which will be used to # count out the number of 1000's, 100's, 10 's and 1's # respectively. By dividing by the arabic part of the place # holder hash key (@figure[i])for each position we # know how many times to repeat the Roman Numeral. my($arg) = shift; 0 < $arg and $arg < 4000 or return undef;# leave if not # arabic number my($x, $roman); # define variables for concatenation # $x is one Roman Numeral Digit (I,X,V, etc.) # $roman is the string we will concatenate to # build the Roman Numeral String. Note, we start # off with a Roman Numeral String of MMMMM which we # then subtract from to get our thousands place # if there is any. # The original arabic number string is passed by # $arg. Note, if you uncommented the hash table # walk in the beginning for %arabic2roman, all # will be obvious here. # foreach (@figure) { # i.e. for 1000, 100, 10, 1 my($digit, $i, $v) = (int($arg / $_), @{$arabic2roman{$_}}); # Uncomment next line for debugging. # print "dollar_digit: $digit, dollar_i: $i, dollar_v: $v \n"; if (1 <= $digit and $digit <= 3) { $roman .= $i x $digit; # Repeat Numeral for "LLL", "CCC", # "MMM", "XXX", "III", etc. } elsif ($digit == 4) { $roman .= "$i$v"; # yields "CD", "XL", "IV" } elsif ($digit == 5) { $roman .= $v; # yields "D", "L", "V" } elsif (6 <= $digit and $digit <= 8) { $roman .= $v . $i x ($digit - 5); #yields "DC", "DCC", "DCCC", ... "VI", "VII", "VIII" etc. } elsif ($digit == 9) { # this is the "9 type". $roman .= "$i$x"; # yields "CM", "XC", "IX" } $arg -= $digit * $_; # subtract out what you have already # taken care of, i.e. 3 times 1000 # for the first iteration here. $x = $i; # Store for later if this is the "9 type" # Roman Numeral digit. # uncomment next line for debugging. # print "this is dollar roman after each iteration: $roman \n"; } $roman; } #Main Section my $arabic_number = "3554"; my $roman_numeral = ""; $roman_numeral = Roman($arabic_number); print "The arabic number: $arabic_number \n"; print "translates to: $roman_numeral \n"; # End Main Program Section exit;