I'm mostly looking to get feedback on how well I've implemented the C++ language. But I would also like feedback on my algorithm. Did I make it more complex than it needs to be? Is there anything I could have done better?
Things my algorithm prevents:
- IIII <- "too many multiples," better represented as IV
- IIIV <- "cannot add the same digit to a subtraction," better represented as VI
- IVI <- "addition cannot follow subtraction," better represented as V
- IXX <- "cannot subtract from a multiple," better represented as XIX
Things it does not prevent (that I'm aware of):
- XICV <- "bad format," better represented as CXIV
- IXIX <- "repeated subtraction," better represented as XVIII
- VV <- "multiple is value of existing digit," better represented as X
Note: This uses the rules of roman numerals I was taught, and I realize that there isn't really a an accepted standard of rules for representing numbers using roman numerals.
#include <string>
#include <stack>
#include <iostream>
#include <ctype.h> // required for tolower()
using namespace std;
int get_roman_value( char );
int roman_to_decimal( string& );
int main( int argc, char* argv[] )
{
if( argc > 1 )
{
string roman(argv[1]);
try {
cout << roman_to_decimal(roman) << endl;
} catch( const char* e ) {
cerr << e << endl;
}
}
return 0;
}
int get_roman_value( char digit )
{
switch( tolower(digit) )
{
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: throw "bad digit";
}
return 0;
}
int roman_to_decimal( string& roman )
{
int decimal = 0; // the final result
int multiple = 0; // keeps track of multiples, eg. In XXV, X would be a multiple
int current = 0; // the digit currently being processed
int last_add = 0; // the last digit that wasn't a multiple, or subtraction operation
int last_sub = 0;
stack<int> digits; // queue of the digits
string::iterator i; // iterator to loop through the roman string
for( i = roman.begin(); i < roman.end(); i++ )
digits.push( get_roman_value(*i) );
do
{
// get the current digit
current=digits.top(), digits.pop();
// if there are too many multiples, then throw up
if( multiple > 2 )
throw "too many multiples";
// check for a substraction operation
if( !digits.empty() && current > digits.top() )
{
if( multiple > 0 )
throw "cannot subtract from a multiple";
if( last_add == digits.top() )
throw "addition cannot follow subtraction";
decimal+=(current-digits.top()), last_sub=digits.top(), digits.pop();
}
// check for multiples
else if( !digits.empty() && current == digits.top() )
decimal += current, multiple++;
// regular addition operation
else
if( last_sub == current )
throw "cannot add the same digit to a subtraction";
else
decimal+=current, multiple=0, last_add=current;
} while( !digits.empty() );
return decimal;
}