C++ converting base 10 to Roman numerals

  • Thread starter Math Is Hard
  • Start date
  • Tags
    Base C++
In summary, the programmer is trying to convert base 10 to Roman numerals, but can't seem to figure out how to make a loop to handle the repetition. They suggest an auxilliary array to store the constants, and then write a function to do the conversion.
  • #36
What's "normal"? And waddaya mean longer? You're not going to charge me for the "amenities", are you?
:smile:
 
Physics news on Phys.org
  • #37
MMDCDXLVIV is correct for 2949.

Point is, my algorithm is inherently simpler than yours.
 
  • #38
2949=MMCMXLIX
 
  • #39
Bartholomew said:
Point is, my algorithm is inherently simpler than yours.

uh oh. them sounds like fightin' words..
 
  • #40
Bartholomew said:
Point is, my algorithm is inherently simpler than yours.

But I thought now we're going for tricky. :cry: :cry: :cry:
 
  • #41
According to that page on roman numerals, IX is incorrect... you can't have a I and then an X, it skips the V, the same reason IMM is incorrect.
 
  • #42
Math Is Hard said:
uh oh. them sounds like fightin' words..
See what you started! o:) o:)
 
  • #43
gnome said:
See what you started! o:) o:)
I know. Mea culpa.
If it's any consolation I think I failed spectacularly on the C++ midterm today. Guess what was on the test - converting to Roman f'ing numerals! :cry: I couldn't remember anything. I was like a deer in the headlights I was so scared.
 
  • #44
I didn't study that page, but I'm sure that 9 is generally written IX and not VIV.
 
  • #45
On the other hand, it's a lot more fun than studying for an exam on computabilty, complexity, etc. -- which is what I should be doing. :devil: :devil:

I'll check back later to see what Bartholomew comes up with.
 
  • #46
My algorithm is the best. Given an integer, look up its string representation in a table of strings. :smile:
 
  • #47
Well, as I said, I don't have a c++ compiler. So rather than translate this into C++ and hope I didn't make any syntax errors in doing so, I'll just post it in Java, which I wrote it in. (No user input here since that takes several lines in Java)
Code:
class RomanNumeral{
	public static void main (String argv[])
	{
		int num, i, ii;
		int cD[] = {1000, 500, 100, 50, 10, 5, 1};
		int c[] = new int[7];
		String cs = "MMMDDDCCCLLLXXXVVVIII";
		num = 2949;
		for(i=-1;i<6;c[++i]=num/cD[i],num%=cD[i]);
		for(i=0;i<7;i++)
			System.out.print(c[i]!=4||i==0?cs.substring(i*3,i*3+c[i]):""+
					cs.charAt(i*3)+cs.charAt(i*3-1));
	}
}
 
  • #48
Bartholomew said:
I'll just post it in Java
Oh no! Now everyone's posting condensed code samples in random languages – this thread is turning into the Obfuscated Roman Numeral Programming Competition... :tongue2:

In Python (this more-or-less does what I outlined earlier (rather inefficiently :wink:); I think it's also a version of Hurkyl's method):
Code:
from sys import stdout
r = 'IVXLCDM'
print 'Decimal to Roman numeral conversions'
print 'Enter an integer 1-9999, press return or enter a non-integer to exit'
try:
    while True:
        n = int(raw_input('Your number? '))
        while (n<1) or (n>9999): n = int(raw_input('Bad number!\nYour number? '))
        if n > 999: stdout.write('M'*(n/1000))
        n = str(n % 1000)
        for (c1,c5,c10),d in [(r[i:i+3], int(n[-(i/2+1)])) for i in xrange((2*len(n)-2),-1,-2)]:
            stdout.write(['', c1, c1*2, c1*3, c1+c5, c5, c5+c1, c5+c1*2, c5+c1*3, c1+c10][d])
        stdout.write('\n')
except ValueError:
    print 'Bye!'
Batholomew said:
According to that page on roman numerals, IX is incorrect... you can't have a I and then an X, it skips the V, the same reason IMM is incorrect.
From the page linked by Integral:
The subtracted number must be no less than a tenth of the value of the number it is subtracted from. So an X can be placed to the left of a C or an L but not to the left of an M or a D.
In other words, 90 = XC not LXL, and thus 9 = IX not VIV. Just look at the page of conversions at Integral's link.
 
  • #49
You (Bartholomew) have disappointed me. :frown: :frown:

It's a few characters shorter than mine (ignoring the user chit-chat), but it's still wrong. Yes, your algorithm is simpler, but only because the language that it recognizes is simpler and as a result it fails to handle 9, 90 and 900 correctly.

Why did you think that 9 = VIV and 90 is LCL?

The Wolfram page that MathIsHard posted
http://mathworld.wolfram.com/RomanNumerals.html
clearly indicates that 9=IX and and 90=XC.

