473,382 Members | 1,545 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,382 software developers and data experts.

Roman numerals to ints

Inspired by a thread on clc++, I decided to try it out...

#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[] )
{
int i;
int result=0;
int this;
int last=0;

if( argc != 2 ) {
printf( "No string specified\n" );
return( EXIT_FAILURE );
}
for( i=0 ; argv[1][i] != '\0' ; i++ ) {
switch( argv[1][i] ) {
case 'M':
this=1000;
break;
case 'D':
this=500;
break;
case 'C':
this=100;
break;
case 'L':
this=50;
break;
case 'X':
this=10;
break;
case 'V':
this=5;
break;
case 'I':
this=1;
break;
default:
printf( "Bad character %c\n", argv[1][i] );
return( EXIT_FAILURE );
}
result+=this;
if( this > last ) {
result-=2*last;
}
last=this;
}
printf( "Result is %d\n", result );
return( EXIT_SUCCESS );
}

This seems to work (and this time I didn't forget my header files :P).
Questions:

A) Is it 100% legal, ANSI C?
B) Is there a more efficient way to implement it?

--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |
Nov 13 '05 #1
13 4347
Christopher Benson-Manica wrote:

Looks pretty good overall. A few ways to make it shorter:
for( i=0 ; argv[1][i] != '\0' ; i++ ) {
switch( argv[1][i] ) {
char *p;

for (p = argv[1]; *p; p++) {
switch (*p) {

Pointers are your friend, in C.
case 'M':
this=1000;
break;
case 'D':
this=500;
break;


This way uses 1/3 as many lines and is easier to read besides:
case 'M': this = 1000; break;
case 'D': this = 500; break;

You could also use a table for the conversion, something like:

char letters[] = "MDCLXVI";
char values[] = {1000, 500, 100, 50, 10, 5, 1};

And use strchr(), but you'd have to subtract pointers and mess
around a bit. I think the switch statement is cleaner, really.

Now (getting silly here), if you had to convert *lots* of roman
numerals to arabic *really fast*, you could build a table of 256
values, where table['M'] = 1000, etc, and invalid characters were
zero... :)

--
Tom Zych
This email address will expire at some point to thwart spammers.
Permanent address: echo 'g******@cbobk.pbz' | rot13
Nov 13 '05 #2
In article <bj**********@chessie.cirr.com>, Christopher Benson-Manica wrote:
Inspired by a thread on clc++, I decided to try it out...

#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[] )
{
int i;
int result=0;
int this;
int last=0;

if( argc != 2 ) {
printf( "No string specified\n" );
A usage note is good here, e.g. roman: usage roman
[roman numeral]. It makes the error message a little more
helpful.
return( EXIT_FAILURE );
}
for( i=0 ; argv[1][i] != '\0' ; i++ ) {
switch( argv[1][i] ) {
case 'M':
this=1000;
break;
case 'D':
this=500;
break;
case 'C':
this=100;
break;
case 'L':
this=50;
break;
case 'X':
this=10;
break;
case 'V':
this=5;
break;
case 'I':
this=1;
break;
default:
printf( "Bad character %c\n", argv[1][i] );
return( EXIT_FAILURE );
}
result+=this;
if( this > last ) {
result-=2*last;
}
last=this;
}
printf( "Result is %d\n", result );
return( EXIT_SUCCESS );
}

This seems to work (and this time I didn't forget my header
files :P). Questions:

A) Is it 100% legal, ANSI C?
If you mean: "Is it 100% in accordance with the langauge
described in the C standard everybody is talking about?", then
yes.

I have no idea if writing such a program as the above is actually
legal. Consult a lawyer for that. ;-)
B) Is there a more efficient way to implement it?


I think it's efficient enough.

C) Does it work?

It seems to. The best way to test this program is with another
program that converts base 10 to roman numerals, or obtain a huge
table of conversions. You can then write a quick script to
convert a few million numbers there and back again, and thus have
more confidence in your program.

It would be nice if it also accepted lower case roman digits.

Finally, it may work for valid roman numerals, but it doesn't
provide useful diagnostics for nonsense combinations of roman
digits like "VIM" or "IXI".

