When converting Roman Numerals, how do I tell the code to consider the fact that the letters are also used for subtraction? Like, X=10 and L=50, but XL is 40 and not 60. How do I do this ( instead of listing all combination )?

include <string>
using std::string;

class decimal2roman {
public string romanvalue;
decimal2roman(int input) {
const string roman[13] = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
const int decimal[13] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
romanvalue = "";
for (int i = 0; i < 13; i++) {
while (input >= decimal[i]) {
input -= decimal[i];
romanvalue += roman[i];
}
}
}

publicstring toString ()
{
return romanvalue;
}

Does anybody know how I can add that? I can't think of anything, honestly.

It would take a while to write a program like this without flaws and you would have to think hard but if you look there is a pattern. There are never more than 3 of the same "digits" in a row and its always high digits to low digits, left to right, unless you are subtracting then you put a lower numeral before a higher one.

I would look at wikipedia they have a good part on roman numerals.

ie
So, for instance, 1234 may be thought of as "one thousand and two hundreds and three tens and four", obtaining M (one thousand) + CC (two hundreds) + XXX (thirty) + IV (four), for MCCXXXIV.

You're probably right. I think it's fine like this, then.

How would I do decimal to Roman Numeral? Just the same way - array and just list them? Or is there something else I could do?

Never even heard of decimal roman numerals but yeah if its like our number system you would think its the similar.

I've never heard of Roman Decimal Numbers either and I'm trying to picture how you would differentiate 1.1 from 1.01 without a zero. I would confirm they exist and write out several examples on paper before attacking the C++ angle of it.

[EDIT]
Never mind. I had a terminology problem. I thought decimal meant you had to handle non-whole numbers. Wrong apparently.

Edited 5 Years Ago by VernonDozier: n/a

>> No, I mean Decimal converting to Roman Numerals.

I think there is a terminology problem. You might want to use "Arabic" instead of "Decimal" and talk about "Arabic" to "Roman" and vice-versa so everyone knows what you mean. According to Wikipedia at least, the Roman Numeral System IS a decimal system. I had always thought that "decimal" meant that you had to be able to handle things after the decimal point. I'm still a little confused frankly. but "Arabic" and "Roman" make it more obvious, at least to me.

Now that it's clear what you're trying to do, I imagine that converting is going to be at least a little more complex than what you have, particularly if you have to parse the whole Roman Number and make sure it's actually legal. I would drop the coding part of it for now and get the algorithm part down first.


[EDIT]
But then again, maybe it's just me. I googled "Roman to Decimal" and got all kinds of hits, so apparently everyone else understood. :)
[/EDIT]

Edited 5 Years Ago by VernonDozier: n/a

The following code is my suggestion, which is a simple solution for your problem. In fact, your problem was that it was difficult to solve the subtraction issue. My idea is that we represent the entire problem as a repetitive subtraction. Also, my code handles the possible bad inputs (romans didn't have negative numbers or 0).

include <string>
using std::string;
 
class decimal2roman {
public string romanvalue;
const private string roman[13] = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
const private int decimal[13] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
private int romanUnit(int number)
{
    for (int i = 0; i < 13; i++)
    if (number >= decimal[i])
    {
        romanvalue += roman[i];
        return number - decimal[i];
    }
}
public void decimal2roman(int input) {
if (input <= 0)
    romanvalue = "invalid";
romanvalue = "";
do
{
    input = romanUnit(input);
}
while (input > 0);
}
}
}
 
publicstring toString ()
{
return romanvalue;
}

Edited 5 Years Ago by DistantGuru: explaining the solution

Comments
We do not SOLVE problems for students, we help the solve it themselves. After all, you don't get the grade, and they don't deserve it.

Thanks ,DistantGuru. I'll check it out!

Then forget about Decimal to Roman. I'll just do Roman to Decimal for now.

Let's see...larger numeral preceding a smaller numeral means addition, so LX is 60. A smaller numeral preceding a larger numeral means subtraction, so XL is 40. Any place in a decimal number, such as the 1s place, the 10s place, and so on, requires from zero to four Roman numerals. I'll see if it works.

Edited 5 Years Ago by Lemonader: n/a

Hello, Roman->Arabic number converting ideas:

You have longer Roman numbers, like: "CM, XC" and so on. You have to sort out these in descending order, so, you start with "CM" and you finish with "IV". You add all these to the variable which will store the result and remove these from the input string. After that, you will do the same with the remaining characters, so the algorithm looks like this:

string roman2[13] = { "CM", "CD", "XC", "XL", "IX", "IV", "M", "D", "C", "L", "X", "V", "I"};
int decimal2[13] = {900, 400, 90, 40, 9, 4, 1000, 500, 100, 50, 10, 5, 1};

1. i <- 0;output <- 0
2. while (i < 13)
3. occurence <- the occurence number of roman2[i] in input
4. output <- output + decimal2[i] * occurence
5. delete all occurence of roman2[i] from input
6. i <- 1 + i

Edited 5 Years Ago by DistantGuru: Making it more readable

So I basically just change everything from string roman until public void and use this algorithm instead?

You just delete all the symbol types from the input string and in the meantime you add these to your result value. This is an inversion of the previous algorithm and while your input string is not empty, you still have numbers to add. This is a simple and quick solution.

Ok, I think I'll stick with the first version you posted.

#include <string>
using std::string;
 class decimal2roman {
public:string romanvalue;
const string roman2[13] = { "CM", "CD", "XC", "XL", "IX", "IV", "M", "D", "C", "L", "X", "V", "I"};
const int decimal2[13] = {900, 400, 90, 40, 9, 4, 1000, 500, 100, 50, 10, 5, 1};
private int romanUnit(int number)
{
    for (int i = 0; i < 13; i++)
    if (number >= decimal[i])
    {
        romanvalue += roman[i];
        return number - decimal[i];
    }
}
public void decimal2roman(int input) {
if (input <= 0)
    romanvalue = "invalid";
romanvalue = "";
do
{
    input = romanUnit(input);
}
while (input > 0);
}
}
}
 
