Roman Numeral Calculator

I'm working on a Roman Numeral Calculator machine problem, but I'm so lost.

Here's the full directions:
You are to design and implement a Roman numeral calculator. The subtractive Roman numeral notation commonly in use today was used only rarely during the time of the Roman Republic and Empire. For ease of calculation, the Romans most frequently used a purely additive notation in which a number was simply the sum of its digits (4 equals IIII in this notation, not IV). Each number starts with the digit of highest value and ends with the digit of smallest value. This is the notation you will use in this program.

Your program inputs two Roman numbers and an arithmetic operator and prints out the result of the operation, also as a Roman number. The values of the Roman digits are as follows:

I 1
V 5
X 10
L 50
C 100
D 500
M 1000
Thus, the number MDCCCCLXXXXVI represents 1996, because 1996 really consists of:

1000 + 500 + 100 + 100 + 100 + 100 + 50 + 10 + 10 + 10 + 10 + 5 + 1.

M D C C C C L X X X X V I

The arithmetic operators that your program should recognize in the input are +, -, *, and /. These should perform the C++ operations of integer addition, subtraction, multiplication, and division.

One way of approaching this problem is to convert the Roman numbers into integers, then perform the required operation, and then convert the result back into a Roman number for printing.

Assume that the input numbers are in purely additive form - that is, digits are followed only by digits of the same or lower value. Also assume that the letters are all legal, no need to check for errors in the input file. Also, assume that the answer to each calculation will be a positive number.

REQUIREMENTS: This program is to be done using functions. These functions must NOT reference global variables directly (use parameter lists). The prototypes and descriptions below are a suggested method of breaking up the problem into functions – if you prefer to design your own functions, feel free to do so, but make sure you have both value-returning and void functions in your solution.

FUNCTION get_Data

This function receives the input file, reads one series of chars representing a Roman numeral, and sends back the value of the numeral read in. This function can call the function convert_from_Roman_to_Decimal to do the conversion while it is reading each letter.

FUNCTION convert_from_Roman_to_Decimal
int convert_from_Roman_to_Decimal(char);
This function is to receive a char (e.g. an 'M' or a 'C' etc.) and return its corresponding integer value as an integer. Use a value-returning function. It can be called from the get_Data function.

FUNCTION convert_from_ Decimal_ to _ Roman
string convert_from_Decimal_to_Roman(int);
This function is to receive a integer (e.g. 13) and return its corresponding roman value as a string (e.g. XIII). Use a value-returning function.


FUNCTION get_Oper
char get_Oper(ifstream&);
This function receives the input file, reads the operator, and sends back the character read in.
FUNCTION calc_Romans
void calc_Romans(int, int, char, int&);
This function is given the two integers and a char (the operator) and returns the result of doing the required operation on the two integers, (using the reference 4th parameter.)

FUNCTION print_Result
void print_Result(int);
This void function receives the integer result of the calculation, and prints it out. It does not have to return anything to the calling program.

INPUT/OUTPUT: The input file will have number of lines. Each line will have two Roman numbers followed by an operator, separated by blanks. Include a copy of the file with your program and output. The style of the data file looks as follows:

MCCXXVI CV +
MCCXXVI MCCXXVI /
...
etc.

Output Example:
The two lines above would produce the output:

The first number is MCCXXVI ( 1226 ).
The second number is CV ( 105 ).
The operator is +
The result is 1331 ( MCCXXXI ).
************************************************

The first number is MCCXXVI ( 1226 ).
The second number is MCCXXVI ( 1226 ).
The operator is /

The result is 1 ( I ).
Hint: Write this program in stages, concentrating on one function at a time. For example, write the Get_Data function and a main program to test it. Make sure that it works and can read a Roman numeral in the file correctly before working on any of the other functions. Your main program will be quite short with lots of function calls to do all the work.

The input file (mp4romanletrdata.txt) has the following data:

MCCXXVI CV +
MCCXXVI MCCXXVI /
V I -
MDCLXVI III *
DL DXXXXVIII -
D L /
MDI CXI +
XXV IIII /
XI CII *