--
Neil Cerutti
Nov 13 '05 #3
On Fri, 12 Sep 2003 19:17:23 UTC, Christopher Benson-Manica
<at***@nospam.cyberspace.org> wrote:
Inspired by a thread on clc++, I decided to try it out...

#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[] )
{
int i;
int result=0;
int this;
int last=0;

if( argc != 2 ) {
printf( "No string specified\n" );
return( EXIT_FAILURE );
}
for( i=0 ; argv[1][i] != '\0' ; i++ ) {
switch( argv[1][i] ) {
case 'M':
this=1000;
break;
case 'D':
this=500;
break;
case 'C':
this=100;
break;
case 'L':
this=50;
break;
case 'X':
this=10;
break;
case 'V':
this=5;
break;
case 'I':
this=1;
break;
default:
printf( "Bad character %c\n", argv[1][i] );
return( EXIT_FAILURE );
}
result+=this;
if( this > last ) {
result-=2*last;
}
last=this;
}
printf( "Result is %d\n", result );
return( EXIT_SUCCESS );
}

This seems to work (and this time I didn't forget my header files :P).
Questions:

A) Is it 100% legal, ANSI C?
Yes.
B) Is there a more efficient way to implement it?


/* you may use this table to convert dec to roman too */

struct {
char rom;
long dec;
} rom_dec[] = {
{ 'I', 1 },
{ 'V', 5; },
{ 'X', 10 },
{ 'L', 50 },
{ 'C', 100 },
{ 'D', 500 },
{ 'M', 1000},
{ 0, 0 } /* end of list, bail out, unknown letter */
};

char *r = argv[1];
char *d = rom_dec;
long result = 0;
long last = 0;

for (; *r, r++) {
for (d = rom_dec; d->rom && *r != d->rom; d++) ; /* for body is
empty! */
if (!d->rom) {
printf("unable to convert %c\n", *r);
return EXIT_FAILTURE;
}
result += d->dec;
if (d->dec > last)
result -= 2*last;
last = this;
}

Not tested yet, but should work

--
Tschau/Bye
Herbert

eComStation 1.1 Deutsch Beta ist verügbar
Nov 13 '05 #4
The Real OS/2 Guy wrote:

<snip>
for (; *r, r++) {
for (d = rom_dec; d->rom && *r != d->rom; d++) ; /* for body is
empty! */
if (!d->rom) {
printf("unable to convert %c\n", *r);
return EXIT_FAILTURE;
}
result += d->dec;
if (d->dec > last)
result -= 2*last;
last = this;
}

Not tested yet, but should work