publicstring toString ()
{
return romanvalue;
}

But it dosen't compile, it has a problem with this:

const string roman2[13] = { "CM", "CD", "XC", "XL", "IX", "IV", "M", "D", "C", "L", "X", "V", "I"}; 
const int decimal2[13] = {900, 400, 90, 40, 9, 4, 1000, 500, 100, 50, 10, 5, 1};

Says C++ forbids initialization of roman2, and that it makes it static. Same with the line below it. Then with the last two } } after while. I already changed that, but then other errors pop up.

Edited 5 Years Ago by Lemonader: n/a

In my first post I've described a solution to convert arabic numbers to roman numbers. The algorithm is to convert roman numbers to arab numbers.

The problem you mentioned is:

You declare the arrays as member data, so you should use

private string roman2[13] = { "CM", "CD", "XC", "XL", "IX", "IV", "M", "D", "C", "L", "X", "V", "I"}; 
private int decimal2[13] = {900, 400, 90, 40, 9, 4, 1000, 500, 100, 50, 10, 5, 1};

instead of

const string roman2[13] = { "CM", "CD", "XC", "XL", "IX", "IV", "M", "D", "C", "L", "X", "V", "I"}; 
const int decimal2[13] = {900, 400, 90, 40, 9, 4, 1000, 500, 100, 50, 10, 5, 1};

Ok, I have to reopen the thread. I did it a little differently, and first I thought it worked, but then, when I ran the code, I noticed it actually doesn't work properly. When the input is XL, the output it just X and 10 ( it list the decimal value again). That is not correct. ughhhh. How do I do this now? :(

#include <iostream>
using namespace std;

class romanType{
public:
	romanType(char&); 
	int convert();
	void print();
	void get();

private:
	int M, D, C, L, X, V, I;
	char romanNumeral;
};
romanType::romanType(char &ch){
	M = 1000;
	D = 500;
	C = 100;
	L = 50;
	X = 10;
	V = 5;
	I = 1;
	cout << ch << endl;
	romanNumeral=ch;	
}
int romanType::convert(){
	switch (romanNumeral) {

case 'M': return 1000;

case 'D': return 500;

case 'C': return 100;

case 'L': return 50;

case 'X': return 10;

case 'V': return 5;

case 'I': return 1;

}
	return 0;   
}
void romanType::print(){
	cout << romanNumeral << endl;
}
void romanType::get(){
}
int main(){
	char romanNumeral;
	cout << "Please enter a number to convert: ";
	cin >> romanNumeral;
	romanType roman=romanType(romanNumeral); 
	cout << roman.convert() << endl;;

	system("pause");
return 0;
}