Currently I'm struggling with the get_Data function, here's what I've got so far, which I know isn't much. Any help is appreciated!

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>
#include <string>

using namespace std;

	int get_Data(ifstream&, string rn1, char R)
	{
		ifstream inFile("mp4romanletrdata.txt");

		while (inFile >> rn1)
		{
			cout << rn1 << endl;
			rn1.substr(0, 1) = R;
		}
		return R;
	}
	
	int convert_from_Roman_to_Decimal(char R)
	{
		if (R == 'I')
		{
			return 1;
		}
		else if (R == 'V')
		{
			return 5;
		}
		else if (R == 'X')
		{
			return 10;
		}
		else if (R == 'L')
		{
			return 50;
		}
		else if (R == 'C')
		{
			return 100;
		}
		else if (R == 'D')
		{
			return 500;
		}
		else if (R == 'M')
		{
			return 1000;
		}
		else
		{
			return 0;
		}
	}

	int main()
	{

	}
Last edited on
@fcailin

Here's a bit of help. Of course, you still have quite a bit to do, like checking if you need to subtract instead of add. IX is a 9, so you would check if the number after a lower number is a higher value, that would mean to subtract the lower from the higher to get the true value. Anyway, here's your program reading in the roman numeral, then converting to a number. I used MDCCCCLXXXXVI (1996) as the roman numeral.

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
// Roman_Numeral Calc.cpp : main project file.

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

string get_Data(string Roman_Numeral)
{
	ifstream inFile("mp4romanletrdata.txt");
	char rn1;
	while (inFile >> rn1)
	{
		Roman_Numeral += rn1;
	}
	return Roman_Numeral;
}

int convert_from_Roman_to_Decimal(string  Roman_Numeral)
{
	int len = Roman_Numeral.length();
	int number = 0;
	for (int x = 0; x < len; x++)
	{
		if (Roman_Numeral[x] == 'I')
		{
			number+= 1;
		}
		else if (Roman_Numeral[x] == 'V')
		{
			number += 5;
		}
		else if (Roman_Numeral[x] == 'X')
		{
			number += 10;
		}
		else if (Roman_Numeral[x] == 'L')
		{
			number += 50;
		}
		else if (Roman_Numeral[x] == 'C')
		{
			number += 100;
		}
		else if (Roman_Numeral[x] == 'D')
		{
			number += 500;
		}
		else if (Roman_Numeral[x] == 'M')
		{
			number += 1000;
		}
	}
	return number;
}

int main()
{
	string Roman_Numeral = "";
	int number;
	Roman_Numeral=get_Data(Roman_Numeral);
	cout << Roman_Numeral << endl;;
	number = convert_from_Roman_to_Decimal(Roman_Numeral);
	cout << number << endl;
}
Should we also handle the irregular cases of Roman numbers too?
For example :
+ IV : 4
+ IX : 9
@closed account 5a8Ym39o6

Should we also handle the irregular cases of Roman numbers too?


Sure. I was just pointing out 1 case, but, yes, there are more. + CM : 900, XL : 40, etc.
@closed account and whitenite1: Reread the OP. The instructions clearly state that the additive principle for Roman Numerals will be used, and NOT the subtractive.
i.e. 4 is IIII and not IV and 900 is DCCCC and not CM, etc..
@Arslan7041

Thanks for pointing that out. Yes, I did miss it, as I actually just scan read what was written.
closed account (48T7M4Gy)
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
#include <iostream>
#include <fstream>
#include <string>

int convert(std::string);

int main()
{
    char operation = ' ';
    std::string Roman_No_1, Roman_No_2;
    
    std::ifstream inFile("roman_numerals.txt");
    
    while (inFile >> Roman_No_1 >> Roman_No_2 >> operation)
        std::cout << convert(Roman_No_1) << operation << convert(Roman_No_2) << '=' << '\n';
    return 0;
}