On the contrary, the compiler will issue a diagnostic for this code, and
almost certainly refuse to provide a binary.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #5
The Real OS/2 Guy <os****@pc-rosenau.de> spoke thus:
for (; *r, r++) {
for (d = rom_dec; d->rom && *r != d->rom; d++) ; /* for body is
empty! */
if (!d->rom) {
printf("unable to convert %c\n", *r);
return EXIT_FAILTURE;
}


Is looping through a table more efficient than a switch statement? (the code
certainly looks cleaner)

--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |
Nov 13 '05 #6
On Sun, 14 Sep 2003 11:58:30 UTC, Richard Heathfield
<do******@address.co.uk.invalid> wrote:
The Real OS/2 Guy wrote:

<snip>
for (; *r, r++) {
for (d = rom_dec; d->rom && *r != d->rom; d++) ; /* for body is
empty! */
if (!d->rom) {
printf("unable to convert %c\n", *r);
return EXIT_FAILTURE;
}
result += d->dec;
if (d->dec > last)
result -= 2*last;
last = this;
}

Not tested yet, but should work


On the contrary, the compiler will issue a diagnostic for this code, and
almost certainly refuse to provide a binary.

Why should it? Don't cry that it is not a complete function!

--
Tschau/Bye
Herbert

eComStation 1.1 Deutsch Beta ist verügbar
Nov 13 '05 #7
The Real OS/2 Guy wrote:
Richard Heathfield wrote:
The Real OS/2 Guy wrote:
for (; *r, r++) {
^
....On the contrary, the compiler will issue a diagnostic for this code, and
almost certainly refuse to provide a binary.


Why should it?


Why do you ask?

Jirka

Nov 13 '05 #8
On Sun, 14 Sep 2003 22:05:35 +0000 (UTC), "The Real OS/2 Guy"
<os****@pc-rosenau.de> wrote:

On Sun, 14 Sep 2003 11:58:30 UTC, Richard Heathfield
<do******@address.co.uk.invalid> wrote:
On the contrary, the compiler will issue a diagnostic for this code, and
almost certainly refuse to provide a binary.

Why should it? Don't cry that it is not a complete function!


gcc foo.c
foo.c:6: parse error before ';' token
foo.c:15: `argv' undeclared here (not in a function)
foo.c:16: warning: initialization from incompatible pointer type
foo.c:20: parse error before "for"
foo.c:20: conflicting types for `r'
foo.c:15: previous declaration of `r'
foo.c:20: conflicting types for `r'
foo.c:20: previous declaration of `r'
foo.c:20: parse error before '++' token
foo.c:30: conflicting types for `last'
foo.c:18: previous declaration of `last'
foo.c:30: `this' undeclared here (not in a function)
foo.c:30: warning: data definition has no type or storage class
foo.c:31: parse error before '}' token

--
#include <standard.disclaimer>
_
Kevin D Quitt USA 91387-4454 96.37% of all statistics are made up
Per the FCA, this address may not be added to any commercial mail list
Nov 13 '05 #9
In article <bk**********@chessie.cirr.com>, Christopher Benson-Manica wrote:
The Real OS/2 Guy <os****@pc-rosenau.de> spoke thus:
for (; *r, r++) {
for (d = rom_dec; d->rom && *r != d->rom; d++) ; /* for body is
empty! */
if (!d->rom) {
printf("unable to convert %c\n", *r);
return EXIT_FAILTURE;
}


Is looping through a table more efficient than a switch
statement? (the code certainly looks cleaner)


I don't think there's much benefit to it over a big switch unless
the table allows lookup faster than linear time (O(n)).

You could do that with a table big enough to hold every valid
character value, or with a table sorted by char value, on which
you can use binary search.

A linear search through the table, as above, probably isn't
better than what you've got now.

--
Neil Cerutti
Nov 13 '05 #10
Richard Heathfield wrote:

The Real OS/2 Guy wrote:

<snip>
for (; *r, r++) {
for (d = rom_dec; d->rom && *r != d->rom; d++) ; /* for body is
empty! */
if (!d->rom) {
printf("unable to convert %c\n", *r);
return EXIT_FAILTURE;
}
result += d->dec;
if (d->dec > last)
result -= 2*last;
last = this;
}

Not tested yet, but should work


On the contrary, the compiler will issue a diagnostic for this code, and
almost certainly refuse to provide a binary.

When I was in college, there was an interesting algorithm
for converting Roman numerals to ints. The jist of it is:
First convert the V's and I's at the end of the number to
a decimal digit. Then strip off the V's and I's from the
end of the string. Use a "translate" function to change
all X's to I's, all L's to V's, all C's to X's, etc.
Basically, this divides the Roman numeral by ten. Repeat
until the string containing the Roman numeral is empty...
(Of course, you have to accumulate the decimal digits
in the right order...)

--
+----------------------------------------------------------------+
| Charles and Francis Richmond richmond at plano dot net |
+----------------------------------------------------------------+
Nov 13 '05 #11
On Tue, 16 Sep 2003 19:17:55 UTC, Neil Cerutti <ho*****@yahoo.com>
wrote:
In article <bk**********@chessie.cirr.com>, Christopher Benson-Manica wrote:
The Real OS/2 Guy <os****@pc-rosenau.de> spoke thus:
for (; *r, r++) {
for (d = rom_dec; d->rom && *r != d->rom; d++) ; /* for body is
empty! */
if (!d->rom) {
printf("unable to convert %c\n", *r);
return EXIT_FAILTURE;
}
Is looping through a table more efficient than a switch
statement? (the code certainly looks cleaner)


I don't think there's much benefit to it over a big switch unless
the table allows lookup faster than linear time (O(n)).


It's more flexible. You have no change to the code when you have to
inert a new entry in the list. O.k. you may have to write a new
function to handle that entry - but not a bit to change existing code.
That reduces the possibility of errors.
You could do that with a table big enough to hold every valid
character value, or with a table sorted by char value, on which
you can use binary search.
You can sort the table by the probable frequency an entry may occure.
Again no codechande.
A linear search through the table, as above, probably isn't
better than what you've got now.

Any change of code increases the possibility to buid new bugs in.
Making code that is short, easy to maintenance and flexible increases
the maintencability, reduces problems and increases the useability.
--
Tschau/Bye
Herbert

eComStation 1.1 Deutsch Beta ist verügbar
Nov 13 '05 #12
In article <wmzsGguTDN6N-pn2-duTf38edoGtt@moon>, The Real OS/2
Guy wrote:
On Tue, 16 Sep 2003 19:17:55 UTC, Neil Cerutti <ho*****@yahoo.com>
wrote:
In article <bk**********@chessie.cirr.com>, Christopher
Benson-Manica wrote:
> The Real OS/2 Guy <os****@pc-rosenau.de> spoke thus:
>
>> for (; *r, r++) {
>> for (d = rom_dec; d->rom && *r != d->rom; d++) ; /* for body is
>> empty! */
>> if (!d->rom) {
>> printf("unable to convert %c\n", *r);
>> return EXIT_FAILTURE;
>> }
>
> Is looping through a table more efficient than a switch
> statement? (the code certainly looks cleaner)


I don't think there's much benefit to it over a big switch
unless the table allows lookup faster than linear time (O(n)).


It's more flexible. You have no change to the code when you
have to inert a new entry in the list. O.k. you may have to
write a new function to handle that entry - but not a bit to
change existing code. That reduces the possibility of errors.


That does not speak to the efficiency of the resulting code.
You could do that with a table big enough to hold every valid
character value, or with a table sorted by char value, on
which you can use binary search.


You can sort the table by the probable frequency an entry may
occure. Again no codechande.
A linear search through the table, as above, probably isn't
better than what you've got now.


Any change of code increases the possibility to buid new bugs
in. Making code that is short, easy to maintenance and flexible
increases the maintencability, reduces problems and increases
the useability.


Making code more maintainable and usable does make the code more
maintainable and usable. I agree! ;-)

--
Neil Cerutti
Nov 13 '05 #13
> > > Is looping through a table more efficient than a switch
statement? (the code certainly looks cleaner)


I don't think there's much benefit to it over a big switch unless
the table allows lookup faster than linear time (O(n)).


It's more flexible. You have no change to the code when you have to
inert a new entry in the list. O.k. you may have to write a new
function to handle that entry - but not a bit to change existing code.
That reduces the possibility of errors.

Dude there's not exactly going to be an extra letter added to the roman
numbering system :)
Nov 13 '05 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
by: Ivo | last post by:
Hi, An array contains elements of the form , for example IVa, XIXb, LIX and LXIVc. Does anyone have a function which can sort this array in a way a human would expect it to, with the roman letters...
9
by: level9 | last post by:
How can I convert roman numerals to intergers in c++ VS 6?
4
by: Patrick Blackman | last post by:
How do you write regular numbers eg 1 23 475896 in roman numerals inC#
7
by: daming23 | last post by:
Hi, I'm taking an online C++ class and having some difficulty understanding the assignments. Can someone please look at the code I wrote to ensure validity? I am not asking for the answer just some...
2
by: bluedemon | last post by:
I've written the program and it works fine. but my instructor said that i can make the program short and use functions in it, but i cant really understand functions that good. so i just need a little...
7
by: billbaitsg | last post by:
Hi, I need some help with figuring out why my program is all messed up. There are two portions two it, one that converts from roman to decimal (rom2dec) and another that converts from decimal to...
3
by: mookbooker | last post by:
I have a code written out with zero errors but i know my main() function is completely wrong and after i build the solution i compile it and nothing happens!! Not even cout statements please help. ...
22
by: kotlakirankumar | last post by:
please help me out the program for converting the integers to roman numerals using files in the c language from 1-5000 range send the program to my mail id ::::::: kotlakirankumar@gmail.com...
3
by: capoeira26 | last post by:
I have is that my entered Roman numerals work only if the numerlas are entered in large to smaller format. For exapmple if I type MMC program will correctly display 2100, but when I enter MCM it will...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.