Roman Numeral converter assistance

I have to write a program to convert roman numerals into actual numbers. Like I to 1 or XI to 11. I have to read the roman numerals from a file which is also easy, but my question is how do i convert a string worth at a time.

This is what i have to read them him and it works, but after i fin rm1(roman numeral one) in a string form how would I go about converting the string.

All help or ideas would be helpful. :) Thanks

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
#include <iostream>
#include <string>
#include <fstream>
using namespace std;

void get_Data(ifstream& fin, string& rm1, string& rm2, char& op)
{
	fin >> rm1 >> rm2 >> op;
}

int convert_roman_to_number(char x)
{

}


void main()
{
	ifstream fin;
	string rm1 = "", rm2 = "";
	char op = ' ';

	fin.open("MP4.txt");

	get_Data(fin, rm1, rm2, op);
	


	system("pause");
}




Input File contents: (no enter before everything)

MCCXXVI CV +
MCCXXCI MCCXXI /
V I -
DL DXXXXVIII -
D L /
MDI CXI +
XXV IIII /
XI CII *
Last edited on
The method I would suggest is using an if/else if structure that would recursively parse the string. I will reply back with a solution soon.

Your base case is an empty string.
Here are some tips:
http://blog.functionalfun.net/2009/01/project-euler-89-converting-to-and-from.html
Need help please!
If you're going to read in the roman numerals as complete strings, you could use the .at() function to analyze each individual character.

I'd make a separate int var and add a certain amount depending on which letter it is.
I'd use a for loop. Maybe something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int d1 = 0, d2 = 0; //"d" standing for decimal

for (int = 0; i < rm1; i++)
{	
	switch (rm1.at(i))
	{
		case 'I': d1 += 1; break;
		case 'V': d1 += 5; break;
		case 'X': d1 += 10; break;
		case 'L': d1 += 50; break;
		case 'C': d1 += 100; break;
		case 'D': d1 += 500; break;	
		case 'M': d1 += 1000; break;
	}
}
//and then do the same for the second string 
This solution of course doesn't account for stuff like the roman numeral IV, but it doesn't look like there's anything like that in your input file.
New Problem........
When i run i get a
R6010 abort code.....
Looked it up and people are saying it is trying to read a file that is not there
but no one cares to say how to fix it
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <iostream>
#include <list>
#include <fstream>
using namespace std;

// stream a pair
template<typename A, typename B>
ostream & operator<<(ostream& os, const pair<A,B>& p)
{
  os << '(' << p.first << ',' << p.second << ')';
  return os;
}

// stream a list
template<typename T>
ostream & operator<<(ostream& os, const list<T>& l)
{
  for (auto it = l.cbegin(); it != l.cend(); ++it) {
    os << *it;
  }
  return os;
}

// convert a roman token to a number. return 0 if invalid
static unsigned RomanTokenToDecimal(char c)
{
  switch (c) {
  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;
  }
  return 0;
}

/*
 * convert a string of Roman symbols to an unsigned number.
 * no checks are done on correctness of input
 * IV => 4
 * IVX => 4
 * VV => 10
 */
static unsigned RomanStringToNumber(const string& str)
{
  /* step 1: convert each token to a sign and a number
   * step 2: work out if there is subtraction of the number to take place
   * step 3: then calculate the number
   *
   * eg: MCMLIX:
   * step 1:
   * M: + 1000
   * C: + 100
   * M: + 1000
   * L: + 50
   * I: + 1
   * X: + 10
   * 
   * step 2:
   * M: + 1000
   * C: - 100 <--- subtract because next number is greater
   * M: + 1000
   * L: + 50
   * I: - 1 <--- subtract because next number is greater
   * X: + 10
   *
   * step3: +1000-100+1000+50-1+10=1990
   */
  list< pair<bool,unsigned> > sign_value; // true(+),false(-)
  // step 1
  for (auto &c: str) {
    sign_value.push_back( pair<bool,unsigned>(true, RomanTokenToDecimal(c)) );
  }

  // step 2: change the sign if the subsequent value is higher
  for (auto it = sign_value.begin(); it != sign_value.end(); ++it) {
    if (it != sign_value.begin()) {
      auto prev = it; --prev;
      if (prev->second < it->second) // do we need to subtract
	prev->first = false;
    }
  }

  // step 3: sum the numbers
  unsigned sum = 0;
  for (auto it = sign_value.cbegin(); it != sign_value.cend(); ++it) {
    sum = sum + (it->first ? it->second : -it->second);
  }

  //cout << sign_value << ' ' << sum << endl;
  return sum;
}