int convert(std::string aWord)
{
    int number = 0;
    
    for(int i = 0; i < aWord.length(); i++)
    {
        switch(aWord[i])
        {
            case 'M':
                number += 1000;
                break;
            case 'D':
                number += 500;
                break;
            case 'C':
                number +=100;
                break;
            case 'L':
                number += 50;
                break;
            case 'X':
                number += 10;
                break;
            case 'V':
                number += 5;
                break;
            case 'I':
                number += 1;
                break;
            default:
                std::cout << "Data error\n";
        }
    }
    return number;
}


You now need another function to crunch the numbers. Should be fairly easy. And then onto the other stuff.
Last edited on
closed account (48T7M4Gy)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int crunchNumbers( int first, int second , char operation)
{
    switch(operation)
    {
        case '+':
            return first + second;
            break;
        case '-':
            return first - second;
            break;
        case '*':
            return first * second;
            break;
        case '/':
            if( second != 0)
                return first/second;
            else
                break;
        default:
            return -9999;
    }
    return -999;
}


1226 + 105 = 1331
1226 / 1226 = 1
5 - 1 = 4
1666 * 3 = 4998
550 - 548 = 2
500 / 50 = 10
1501 + 111 = 1612
25 / 4 = 6
11 * 102 = 1122
Program ended with exit code: 0


That's the principle but you'll have to alter it to suit the question specification.
Last edited on
@kemort

Thanks for you're help! I reworked the code a bit, and I changed the function under int main() to int get_Data(). But now I'm confused as to how to call crunchNumbers and use the numbers from get_Data since all the variables are local to the functions.

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

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int convert_to_decimal(string);

int get_Data()
{
	char operation = ' ';
	string Roman_No_1, Roman_No_2;

	ifstream inFile("mp4romanletrdata.txt");

	while (inFile >> Roman_No_1 >> Roman_No_2 >> operation)
		cout << Roman_No_1 << "(" << convert_to_decimal(Roman_No_1) << ") " << operation << " " << Roman_No_2 << "(" << convert_to_decimal(Roman_No_2) << ") " << '=' << '\n' << "***********************" << '\n';
	return 0;
}

int convert_to_decimal(string aWord)
{
	int number = 0;

	for (int i = 0; i < aWord.length(); i++)
	{
		switch (aWord[i])
		{
		case 'M':
			number += 1000;
			break;
		case 'D':
			number += 500;
			break;
		case 'C':
			number += 100;
			break;
		case 'L':
			number += 50;
			break;
		case 'X':
			number += 10;
			break;
		case 'V':
			number += 5;
			break;
		case 'I':
			number += 1;
			break;
		default:
			cout << "Data error\n";
		}
	}
	return number;
}
int crunchNumbers(int first, int second, char operation)
{
	switch (operation)
	{
	case '+':
		return first + second;
		break;
	case '-':
		return first - second;
		break;
	case '*':
		return first * second;
		break;
	case '/':
		if (second != 0)
			return first / second;
		else
			break;
	default:
		return -9999;
	}
	return -999;
}


int main()
{
	char operation = ' ';
	string Roman_No_1, Roman_No_2;

	cout << get_Data() << crunchNumbers(convert_to_decimal(Roman_No_1), convert_to_decimal(Roman_No_2), operation);

}



MCCXXVI(1226) + CV(105) =
***********************
MCCXXVI(1226) / MCCXXVI(1226) =
***********************
V(5) - I(1) =
***********************
MDCLXVI(1666) * III(3) =
***********************
DL(550) - DXXXXVIII(548) =
***********************
D(500) / L(50) =
***********************
MDI(1501) + CXI(111) =
***********************
XXV(25) / IIII(4) =
***********************
XI(11) * CII(102) =
***********************
closed account (48T7M4Gy)
I understand what you are saying and what you need to do is read the problem specification very carefully. You will need to keep the same functionality as you have but rearrange the prices to fit the requirements by passing appropriate parameters each time.

The problem specification tells you what the parameters are and what the output is for each function. You don't have to change much. Just do them one at a time, with testing as you go.
Last edited on
Okay, I worked on it and I've made some changes, and it works. Now the only problem I have is it reads the last input line of the file twice and I'm not sure why. Any idea 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
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

