This program gives you practice with integer arithmetic, string building, branching, and looping.
Make a program that translates Arabic numbers into Roman numerals.
SPECIAL NOTE
Don't display your Roman numeral conversion directly on the screen.
Instead, store the Roman version of the user's number into a string variable. Then, after the conversion is
complete, display the string to the
screen.
Hint: Start by converting a one-digit number (between 1 and 9). Since each digit follows the same basic pattern, it should then just be a matter of extracting the correct digit and following the same conversion pattern.
As an example, you might have the program interaction look something like (the parts in this color are typed by the user):
$ ./roman.out Welcome to the Roman Numeral Program!!! Will you be converting numbers to Roman form with us today? yes Excellent! Glad to have you along! Enter your number: 4330 Oh, I'm sorry, that value is too large for Roman civilization. Please try again with a number [strictly] less than 4000, thank you... Enter your number: 0 Oh, I'm sorry, that value is too small for Roman civilization. Please try again with a number [strictly] greater than 0, thank you... Enter your number: 1330 Ah, I believe that would be MCCCXXX, right? Would you like to convert another number? y Enter your number: 132 Hmm...I think that is CXXXII, right? Would you like to convert another number? nah... Thank you for using the RNP!! Endeavor to have a plebeian day! $
Did you notice how the response text changed for each valid entry? Pretty spiffy, eh?
Is there a simple repeating pattern here that might help you extract commonality and save coding time?
V X XC XCV C I VI XI ... XCI XCVI ... II VII XII ... XCII XCVII ... III VIII XIII ... XCIII XCVIII ... IV IX XIV ... XCIV XCIX ...
And similarly:
L D X LX ... C DC ... M XX LXX ... CC DCC ... MM XXX LXXX ... CCC DCCC ... MMM XL XC ... CD CM ...
(Hint: complete this chart yourself and it might clarify the pattern.)
How does modulo fit into this scheme? (Hint: Look, for instance, at 2 and 7... or 1 and 6... or 3 and 8...)
Why will your program only work for values in the (integral) range [1..3999]? (Hint: What's the Roman numeral representation of 5000? How did Romans represent zero?)
For the conversion of each digit to Roman form (except maybe the thousands digit), you should have four branches. How many are cascaded from one another?
How many of these branches are nested aside from cascading?
(For you worriers: it can certainly be done with more branches, but it can be done with just four branches.)
What is the purpose of each of the three loops in your program? (Okay, so you actually should have six loops, but four of them are pretty much doing the same thing, now aren't they?)
How many tests would be required to completely test this program? (Shockingly, it is far less than 3999!)
Why does Jason want us to convert numbers from a dead civilization, anyway? (I.E. What are Roman numerals typically used for in our society?)
How can your program allow the user to type both y and yes for their again response? (Hint: This does NOT involve strings!!!)
How can your program allow the user to type both y and Y for their again response? (Hint: There are two ways, but one is far easier. You know, since it's mostly done for you in that library fun... Whoa! I almost let that one slip, eh? *chuckle*)
How can you have your program print different response text before (and after?) the Roman numeral result? (Hint: Think of it as a randomly chosen message...or a pair of randomly selected leaders and trailers...)
You might find the following resources handy, as well:
Lee's Roman Numerals at the Classics Technology Center
(although the applet seems broken, the information pages are still in tact..)
(For those of you paying attention: NO, you do NOT have to represent any of the 'barred' forms, alternative forms, or fractions...but see the options if you are desperate for such...*smile*)
This assignment is (Level 3).
Add (Level 3) to use functions to break your program into more manageable pieces. I'd recommend the bounds checking code for the user's number and the display of the result. In fact, that results display itself could be broken down into a couple of functions: random pre-message and random post-message (with the result itself printed between these calls).
You can add another (Level 1.5) to place the repetitious pattern of converting [each digit of] the user's number into A re-usable function.
Add (Level 1) to add failure checking to the numeric entry code. (Yes, this would go into the function if you do that option. But, you can add another (Level 1) if you make it a separate function that works well together with the bounds checking function...)
Add (Level 2) to use a switch to good effect in your [digit] conversion code. (This option is unaffected by that code being placed in a function. i.e. you still get this level as well as that one...)
(Note: the switch variant still has four 'branches', but it may need more than one case per branch. Some programmers call each case a branch even when several match to the same statement(s). *shrug* I'd probably go with 'the number of branches in a switch is the number of statement groups -- each possibly matchable by several cases'.)
Oh, why not? Go ahead and add (Level 2.5) to translate fractions. (See the resources above!)
For example:
Enter your number: 18 1/4 Ahh...that's gotta be 'XVIII...', right? Would you like to convert another number? yup Enter your number: 18 1/5 Oh, I'm sorry, Roman civilization did not respect the concept of '1/5'. I'll have to insist that you stick strictly to versions of '1/12'... ...if you don't mind. Enter your number: 81 1/12 Could it be 'LXXXI.'? Would you like to convert another number? yup Enter your number: 777 Hmm...I think that is DCCLXXVII, right? Would you like to convert another number? yup Enter your number: 777 7/12 Ahh...that's gotta be 'DCCLXXVIIS.', right?
Note the error checking since we only have fractional symbols for twelfths. (And, yet, the 1/4 came in okay...*hmm*)
Also note that we don't read in decimal places but actual fraction notation: n/d. And only when they put one in..! (That is, the fraction part is optional...)
You don't have to put the extra single quotes around the number when there are fractional bits, though. I just thought it helped separate the periods that were part of the Roman form from any punctuation that was in my response text. *shrug*
You can add an extra (Level 1) to make the input of a fraction its own separate function and call it from where you input their original number.
Look at that pattern, though:
S . S. .. S.. ... S... .... S.... ..... S.....
Maybe we could reuse some of our earlier code to help here? Or maybe even a function we wrote? I'll add another (Level 1) to make such clear and clever reuse!
Add (Level 3) to translate either to...*drumroll* or from Roman numerals!
You'll have to detect whether the user is entering a normal or Roman numeral before you begin to read since a normal numeral is going to be an integer type but a Roman numeral will need to be read into a string-type variable.
(Hint: You've noticed by now that each digit is a separate translation effort that differs only in the characters being used. Consider, then, that you can detect the end of a Roman 'digit' (okay, digit-group) by the fact that each one has a unique group of characters. (Don't let the 'overlap' of the '10s' character into the next digit-group's '1s' character confuse you. Remember that the '10s' character is only used in a digit-group for one of the nine possibilities.) So consider using something like ...oh, say... .find_first_not_of() to locate the end of each digit-group..?)
If you've done the function options above, you can get another (Level 1) for either:
(If you do b, this explanation can be placed with your TPQ answers. *smile*)
Add (Level 1) to place any Roman numeral translation functions you've written into a nice little library to make them easier to re-use later.
If you did all above options, this lab could be worth as much as (Level 21).