I can't believe I got it that far at 5am in the morning lol.
Code:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <limits.h>
#include <assert.h>
#define UNUSED(x) (void)(x)
#define BIT_COUNT(x) (sizeof(x) * CHAR_BIT)
/* won't need more than 16 chars (+1 for null-byte) */
#define ROMAN_NUMERAL_BUFFER_SIZE 17
static const int numerals_len[9] = { 1, 2, 3, 2, 1, 2, 3, 4, 2 };
static const char *numerals[27] =
{
"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX",
"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC",
"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM",
};
uint32_t binstr_to_uint32(const char *bin)
{
uint32_t v = 0;
size_t e = strlen(bin);
while (e--)
{
assert(*bin == '0' || *bin == '1');
v += (*bin++ - '0') << e;
}
return v;
}
int uint32_to_binstr(uint32_t value, char *bin, size_t len)
{
size_t l = BIT_COUNT(value) - 1;
int flag = 0;
char *p = bin;
do
{
if (BIT_COUNT(value) - l - 1 >= len) return 0;
if ((value >> l) & 1) *p++ = '1', flag = 1;
else if (flag) *p++ = '0';
}
while (l-- > 0);
*p = 0;
return 1;
}
void bin_to_roman(const char *bin, char *roman)
{
uint32_t value = binstr_to_uint32(bin);
assert(value && value < 5000); /* roman numerals limit standard is 4999 */
while (value >= 1000) { *roman++ = 'M'; value -= 1000; }
if (value / 100)
{
strcpy(roman, numerals[(value / 100) + 17]);
roman += numerals_len[(value / 100) - 1];
value %= 100;
}
if (value / 10)
{
strcpy(roman, numerals[(value / 10) + 8]);
roman += numerals_len[(value / 10) - 1];
value %= 10;
}
if (value)
{
strcpy(roman, numerals[value - 1]);
roman += numerals_len[value - 1];
}
*roman = 0;
}
int roman_to_bin(const char *roman, char *bin, size_t len)
{
int i = 26, e = 100;
uint32_t value = 0;
while (*roman == 'M') { value += 1000; ++roman; }
while (i > -1)
{
if (strncmp(roman, numerals[i], numerals_len[i % 9]) == 0)
{
value += ((i % 9) + 1) * e;
roman += numerals_len[i % 9];
}
if (i-- % 9 == 0) e /= 10;
}
return uint32_to_binstr(value, bin, len);
}
int main(void)
{
uint32_t value;
char bin[BIT_COUNT(value) + 1];
char roman[ROMAN_NUMERAL_BUFFER_SIZE];
const int offset = 33;
const uint32_t limit = 4999;
for (uint32_t i = 1; i <= limit; ++i)
{
if (!uint32_to_binstr(i, bin, sizeof(bin)))
{
fputs("ERORR: uint32_to_binstr failed.\n", stderr);
return 1;
}
bin_to_roman(bin, roman);
printf("%*s -> %*s| ", offset, bin, offset, roman);
roman_to_bin(roman, bin, sizeof(bin));
printf("%*s -> %*s\n", offset, roman, offset, bin);
}
}
^ Tons of values to sample.