New Roman Numeral Converter

Write a program to read in New Roman numerals and print out their values(base 10 number). Old Roman numerals do not have a smaller value in front of a larger one but New Roman Numerals can have smaller value numeral in front of a larger one.

Example input: III Results: III = 3
IV IV = 4
XVIII XVIII = 18
MCCXLIV MCCXLIV = 1244

I is 1, V is 5, X is 10, L is 50, C is 100, D is 500, M is 1000.

Write the program that inputs the Roman Numeral from the keyboard. Use the following to test your code.

Test Data: LXXXII
LCLIXX
CCLIVI
MMMCMX
CMCDXX
LXXIX4V
MDCLXV

I haven't a clue on how to begin this. I have looked at examples of this within this forum, but it doesn't help me any. I can only use IF, IF ELSE, SWITCH. No loops like WHILE or FOR. I have barely any code written for this, as I am not certain how to approach this.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    ofstream rom;
    rom.open("RomanNumerals.out");

    rom << "test";

    int number = 0;

    string rom_num = "LXXXII";

    switch(number)
    {
        case 'I':
            number += 1;
            break;

        case 'V':
            number += 5;
            break;

        case 'X':
            number += 10;
            break;

        case 'L':
            number += 50;
            break;

        case 'C':
            number += 100;
            break;

        case 'D':
            number += 500;
            break;

        case 'M':
            number += 1000;
            break;

        default:
            cout << "You didn't enter a valid Roman Numeral.";
            break;


        rom << "The value of the Roman Numeral " << rom_num
            << " is " << number;

    }


    return 0;
}
Last edited on
@CodeNovice01

Old Roman numerals do not have a smaller value in front of a larger one


Actually, Roman numerals DO allow smaller numbers in front of a larger one. That's when you know to subtract the smaller number from the larger, as in the IV you show. 1 is subtracted from 5, giving you the 4.

I'm not quite sure what the rules are in your New Roman Numerals.
(One of your test data statements is) LCLIXX = ?

50 + 100 + 50 + 1 + 20?
Or is the first 50 subtracted from 100 (C) giving 50, then added to L, another 50, giving 100, then added to 9, (IX), or is it added to 1, then added to 20 (XX)

If I knew a bit more on the counting I may be able to help, but as it stands right now, there is no rhyme or reason, to the program. Give me a little more to go on, please.
I suspect the difference between “old” and “new” Roman numerals is in the old and new programs to implement Roman numerals. Perhaps OP was demonstrated an “old” algorithm that could not handle subtractive Roman numerals.

The numeral LCLIXX is mal-formed, but not invalid.
It is L C L IX X = 50 + 100 + 50 + 9 + 10 = 219.

The correct way to write that today is CCXIX, but CCIXX is also acceptable.

Today only I, X, and C are used subtractively (subtract tenths, not halves), but you can certainly write an algorithm that takes VL as 45, and that would be reasonable. (We would normally write 45 as XLV today.) The problem is that it would make LCLIXX equal to LC L IX X, or 50 + 50 + 9 + 10 = 119.

You should ask your professor about this discrepancy. Should LCLIXX produce 219 or 119? Or worded differently, should V, L, and D be subtractive?


Another note: your program should take input “from the keyboard” (meaning, from standard input == std::cin) and “print out their values” (meaning, to standard output == std::cout).

This is easy enough:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <string>

int roman_to_integer( const std::string& s )
{
  ...
}

int main()
{
  std::string s;
  while (getline( std::cin, s ))
    std::cout << roman_to_integer( s ) << "\n";
}

That’s it! The function should do the conversion from the Roman numeral string to int.

Hope this helps.
@whitenite1, I provided the full text of the assignment. He altered it last minute since we aren't able to use loops yet. There is a reason for this program, its to get a grade. I'm not a confident coder, I thought it was easy just using cin and cout, now I just don't know what to do. I may need to rethink my degree.


I have no clue where to go from here, as for calculations of the roman numerals. I'm stuck.

as for the example of LCLIXX: Anything smaller of value will be subtracted if it isn't at the end of the numeral. SO IX would become 9. With that same logic, I assume the CL would become 50. You'd have something similar to 50 + (100 - 50) + (1 - 10) + 10? Professor stated anything smaller in front of a larger should be reduced.