If you look at page "9" (roman-numbered) of the preface of any textbook, or the production date of any 20th century movie you'll see ix and MCM...

Bartholomew said:
According to that page on roman numerals, IX is incorrect... you can't have a I and then an X, it skips the V, the same reason IMM is incorrect.
What page were you referring to?
 
  • #50
If you don't have a Java SDE, here's a _tentative_ translation into C++. Probably this doesn't work, but hopefully you'll be able to correct the error if that's the case. (it won't be a logic error, it does work in Java) I also refined the code slightly while translating, to shave off an additional few characters and further complicate that beautiful cout of mine :rofl: .

Code:
#include <iostream>
int main(){
	int num, i;
	int cD[] = {1000, 500, 100, 50, 10, 5, 1};
	int c[7];
	string cs = "IIIVVVXXXLLLCCCDDDMMM";
	cin >> num;
	for(i=-1;i<6;c[++i]=num/cD[i],num%=cD[i]);
	for(i=6;i>-1;i--)
		cout<<(c[6-i]!=4||i==6?cs.substr(i*3,c[6-i]):cs.substr(i*3+2,2));
	return 0;
}
 
  • #51
Oh, I didn't see you had posted--took me a while to do that translation. 1 moment.

Edit: Okay, you raise a valid point. I will think about how best to modify my method to do 9's, 90s, and 900s correctly. It will still be very short though.
 
Last edited:
  • #52
Alright, let me have a shot at this:

Code:
#include <iostream>
#include <cstdio>

using namespace std;

int main(int argc, char **argv)         {
	int *input = new int();
	int *rom = new int[7];
	int *steps = new int[6];
	char *map = new char[7];
	*map = 'M'; *(map+1)='D'; *(map+2)='C'; *(map+3)='L'; *(map+4)='X';
	*(map+5)='V'; *(map+6)='I';

	printf("Please enter the number that must be converted: ");
	scanf("%i", input);
	
	*rom = *input / 1000;
	*(rom + 1) = (*steps = *input % 1000) / 500;
	*(rom + 2) = (*(steps+1) = *steps % 500) / 100;
	*(rom + 3) = (*(steps+2) = *(steps+1) % 100) / 50;
	*(rom + 4) = (*(steps+3) = *(steps+2) % 50) / 10;
	*(rom + 5) = (*(steps+4) = *(steps+3) % 10) / 5;
	*(rom + 6) = (*(steps+4) % 5);
	
	printf("Here is your number in Roman numerals: ");
	for (register int i = 0; i < 6; i++) {
		for (register int k = 0; k < *(rom + i); k++) printf("%c", *(map + i));
	};

	switch(*(rom+6))	{
		case 1: printf("%s", "I"); break;
		case 2: printf("%s", "II"); break;
		case 3: printf("%s", "III"); break;
		case 4: printf("%s", "IV"); break;
		default: break;	};

	return 0;				}

Please compile Multi-threaded! :biggrin:

PS: Don't be hatin' on the printf! :smile:
 
Last edited by a moderator:
  • #53
Interesting, but not correct:

Please enter the number that must be converted: 1999
Here is your number in Roman numerals: MDCCCCLXXXXVIV

3 errors: DCCCC for 900, LXXXX for 90, VIV for 9


Edit: What's the "multithreaded" comment about?
 
  • #54
Ah crap, didn't notice that. Awesome beta testing on your part.

I meant, if your compiler supports it (I think all compilers nowadays do), like gcc 3.4.x, compile it for Multi-threaded mode (to support Intel Hyper-Threading!) and notice the performance difference. I believe the code is significantly faster if it runs multithreaded.


