ROMAN NUMERAL CONVERSION ROUTINES FOR THE HP48 15Mar92 The following two routines translate between integers and roman numerals. The Roman system uses 7 letters to represent different weightings: M 1000 D 500 C 100 L 50 X 10 V 5 I 1 These are assembled additively into a string, largest numbers being left justified: e.g. "MCL" is 1150 In addition any character may be preceeded by one of the following: C 100 X 10 I 1 and this is subtracted from the character. So 9 is "IX" and NOT "VIIII" However "IM" is not allowed for 999. The preceeding character must be the next least significant of the ones listed above, e.g. "CMXCIX" for 999. Only one preceeding character is allowed at a time, 8 is NOT "IIX" it should be represented by "VIII". Finally a whole expression can be multiplied by 1000 if a bar covers it. This aspect is not reproduced in the following programs. ->RN: Takes a number from the stack and returns a string containing the roman numeral. The result is "tagged" with the original number from the stack. If the stack is empty then a message indicating the correct syntax for the routine is returned. If the number has a fractional part then the fraction is ignored. If the number is greater than 10000 then only the part of the number <10000 is processed, the resulting string is preceeded with a "+" to indicate this. This prevents the creation of very long roman numerals with dozens of preceeding "M"'s, that take ages to process. RN->: Takes a string from the stack and returns the equivalent integer. The result is "tagged" with the original string from the stack. If the stack is empty then a message indicating the correct syntax for the routine is returned. If the string contains characters other than "MDCLXVI" then the program fails. The routine will translate all legal roman numerals, it will also translate some non legal ones: e.g. "VX" (5) "MIM" (1999), however it will not translate "IIV" correctly. HP48 ASCII CODE for \->RN..................................................... %%HP: T(3)A(D)F(.); \<< DEPTH IF THEN IP "MDCLXVI" "CCXXII " { 1000 500 @ Create four lists that 100 50 10 5 1 } { 100 100 10 10 1 1 0 } @ define the translation \-> r rs w ws \<< DUP DUP 10000 > IF THEN 10000 MOD "+" @ If greater than 10000 then ELSE "" @ truncate input and add "+" END 1 r SIZE FOR i @ For each character in the r i i SUB rs i i SUB w i GET ws i GET@ translation get the weighting \-> r1 r2 w1 w2 @ from the list \<< WHILE OVER w1 \>= REPEAT SWAP w1 - SWAP r1 + @ subtract weighting as END @ many times as possible. IF OVER w2 + w1 \>= @ Check if one more can be THEN SWAP w1 - w2 + SWAP r2 + r1 + @ subtracted with preceeding END @ character. \>> NEXT \>> SWAP DROP SWAP \->TAG @ Tag output with input integer ELSE "INT \-> Roman Numeral $" @ Print this string as help DOERR END \>> HP48 ASCII CODE for RN\->..................................................... %%HP: T(3)A(D)F(.); \<< DEPTH IF THEN EVAL DUP SIZE "IVXLCDM" { 1 5 10 @ Create two lists for 50 100 500 1000 } \-> s l r w @ the translation \<< { } 1 l FOR i @ for each character in the input s i i SUB r SWAP POS w SWAP GET + @ build a list of the weights NEXT 0 + l \-> v l \<< 0 1 l FOR i @ For the list of weights v i GET DUP v i 1 + GET < @ subtract if followed by a IF THEN - ELSE + END @ larger number else add NEXT s \->TAG @ Tag output with input string \>> \>> ELSE "Roman Numeral $ \-> INT" @ Print this string as help DOERR END \>>