I wish I could provide more insight, but I don't have it. I have no idea where to go from here and I'm losing my motivation for this class.
Ah, so 119 it is.

Aaaannd, looking at your test data, I realize that all inputs are 6 characters long. (You have an accidental '4' typed in the penultimate test case.)

That helps quite a lot, because you no longer need loops. You need:
  • six character reads (you can use getline() to simply get a string)
  • a running total (which you named 'number')
  • a lookup table to convert things like 'V' to 5 (use a function)

Your Roman digit → value function should just be a case statement, returning a value.

4
5
6
7
8
9
10
11
int to_int( char roman_digit )
{
  switch (roman_digit)
  {
    case 'I': return 1;
    ...
  }
}


Now for the algorithm. Remember the key difference here: for each value, if it is smaller than the next value (if any) then we subtract. Otherwise we add. So:

  VI   is   5 + 1     (the 5 is added because it is NOT smaller than the next value)

and:

  XX   is   10 + 10     (the first 10 is added because it is NOT smaller than the next)

but:

  IV   is   -1 + 5     (the 1 is subtracted because it IS smaller than the next value)

Now you just need six statements to choose how to add or subtract to your running total. Five of those will be an if statement. (The last value will always be added, right?)

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
int main()
{
  // Get the input 6-digit Roman numeral (which we assume is correct -- no error checking)
  std::string roman_numeral;
  getline( std::cin, roman_numeral );

  // Here is our running total
  int number = 0;

  // Now, for each digit:
  //  • subtract it if it is < the next digit
  //  • add it otherwise
  if (to_int(roman_numeral[0]) < to_int(roman_numeral[1])) number -= to_int(roman_numeral[0]); else number += to_int(roman_numeral[0]);
  ... /* and so on */

  // Print the total
  std::cout << number << std::endl;
}

Hope this helps.
So I would need to include an IF ELSE for each of the values of Roman Numerals??
I don't understand the if (to_int(roman_numeral[0]) < to_int(roman_numeral[1])) number -= to_int(roman_numeral[0]); else number += to_int(roman_numeral[0]);

How does this know which position of the 6 numerals to read? or is this why you mentioned the need for 5 IF statments?

Also, I can't use multiple functions. It has to be longhand. Just mentioning this, as it appears to me, that you have a separate function for roman_digit. Then, are you using an array within the if statement? Assumed the use of [] meant array.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
 
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
    ofstream rom;
    rom.open("RomanNumerals.out");

    rom << "test";
    string roman_numeral;

    int number = 0;
    int to_int(char roman_digit);

    cout<< "enter a value";
    cin >> roman_numeral;

    switch(number)
    {
        case 'I':
            return 1;
            break;

        case 'V':
            return 5;
            break;

        case 'X':
            return 10;
            break;

        case 'L':
            return 50;
            break;

        case 'C':
            return 100;
            break;

        case 'D':
            return 500;
            break;

        case 'M':
            return 1000;
            break;

        default:
            cout << "You didn't enter a valid Roman Numeral.";
            break;
    }
        getline(cin, roman_numeral);

        if (to_int(roman_numeral[0]) < to_int(roman_numeral[1]))
            number -= to_int(roman_numeral[0]);
        else
            number += to_int(roman_numeral[0]);

        rom << "The value of the Roman Numeral " << roman_numeral
            << " is " << number;

    return 0;
}


I gave it a shot, I knew I'd screw it up somehow. Now the program won't run. I've gotten things crossed and confused to the point i'm unsure where to begin debugging. I appreciate your help. It does complement my ignorance but I believe I may be too far lost. Ha
I believe I may be too far lost.

No, you're quite close.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <string>

constexpr int not_roman_digit = 0;

int roman_digit_value(char rn)
{
  switch (rn)
  {
    case 'I': return 1;
    case 'V': return 5;
    case 'X': return 10;
    case 'L': return 50;
    case 'C': return 100;
    case 'M': return 1000;
    default : return not_roman_digit;
  }
}