Btw, I found this rather succint piece of code (I'm quite sure it works) http://home.att.net/~srschmitt/script_roman.html . I feel a JScript to C/C++ conversion is in order. :tongue2:
 
Last edited by a moderator:
  • #55
freemind said:
Btw, I found this rather succint piece of code (I'm quite sure it works) http://home.att.net/~srschmitt/script_roman.html . I feel a JScript to C/C++ conversion is in order. :tongue2:
That's no good -- it's not obfuscated at all! :tongue: :tongue:

Here's my latest effort. It's not as short as I'd hoped it would be, but I think it's cute:
Code:
#include <iostream>
#include <string>
#include <math.h>
using namespace std;         // added this line for MSVC 6.0
#define LTRS "MDCLXVI"
int iter[]={9,5,4};
void build(int& val, int p, string& s){
    int r = (int)pow(10,p);
    while(val>=r){
        val -= r;
    s += LTRS[6-2*p];
    }
}
void trim(string t, int i, int j, string &s){
    int ind = s.find(t,0);
    string tt;
    if (j!=1)
        tt += LTRS[2*i+2];
    j == 0 ? tt += LTRS[2*i] : tt += LTRS[2*i+1];
    if (ind >=0)
       s.replace(ind, iter[j], tt);
}
int main(){
    int i, j, k, p, dec;
        string t, roman;
    cout << "Enter integer to be translated:\n";
    cin >> dec;
    for(p = 3; p >=0; p--)
        build(dec, p, roman);
    for(i = 0; i < 3; i++) {
        for (j = 0; j < 3; j++) {
            t.erase();
            for(k = 0; k < iter[j]; k++)
                t += LTRS[2*i+2];
            trim(t,i,j,roman);
        }
    }
    cout << roman.c_str() << endl;            // edited for MSVC 6.0
    return 0;
}
 
Last edited by a moderator:
  • #56
I kinda half-understand your algorithm (it's very complex), but compiling it on Microsoft Visual C++ 7.0 and running in debug mode gives garbled output. :yuck:
Did it give the correct lettering on your system?

P.S: AFAIK, the string class doesn't have operator overloading support for << (@ least not in the MSVC++ 7.0 implementation), which means 'cout << roman << endl;' threw tantrums. I had to change that to 'printf("%s", &roman);', but I doubt that's the cause of the messed result.
 
  • #57
Sorry, it worked fine in my old Dev-C++ (mingw compiler).

It also works fine in with my g++ compiler, but for that one I had to add "using namespace std;" so I edited my previous post to add that line.

I also made a small change to that final cout so now it compiles and runs correctly in MSVC 6. I don't know about MSVC 7.

Funny thing is, I have MSVC7 (I think). A few months ago I bought a student copy of Visual Studio .net but never used it. So now I'm trying, and DAMN if I can't figure out how to compile ANYTHING with it. So far all I seem to have here is the world's most complicated editor. There's buttons for everything under the sun, but no "compile", no "build", no "run". How the heck do I get this thing to do something useful? :grumpy: :grumpy: :grumpy:
 
Last edited:
  • #58
It works perfectly now!

I know what you mean. MSVC++.NET isn't exactly a quick-and-dirty superfast development IDE. But for large programs that use a lot of custom-built libraries, it is priceless. As for the compile, build and run buttons, it is quite silly that they don't exist in the default view. I simply use the shortcut Ctrl+Shift+B to build, and F5 to run (debug). Still, having used Borland C++ :yuck: , Dev-C++ (it took forever to compile, I don't know why), and gcc/g++, I would still say that Microsoft makes the best compilers/IDEs around. Then again, I'm also known to be a M$-fanboy. :smile:

Kudos to gnome for a fine piece of code!
 
  • #59
Okay, here is my masterpiece!

Code:
#include <iostream>
int main(){
	string s = "IIIVIXXXLXCCCDCMMM";
	int n, c[] = {1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000};
	cin>>n;
	for(int i=12; i>-1;n%=c[i], i--)
		cout<<(n/c[i]>0?s.substr(i+(i+3)/4,i%4?(i-2)%4?2:1:n/c[i]):"");
}
:rofl: :rofl: Hopefully I translated this into C++ right; it does work in Java. If you can't get it to work I'll post the Java code which is a little longer.
 
Last edited:
  • #60
Beautiful. I changed it slightly, adding "#include<string>", changed "String" to "string", and "cin >> n"; instead of your constant n.
Code:
#include <iostream>
#include <string>
int main(){
	string s = "IIIVIXXXLXCCCDCMMM";
	int n, c[] = {1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000};
	cin >> n;
	for(int i=12; i>-1;n%=c[i], i--)
		cout<< (n/c[i]>0 ? s.substr(i+(i+3)/4, i%4 ? (i-2)%4 ? 2 : 1 : n/c[i]) : "");
}

edit: Oh, I see you already made two of those changes.

(But what if I have more than 3999 olives to count?) :tongue:


I've never seen a compound conditional statement like that. Is is just composed from the inside out, i.e.:
n/c>0 ? ( s.substr(i+(i+3)/4, [ i%4 ? [ (i-2)%4 ? 2 : 1] : n/c ] ) ) : ""
 
Last edited:
  • #61
If you want to count more than 3999, you would use parentheses around letters as explained at http://mathworld.wolfram.com/RomanNumerals.html. You wouldn't write MMMM. 4000 would be written M(V)

Edit: Or you could add a vinculum by using 2 lines of output and an underscore.

If for some reason you want to use more than 3 M's, you can just add more M's at the end of string s.

Yes, that's how the conditional statement works.
 
Last edited:

Similar threads

  • Programming and Computer Science
Replies
22
Views
2K
  • MATLAB, Maple, Mathematica, LaTeX
Replies
3
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
3
Views
871
  • Programming and Computer Science
Replies
3
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
10
Views
1K
  • Introductory Physics Homework Help
Replies
7
Views
664
  • Engineering and Comp Sci Homework Help
Replies
2
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
3
Views
1K
  • Introductory Physics Homework Help
Replies
6
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
5
Views
1K
Back
Top