void get_Data(ifstream &inFile, string &romanOne, string &romanTwo, char &oper)
{
	inFile >> romanOne >> romanTwo >> oper;
}

string convert_to_Roman(int number)
{
	string roman = "";
	while (number > 0)
	{
		if (number >= 1000)
		{
			roman += "M";
			number -= 1000;
		}
		else if (number >= 500)
		{
			roman += "D";
			number -= 500;
		}
		else if (number >= 100)
		{
			roman += "C";
			number -= 100;
		}
		else if (number >= 50)
		{
			roman += "L";
			number -= 50;
		}
		else if (number >= 10)
		{
			roman += "X";
			number -= 10;
		}
		else if (number >= 5)
		{
			roman += "V";
			number -= 5;
		}
		else
		{
			roman += "I";
			number -= 1;
		}
	}
	return roman;
}

int convert_to_decimal(string roman)
{
	int number = 0;

	for (int i = 0; i<roman.length(); i++)
	{
		switch (roman[i])
		{
		case 'M':
			number += 1000;
			break;
		case 'D':
			number += 500;
			break;
		case 'C':
			number += 100;
			break;
		case 'L':
			number += 50;
			break;
		case 'X':
			number += 10;
			break;
		case 'V':
			number += 5;
			break;
		case 'I':
			number += 1;
			break;
		default:
			cout << "Data error\n";
		}
	}
	return number;
}

int calc_Romans(int num1, int num2, char oper)
{
	switch (oper)
	{
	case '+':
		return num1 + num2;
		break;
	case '-':
		return num1 - num2;
		break;
	case '*':
		return num1*num2;
		break;
	case '/':
		if (num2 != 0)
		{
			return num1 / num2;
		}
		else
			break;
	}
	return 0;
}

void print_Result(string romanOne, string romanTwo, char oper, string RomanResult, int intResult)
{
	cout << "The first number is " << romanOne << "(" << convert_to_decimal(romanOne) << ")" << endl;
	cout << "The second number is " << romanTwo << "(" << convert_to_decimal(romanTwo) << ")" << endl;
	cout << "The operator is " << oper << endl;
	cout << "The result is " << intResult << "(" << RomanResult << ")" << endl;
	cout << "******************************" << endl;
}

int main()
{
	string romanOne, romanTwo, romanResult;
	char oper;
	int num1, num2, numResult;

	ifstream inFile;
	inFile.open("mp4romanletrdata.txt");
	while (!inFile.eof())
	{
		get_Data(inFile, romanOne, romanTwo, oper);
		num1 = convert_to_decimal(romanOne);
		num2 = convert_to_decimal(romanTwo);
		numResult = calc_Romans(num1, num2, oper);
		romanResult = convert_to_Roman(numResult);
		print_Result(romanOne, romanTwo, oper, romanResult, numResult);
	}
}



The first number is MCCXXVI(1226)
The second number is CV(105)
The operator is +
The result is 1331(MCCCXXXI)
******************************
The first number is MCCXXVI(1226)
The second number is MCCXXVI(1226)
The operator is /
The result is 1(I)
******************************
The first number is V(5)
The second number is I(1)
The operator is -
The result is 4(IIII)
******************************
The first number is MDCLXVI(1666)
The second number is III(3)
The operator is *
The result is 4998(MMMMDCCCCLXXXXVIII)
******************************
The first number is DL(550)
The second number is DXXXXVIII(548)
The operator is -
The result is 2(II)
******************************
The first number is D(500)
The second number is L(50)
The operator is /
The result is 10(X)
******************************
The first number is MDI(1501)
The second number is CXI(111)
The operator is +
The result is 1612(MDCXII)
******************************
The first number is XXV(25)
The second number is IIII(4)
The operator is /
The result is 6(VI)
******************************
The first number is XI(11)
The second number is CII(102)
The operator is *
The result is 1122(MCXXII)
******************************
The first number is XI(11)
The second number is CII(102)
The operator is *
The result is 1122(MCXXII)
******************************
closed account (48T7M4Gy)
I suspect the reason is you are using eof() as the test for reading in the file data. Look at my line 14.
Topic archived. No new replies allowed.