int main()
{
  std::string line; 
  std::getline(std::cin, line);
   
  // store the value of each digit in the six-digit roman number
  // into its own variable.
  // For example, given the input LCLIXX:
  //   v0 has the value of L, 50;
  //   v1 has the value of C, 100;
  //   v2 has the value of the second L, 50;
  //   v3 has the value of I, 1;
  //   v4 has the value of X, 10; and
  //   v5 has the value of the last X, 10.
  int const v0 = roman_digit_value(line[0]);
  int const v1 = roman_digit_value(line[1]);
  int const v2 = roman_digit_value(line[2]);
  int const v3 = roman_digit_value(line[3]);
  int const v4 = roman_digit_value(line[4]);
  int const v5 = roman_digit_value(line[5]);

  // Declare an integer to keep a running total of the roman number's
  // value.
  int result = 0;
  
  // If the first digit is worth less than the second digit
  // subtract the first value from the running total,
  // otherwise, add it to the running total.
  if (v0 < v1) result -= v0; 
  else         result += v0;
    
  // Repeat the process above for the second and third digit
  if (v1 < v2) result -= v1;
  else         result += v1;
  
  // Repeat the process above for the third and fourth digit
  if (v2 < v3) result -= v2;
  else         result += v2;
  
  // Repeat the process above for the fourth and fifth digit
  if (v3 < v4) result -= v3;
  else         result += v3;
  
  // Repeat the process above for the fifth and sixth digit
  if (v4 < v5) result -= v4;
  else         result += v4;
  
  // Unconditionally add the value of the sixth and last digit
  // Display the final running total
  result += v5;

  std::cout << result << '\n';
}
Last edited on
How does your line 6 work? Can you explain that a little for me please? As well as, lines 22 and 23? Thank you very much!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

const int not_roman_digit = 0;

int roman_digit_value(char rn)
    {
            switch(rn)
        {
            case 'I': return 1;
            case 'V': return 5;
            case 'X': return 10;
            case 'L': return 50;
            case 'C': return 100;
            case 'D': return 500;
            case 'M': return 1000;
            default: return not_roman_digit;
        }
    }
int main()
{
    ofstream rom;
    rom.open("RomanNumerals.out");

    string line;
    int const v0 = roman_digit_value(line[0]);
    int const v1 = roman_digit_value(line[1]);
    int const v2 = roman_digit_value(line[2]);
    int const v3 = roman_digit_value(line[3]);
    int const v4 = roman_digit_value(line[4]);
    int const v5 = roman_digit_value(line[5]);
    int number = 0;


    if (v0 < v1)
        number -= v0;
    else
        number += v0;
    if (v1 < v2)
        number -= v1;
    else
        number += v1;
    if (v2 < v3)
        number -= v2;
    else
        number += v2;
    if (v3 < v4)
        number -= v3;
    else
        number += v3;
    if (v4 < v5)
        number -= v4;
    else
        number += v4;

    number += v5;


        rom << "The value of the Roman Numeral " << roman_digit_value
            << " is " << number;

    return 0;
}


This is what I have come up with thanks to your input. But I am having a learning curve issue when it comes to using cin and outfile. How do I read in the values that I want to calculate without cin and make them appear on my outfile?
Unless your professor has specifically instructed you to use files, stop doing that. Use cin and cout.

The instructions you posted in your OP specifically state that input is to be cin. And a typical, unqualified print is typically expected to be to the console.

Hope this helps.
How do I read in the values that I want to calculate without cin

^^ That is not a good question. Do you want to read it from a file? Or from the user, but not using cin for some reason, or something else? GUI tools have libraries and tools to read from gui objects, but c++ in the raw does not have this.

make them appear on my outfile?
This is better.
you open a file:
ofstream ofs(filename); //filename may be a string that has the path/filename
string value = "hello world";
ofs << value << endl; //write things to a file as text. it works exactly like cout.

which is exactly like what you have. So your file opened via 'rom' should have the output in it. Does it not? Open it with notepad or something... ?
Last edited on
Write the program that inputs the Roman Numeral from the keyboard.

"Inputs from the keyboard." That means using std::cin or some variation of std::getline. Reading from a file is not getting input from the keyboard.

