dcsimg
Results 1 to 2 of 2

Thread: Too Late for Contest 8, Roman Numeral Converter - [Milk]

  1. #1

    Thread Starter
    Cumbrian Milk's Avatar
    Join Date
    Jan 2007
    Location
    0xDEADBEEF
    Posts
    2,448

    Too Late for Contest 8, Roman Numeral Converter - [Milk]

    I realise this is too late for the competition. I hope its still okay to be shown together with the other entries once they have been assessed.
    Code:
    #include <stdio.h>
    #include <ctype.h>
    #include <string.h>
    
    enum
    {
    	ILLEGAL = -2,
    	WHITESPACE = -1,
    	DIGIT = 0,
    
    	MAX_NUMBER = 5000,
    	MAX_CHARACTERS = 17, // 'MMMMDCCCLXXXVIII\0' (including null)
    };
    
    const char chars[] = "MDCLXVI";
    char buf[MAX_CHARACTERS];
    int lut[256];
    
    const char* dec2roman(int n)
    {
    	if (n > MAX_NUMBER)
    		return 0;
    
    	char * p = buf;
    	unsigned m, d = 1000, i = 0;
    
    	// special handling for 'M' allowing numbers > 3999
    	n -= (m = n / d) * d;
    	while (m--)
    	{
    		*p++ = chars[i];
    	}
    
    	// main loop
    	while (n)
    	{
    		while (n < d)
    		{
    			i += 2;
    			d /= 10u;
    		}
    		m = n / d;
    		n -= m * d;
    
    	
    	start_of_switch:
    		switch (m)
    		{
    		case 9: 
    			*p++ = chars[i];
    			*p++ = chars[i - 2];
    			break;
    		
    		case 8:	
    		case 7:	
    		case 6: 
    		case 5:
    			m -= 5;
    			*p++ = chars[i - 1];
    			goto start_of_switch; // reassess m 
    
    		case 4: 
    			*p++ = chars[i];
    			*p++ = chars[i - 1];
    			break;
    		
    		case 3:	// drop through...
    			*p++ = chars[i];
    		case 2: 
    			*p++ = chars[i];
    		case 1:	
    			*p++ = chars[i];
    		}
    
    	}
    	*p++ = '\0';
    
    	return buf;
    }
    
    inline int parse_char(int& character, int& value)
    {
    	character = getchar();
    	value = lut[character & 255];
    	return value;
    }
    
    void parse_number(int& character, int& value)
    {
    	int ct = 0;
    	int n = character - '0';
    	while (parse_char(character, value) == DIGIT)
    	{
    		n = n * 10 + character - '0';
    		++ct;
    	}
    
    	if (value != WHITESPACE)
    		value = ILLEGAL;
    	else if( ct > 5 || n > MAX_NUMBER)
    		fputs("OVERFLOW\n",stderr);
    	else		
    		puts(dec2roman(n));
    }
    
    void parse_roman(int& character, int& value)
    {	
    	char buf[MAX_CHARACTERS];
    	int i = 0, n = value, old = value;
    	buf[0] = toupper(character);
    
    	while (parse_char(character, value) > DIGIT && ++i < MAX_CHARACTERS)
    	{
    		buf[i] = toupper(character);
    		n += old < value ? value - 2 * old : value;
    		old = value;
    	}
    	if (++i < MAX_CHARACTERS)
    		buf[i] = '\0';
    
    	if (value != WHITESPACE)
    		value = ILLEGAL;
    	else if (n > MAX_NUMBER)
    		fputs("OVERFLOW\n",stderr);
    	else if (strcmp(dec2roman(n), buf) != 0)
    		fputs("BAD NUMERAL\n", stderr);
    	else
    		printf("%d\n", n);
    }
    
    
    int main()
    {
    	puts("Enter one or more numbers or numerals separated by spaces.\nHit Ctrl-C to quit.\n");
    
    	// build look up table
    	// mark illegal, whitespace and digit characters 
    	for (int i = 0; i < 256; ++i)
    		lut[i] = isspace(i) ? WHITESPACE : isdigit(i)? DIGIT : ILLEGAL;
    
    	// mark tens "MCXI" 1000, 100, 10, 1 
    	for (int i = 0, v= 1000; i < sizeof(chars)-1; i += 2, v /= 10)
    		lut[chars[i]] = lut[tolower(chars[i])] = v;
    
    	// mark halfs "DLV" 500, 50, 5
    	for (int i = 1, v = 500; i < sizeof(chars)-1; i += 2, v /= 10)
    		lut[chars[i]] = lut[tolower(chars[i])] = v;
    
    	int c, v;
    	parse_char(c, v);
    	do
    	{
    		switch (v)
    		{
    		case ILLEGAL:
    			fputs("BAD PARSE\n", stderr);
    			while (parse_char(c, v) != WHITESPACE); // eat non whitespace
    			// drop through...
    		case WHITESPACE:			
    			while (parse_char(c, v) == WHITESPACE); // eat whitespace
    			break;
    
    		case DIGIT:
    			parse_number(c, v);
    			break;
    
    		default: //must be numeral
    			parse_roman(c, v);
    			break;
    		} 
    
    	} while (c != EOF);
    
    	return 0;
    }
    roman_numerals.zip
    W o t . S i g

  2. #2
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    9,544

    Re: Too Late for Contest 8, Roman Numeral Converter - [Milk]

    Thanks for the submission! Try for the next contest too.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width