Also tried if-else, but it's the same result.

You have the following problems:
1.) XL contains 'X' and in your function you're searching for 'X' before you search for "XL", so, the first problem, that you should check in the order which was given in the array before. The order is: { "CM", "CD", "XC", "XL", "IX", "IV", "M", "D", "C", "L", "X", "V", "I"}
2.) The second problem is that you use switch case which only works for characters. You should use if's and the equals operator of the string obtject.
3.) Your convert function works only with roman numbers which can be characters. The concept is far from a solution, because you'll have problems with inputs like "VII" being considered to be 5 instead of 7. You must use the algorithm I've provided before:

private string roman2[13] = { "CM", "CD", "XC", "XL", "IX", "IV", "M", "D", "C", "L", "X", "V", "I"};
private int decimal2[13] = {900, 400, 90, 40, 9, 4, 1000, 500, 100, 50, 10, 5, 1};

private romanNumber = "";

public int countElementsInString(string rm)
{
    int index = 0;
    int output = -1;
    string start;
    string end;
    do
    {
        start = "";
        end = "";
        index = romanNumber.find(rm);
        if (index >= 0)
        {
            try{ start = romanNumber.substr(0, index);} catch (Exception exception);
            try{ end =   romanNumber.substr(index + rm.length());} catch (Exception exception);
            romanNumber = start + end;
        }
        output++;
    }
    while (index >= 0);
    return output;
}

public int converter(string romanNumber)
{
int i = 0;
int output = 0;
while (i < 13)
{
    output += decimal2[i] * countElementsInString(roman2[i]);
    i++;
}
return output;
}

This is the implementation of the algorithm shown before, which is:

1. i <- 0;output <- 0
2. while (i < 13)
3. occurence <- the occurence number of roman2[i] in input
4. output <- output + decimal2[i] * occurence
5. delete all occurence of roman2[i] from input
6. i <- 1 + i

Edited 5 Years Ago by DistantGuru: n/a

But this gives me a bunch of error codes:

#include <string>
using std::string;
class decimal2roman {
public:string romanvalue;
private string roman2[13] = { "CM", "CD", "XC", "XL", "IX", "IV", "M", "D", "C", "L", "X", "V", "I"};
private int decimal2[13] = {900, 400, 90, 40, 9, 4, 1000, 500, 100, 50, 10, 5, 1};

private romanNumber = "";

public int countElementsInString(string rm)
{
    int index = 0;
    int output = -1;
    string start;
    string end;
    do
    {
        start = "";
        end = "";
        index = romanNumber.find(rm);
        if (index >= 0)
        {
            try{ start = romanNumber.substr(0, index);} catch (Exception exception);
            try{ end =   romanNumber.substr(index + rm.length());} catch (Exception exception);
            romanNumber = start + end;
        }
        output++;
    }
    while (index >= 0);
    return output;
}

public int converter(string romanNumber)
{
int i = 0;
int output = 0;
while (i < 13)
{
    output += decimal2[i] * countElementsInString(roman2[i]);
    i++;
}
return output;
}

You aren't thinking this problem through properly.

Roman numerals have the same 'design' as Arabic numbers: thousands, hundreds, tens, ones places. The difference is Arabic values have 1 character for each, Roman has multiple.
100: C < D
10: X < L
1: I < V

742 = DCCXLII -- 700=DCC 40=XL 2=II

So, look at the string and find the hundreds characters and process them accordingly:

hund = 0
while roman[i] is a hundreds-char
    if hund = 0 then 
        hund = arabic-value(roman[i])  ;; first value, save it
    else
    if hund < arabic-value(roman[i]) then 
        hund = arabic-value(roman[i]) - hund  ;; next value is greater, subtract previous
    else
        hund = hund + arabic-value(roman[i]) ;; add

    i=i+1
end while
This article has been dead for over six months. Start a new discussion instead.