Without some form of a loop that means your program as it currently is written can only realistically process one input. Your test data is more than one Roman numeral, so you have to run your program multiple times.

Without reading the data from a file or using std::getline/std::cin, hard-code the Roman numerals into a std::string array:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <string>

constexpr int not_roman_digit = 0;

int roman_digit_value(char);
int convert_roman_to_arabic(std::string&);

int main()
{
   std::string roman_numbers[] = { "LXXXII", "LCLIXX", "CCLIVI", "MMMCMX",
                                   "CMCDXX", "LXXIXV", "MDCLXV" };

   int arabic_number = convert_roman_to_arabic(roman_numbers[0]);
   std::cout << roman_numbers[0] << " = " << arabic_number << "\n\n";

   arabic_number = convert_roman_to_arabic(roman_numbers[1]);
   std::cout << roman_numbers[1] << " = " << arabic_number << "\n\n";

   arabic_number = convert_roman_to_arabic(roman_numbers[2]);
   std::cout << roman_numbers[2] << " = " << arabic_number << "\n\n";

   arabic_number = convert_roman_to_arabic(roman_numbers[3]);
   std::cout << roman_numbers[3] << " = " << arabic_number << "\n\n";

   arabic_number = convert_roman_to_arabic(roman_numbers[4]);
   std::cout << roman_numbers[4] << " = " << arabic_number << "\n\n";

   arabic_number = convert_roman_to_arabic(roman_numbers[5]);
   std::cout << roman_numbers[5] << " = " << arabic_number << "\n\n";

   arabic_number = convert_roman_to_arabic(roman_numbers[6]);
   std::cout << roman_numbers[6] << " = " << arabic_number << '\n';
}


int roman_digit_value(char rn)
{
   switch (rn)
   {
   case 'I': return 1;
   case 'V': return 5;
   case 'X': return 10;
   case 'L': return 50;
   case 'C': return 100;
   case 'M': return 1000;
   default: return not_roman_digit;
   }
}

int convert_roman_to_arabic(std::string& str)
{
   int const v0 = roman_digit_value(str[0]);
   int const v1 = roman_digit_value(str[1]);
   int const v2 = roman_digit_value(str[2]);
   int const v3 = roman_digit_value(str[3]);
   int const v4 = roman_digit_value(str[4]);
   int const v5 = roman_digit_value(str[5]);

   int result = 0;

   if (v0 < v1) result -= v0;
   else         result += v0;

   if (v1 < v2) result -= v1;
   else         result += v1;

   if (v2 < v3) result -= v2;
   else         result += v2;

   if (v3 < v4) result -= v3;
   else         result += v3;

   if (v4 < v5) result -= v4;
   else         result += v4;

   result += v5;

   return result;
}

LXXXII = 82

LCLIXX = 119

CCLIVI = 255

MMMCMX = 3910

CMCDXX = 1020

LXXIXV = 84

MDCLXV = 1165

Using a loop is less error-prone to typing mistakes:
1
2
3
4
5
6
7
8
9
10
11
int main()
{
   std::string roman_numbers[] = { "LXXXII", "LCLIXX", "CCLIVI", "MMMCMX",
                                   "CMCDXX", "LXXIXV", "MDCLXV" };

   for (size_t loop { }; loop < std::size(roman_numbers); loop++)
   {
      int arabic_number = convert_roman_to_arabic(roman_numbers[loop]);
      std::cout << roman_numbers[loop] << " = " << arabic_number << '\n';
   }
}

LXXXII = 82
LCLIXX = 119
CCLIVI = 255
MMMCMX = 3910
CMCDXX = 1020
LXXIXV = 84
MDCLXV = 1165
@Jonin, the professor has asked us to write our programs to a file(output). I wasn't sure how to declare and or create a way to input my test data so it would read from the program into the "rom" file. Thank you for the example as it did help. I don't have time at the moment to debug further as I am about to walk into Discrete Math class.

@FUrry Guy, on your line 4, my compiler will not read that. It says "note: C++11 'constexpr' only available with -std=c++11 or -std=gnu++11|"
Then change constexpr to const.