/*
 * not sure if romans had negative numbers, but allow negative numbers
 */
static int doOperation(unsigned arg1, unsigned arg2, char op)
{
  switch (op) {
  case '+': return arg1 + arg2;
  case '-': return arg1 - arg2;
  case '*': return arg1 * arg2;
  case '/': return arg1 / arg2;
  }
  return 0;
}

int main()
{
  // do a little bit of checking
  {
    string a("I");
    cout << a << ':' << RomanStringToNumber(a) << endl;
  }
  {
    string a("II");
    cout << a << ':' << RomanStringToNumber(a) << endl;
  }
  {
    string a("III");
    cout << a << ':' << RomanStringToNumber(a) << endl;
  }
  {
    string a("IV");
    cout << a << ':' << RomanStringToNumber(a) << endl;
  }
  {
    string a("V");
    cout << a << ':' << RomanStringToNumber(a) << endl;
  }
  {
    string a("VI");
    cout << a << ':' << RomanStringToNumber(a) << endl;
  }
  {
    string a("VII");
    cout << a << ':' << RomanStringToNumber(a) << endl;
  }
  {
    string a("VIII");
    cout << a << ':' << RomanStringToNumber(a) << endl;
  }
  {
    string a("IX");
    cout << a << ':' << RomanStringToNumber(a) << endl;
  }
  {
    string a("X");
    cout << a << ':' << RomanStringToNumber(a) << endl;
  }
  {
    string a("MCMXL");
    cout << a << ':' << RomanStringToNumber(a) << endl;
  }

  // open the file
  ifstream fin;
  fin.open("MP4.txt");

  // read line by line, performing the operation
  for (;;) {
    string rm1, rm2;
    char op;
    fin >> rm1 >> rm2 >> op;
    if (fin.fail()) break;

    cout << "rm1=" << rm1 << " rm2=" << rm2 << " op=" << op << " ";

    cout << RomanStringToNumber(rm1) << op
	 << RomanStringToNumber(rm2) << "="
	 << doOperation(RomanStringToNumber(rm1),
			RomanStringToNumber(rm2),op) << endl;
  }
  fin.close();
  return 0;
}


I:1
II:2
III:3
IV:4
V:5
VI:6
VII:7
VIII:8
IX:9
X:10
MCMXL:1940
rm1=MCCXXVI rm2=CV op=+ 1226+105=1331
rm1=MCCXXCI rm2=MCCXXI op=/ 1301/1221=1
rm1=V rm2=I op=- 5-1=4
rm1=DL rm2=DXXXXVIII op=- 550-548=2
rm1=D rm2=L op=/ 500/50=10
rm1=MDI rm2=CXI op=+ 1501+111=1612
rm1=XXV rm2=IIII op=/ 25/4=6
rm1=XI rm2=CII op=* 11*102=1122
Last edited on
With recursion:

This code may be executed on the commandline with ./main XVII for instance.
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
#include <iostream>

using namespace std;
int getDecVal( char );
string tail( string const&, size_t const );
int rome_to_dec( string );

int main( int argc, char** argv ){
	cout << rome_to_dec( argv[1] );
	return 0;
}

int rome_to_dec( string str ){
	int mulVal;
	if( str.size() == 0 ){
		return 0;
	}else{
		mulVal = getDecVal(str[0]);
		if( str.length() > 1 ){
			if( mulVal < getDecVal(str[1]) ){
				mulVal = -mulVal;
			}
		}
		return mulVal + rome_to_dec( tail(str, str.size()-1) );
	}	
}

string tail( string const& source, size_t const length){
	if( length >= source.size() ){ return source; }
	return source.substr(source.size() - length);
}

int getDecVal( char x ){
	switch(x){
	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;
	}
	return 0; // Continue the statement
	
}


However, this solution that I provided does not account for invalid user input. For instance, XIIV is not valid. However this algorithm that I presented will return the number 15. You would need to add another function that is verifying that the user input is valid--or build that into the recursion (which I highly discourage).

I checked my solutions against this:
http://westerlund09.wikis.birmingham.k12.mi.us/file/view/roman_numerals.jpg
Last edited on
Topic archived. No new replies allowed.