C++ converting base 10 to Roman numerals

  1. Math Is Hard

    Math Is Hard 4,915
    Staff Emeritus
    Science Advisor
    Gold Member

    Hi,
    I just began working on a little program to convert base 10 number to Roman numerals. I couldn't figure out how to make a loop to count how many Ms, Ds, Cs etc. so I wrote it out the long way for now.
    I can see a lot a repetition and an obvious pattern in my divisors, since I am dividing by
    103 , (103)/2 , 102 , (102)/2 ,etc.
    but I can't figure out a loop that will handle this properly. Any suggestions?
    (note: I haven't written the logic for the last piece of it yet which will deal with the order of the numbers, for instance, converting VIIII to IX.)

    Thanks for any advice on handling the loop. Here's what I did:

    Code (Text):

    # include <iostream>

    using namespace std;

    //converts base 10 to romans

    int main()
    {
        int num;
        int quotient;
        int M = 0;
        int D = 0;
        int C = 0;
        int L = 0;
        int X = 0;
        int V = 0;
        int I = 0;

        cin >> num;

        quotient = num/1000;
        M = quotient;
        num = num % 1000;

        quotient = num/500;
        D = quotient;
        num = num % 500;
       
        quotient = num/100;
        C = quotient;
        num = num % 100;

        quotient = num/50;
        L = quotient;
        num = num % 50;
       
        quotient = num/10;
        X = quotient;
        num = num % 10;

        quotient = num/5;
        V = quotient;
        num = num % 5;
       
        I = num;


            for (int m = 0; m < M; m++)
                cout << "M";
            for (int d = 0; d < D; d++)
                cout << "D";
            for (int c = 0; c < C; c++)
                cout << "C";
            for (int l = 0; l < L; l++)
                cout << "L";
            for (int x = 0; x < X; x++)
                cout << "X";
            for (int v = 0; v < V; v++)
                cout << "V";
            for (int i = 0; i < I; i++)
                cout << "I";

        return 0;
    }

     
     
  2. jcsd
  3. Hurkyl

    Hurkyl 16,089
    Staff Emeritus
    Science Advisor
    Gold Member

    The trick is to make an auxilliary array of the constants you need.

    int divisor[] = { 1000, 500, 100, 50, 10, 5, 1 };
    char symbol[] = "MDCLXVI";

    I'll give you a chance to take it from here.
     
  4. Math Is Hard

    Math Is Hard 4,915
    Staff Emeritus
    Science Advisor
    Gold Member

    Hey Hurkyl, thanks for your response.

    sorry, I should have mentioned this in my first post: No arrays allowed yet.
    Technically we're not supposed to know what an array is yet.
    Think there might be another way?
     
  5. Hurkyl

    Hurkyl 16,089
    Staff Emeritus
    Science Advisor
    Gold Member

    Well... you could write a function that contains the replicated logic, and then call the function a few times with the parameters. Or, you could put them into a file, and read them from the file instead of from an array...
     
  6. Math Is Hard

    Math Is Hard 4,915
    Staff Emeritus
    Science Advisor
    Gold Member

    ok, I'll think on that. That should make things a little bit nicer (and shorter!). Thanks!
     
  7. You can't have a loop because you have the separate variables M D C L X V I. There is no good way to access the M in the first iteration, the D in the second, etc. You could use 2 arrays, one to store the number of M's, D's, C's, etc. and the other to store the letters 'M,' 'D,' 'C,' etc., and that would let you do a loop. But unless you were specifically asked to use a loop, I don't think you should.

    You can tighten the code by not initializing any of the M's, D's, etc. to 0 since they are assigned values later in the code before they are used.

    Also, you can write

    quotient = num/5;
    V = quotient;
    num = num % 5;

    as

    V = num/5;
    num %= 5;

    getting rid of the quotient variable.

    If you do need a loop, it would go something like this (currentDivide set to 1000 to begin with):
    for(i = 0; i < 7; i++)
    {
    (do something with your array of letters here)
    if(i % 2 == 0)
    currentDivide /= 2;
    else
    currentDivide /= 5;
    }
     
  8. But I think you should focus on the second part of the problem. Your program would convert 499 into CCCCLXXXXVIIII, and there is not an easy way to go from there to the correct answer, ID, so you should convert it to ID as you go rather than afterwards.

    Edit: nevermind, ID is not the standard representation for 499
     
    Last edited: Feb 2, 2005
  9. Integral

    Integral 7,349
    Staff Emeritus
    Science Advisor
    Gold Member

    Instead of dividing by 1000 do a loop that subtracts 1000, each loop add a M, check to see if you are below 1000, then start subtracting 500. etc. You will need to condsider the logic needed to get the order of the Roman Numeral symbols right.

    I did this some years ago in quick basic, Sorry lost the code... Hum... I still have a collection 5.25 floppies I might be lucky and still have it somewhere.
     
  10. No, the way she did it is more concise than that would be.
     
  11. Math Is Hard

    Math Is Hard 4,915
    Staff Emeritus
    Science Advisor
    Gold Member

    OK, thanks! I am going to play around with some of those suggestions, but if I get stuck at least I have my long-winded version to use.
     
  12. Integral

    Integral 7,349
    Staff Emeritus
    Science Advisor
    Gold Member

    Surely you jest! We are converting to Roman numerals aren't we?

    Can you tell me exactly what the difference between subtraction and division is? Does your CPU know the difference?
     
  13. Well, probably my CPU does know the difference. But I was talking more about shorter source code.
     
  14. Integral

    Integral 7,349
    Staff Emeritus
    Science Advisor
    Gold Member

    Actually your CPU does division by successive subtractions.

    I am not sure that the division algorithm is more efficient. Since you will have to do some form of a loop based on the result of the division to create the final answer. This way you do a while loop subtracting the appropriate amount and build the result as you go, you can even throw in the ordering logic. The subtraction saves machine cycles....LOL as if that is a concern for this problem. :biggrin:

    I would recommend doing it the way that easiest to code. That comes down to what works for, and makes the most sense to, the programmer.
     
  15. I'm not familiar with the specifics of my computer's innards but I'm willing to bet that it has division instructions which are more efficient than successive subtraction. Long division by hand, for example, is quicker than repeated subtraction by hand.

    Personally, I'm used to dividing and using %.
     
  16. I think this involves too many special cases to have "elegant" code. You have to deal separately with thousands, nine-hundreds, five-hundreds, four-hundreds, hundreds, nineties, fifties, forties, tens, nine, five, four and one; Integral's way is best.
     
  17. Math Is Hard

    Math Is Hard 4,915
    Staff Emeritus
    Science Advisor
    Gold Member

    I'm trying to work out the rest of the Roman numeral formatting now to put the I before the V or the I before the X. I'm stumped on that so far but I think I'm just burning out now. Maybe if I sleep on it... :zzz: .. sometimes I'll have an idea in the morning.
    I've been reading this page for help, if anyone's interested in Roman Numeral rules and trivia.
     
  18. It is interesting. And now it's even more complicated. So which system of "Roman" numerals are you supposed to convert to?
     
  19. "...now to put the I before the V or the I before the X..." or the X before the C (or L) or the C before the M (or D) and so on...

    That's why Integral suggested building the string while whittling down the decimal number. Or, if you're not up to strings yet, just print each character or pair of characters in the same loop with the subtraction. In other words, if you have nine-hundred-something, subtract nine hundred, print "CM" and then continue processing the "something".
     
  20. Integral

    Integral 7,349
    Staff Emeritus
    Science Advisor
    Gold Member

    Ya'll got me wondering aobut correct form of Roman numerals, I had a pretty good sense of how it works but was not certian. I found this page

    check out the conversion calculator (I scored X/X on the little test!)

    Also look at the 1999 question.

    according to this page ID is not the best form of 499 it would be CDXCIX
     
  21. Yeah, that's what my program does. And MCMXCIX for 1999.
     
Know someone interested in this topic? Share a link to this question via email, Google+, Twitter, or Facebook

Have something to add?