Or delete the entire global definition and change the switch default to 0.

The global variable wasn't MY line, I copied the bulk of the code from mbozzi.

the professor has asked us to write our programs to a file(output).

Easy to do.

1. Include the <fstream> header.

2. declare a file stream object. For example: std::ofstream ofs("test.txt", std::ofstream::out);

3. Change all uses of std::cout to your file stream object.

main() should now look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int main()
{
   std::string roman_numbers[] = { "LXXXII", "LCLIXX", "CCLIVI", "MMMCMX",
                                   "CMCDXX", "LXXIXV", "MDCLXV" };

   std::ofstream ofs("test.txt", std::ofstream::out);

   int arabic_number = convert_roman_to_arabic(roman_numbers[0]);
   ofs << roman_numbers[0] << " = " << arabic_number << '\n';

   arabic_number = convert_roman_to_arabic(roman_numbers[1]);
   ofs << roman_numbers[1] << " = " << arabic_number << '\n';

   arabic_number = convert_roman_to_arabic(roman_numbers[2]);
   ofs << roman_numbers[2] << " = " << arabic_number << '\n';

   arabic_number = convert_roman_to_arabic(roman_numbers[3]);
   ofs << roman_numbers[3] << " = " << arabic_number << '\n';

   arabic_number = convert_roman_to_arabic(roman_numbers[4]);
   ofs << roman_numbers[4] << " = " << arabic_number << '\n';

   arabic_number = convert_roman_to_arabic(roman_numbers[5]);
   ofs << roman_numbers[5] << " = " << arabic_number << '\n';

   arabic_number = convert_roman_to_arabic(roman_numbers[6]);
   ofs << roman_numbers[6] << " = " << arabic_number << '\n';
}

Compile, run and you're done. There will be no console output, all output is now in a text file.

http://www.cplusplus.com/reference/fstream/ofstream/

I have to ask, exactly what compiler are you using that C++11 causes it to have problems?
Furry Guy,

Thank you for the detailed explanation. Truly!! I am using Code Blocks 17.12
Furry Guy,

What is the statement on line 3 and 4? Is that an array of sorts?
C::B 17.12 should be more than capable of compiling C++11 code, if you installed the version with that includes MinGW. You will probably have to change a setting to do so.

https://stackoverflow.com/questions/18174988/how-can-i-add-c11-support-to-codeblocks-compiler

I use C::B but not a lot and don't usually change any settings.

At least you don't use the really ancient Turbo C compiler. People using that really have problems with modern C++ code.

I am so used to C++11 ways of doing things that it takes me more than a bit of skull sweat to fall back to an earlier standard.

I use Visual Studio 2019 (free in the Community edition) for the most part, and that defaults to C++14, so C++11 code works without a burp.

If I require C++17 or later, a quick project setting change and away we go.

I use VS2019 in part so I can easily create both x86 and x64 executable apps from the same code. C::B it is possible but it requires making some fairly extensive changes to the IDE settings. At least major for me that I'd rather not do.

Creating Windows GUI apps in both x86 and x64 versions without a lot of work is a huge selling point to me for using VS2019.

Enough of this off-topic babbling.....

Your professor sure has some weird restrictions in place. Multiple inputs but can't use any reasonable form of a loop to get the data.

One IMO UN-reasonable way could be with goto "loops," but I really don't believe you should go there. goto may still be an available part of the language, but it is hackish at best.

https://en.cppreference.com/w/cpp/language/goto
What is the statement on line 3 and 4? Is that an array of sorts?

It is an array of std::strings. A 7 element array. The number of elements determined by the number of strings in the initializer list.

https://www.geeksforgeeks.org/array-strings-c-3-different-ways-create/

Under normal circumstances I would use std:vector over an old C style array. Maybe even the new fangled C++11 std::array.

https://en.cppreference.com/w/cpp/container/array

One thing I will personally never use is using namespace std;

https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice

https://www.geeksforgeeks.org/using-namespace-std-considered-bad-practice/

Now I don't even have to think about typing "std::" when using the standard C++ library/STL, my fingers do it automatically.
Topic archived. No new replies allowed.