¿Cómo convertir un valor entero a una cadena de números romanos?

5 minutos de lectura

avatar de usuario
Vishwanath Dalvi

¿Cómo puedo convertir un número entero a su representación de cadena en números romanos en C?

  • A menos que trabajes para la NFL, esto tiene que ser tarea, ¿no?

    – jason

    13 de febrero de 2011 a las 20:03

  • Bueno, no lanzando la tarea en SO y esperando el código;)

    usuario395760

    13 de febrero de 2011 a las 20:03

  • @delnan: aparentemente funciona de todos modos 🙂

    – 6502

    13 de febrero de 2011 a las 20:27

  • @Jason, o algún proyecto de localización se está pasando un poco de la raya

    – Martín Beckett

    13 de febrero de 2011 a las 20:47

  • @jason search.cpan.org/~dconway/Lingua-Romana-Perligata-0.50/lib/…

    – Martín Beckett

    14 de febrero de 2011 a las 2:17

avatar de usuario
paxdiablo

La forma más fácil es probablemente configurar tres matrices para los casos complejos y usar una función simple como:

// convertToRoman:
//   In:  val: value to convert.
//        res: buffer to hold result.
//   Out: n/a
//   Cav: caller responsible for buffer size.

void convertToRoman (unsigned int val, char *res) {
    char *huns[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
    char *tens[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
    char *ones[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
    int   size[] = { 0,   1,    2,     3,    2,   1,    2,     3,      4,    2};

    //  Add 'M' until we drop below 1000.

    while (val >= 1000) {
        *res++ = 'M';
        val -= 1000;
    }

    // Add each of the correct elements, adjusting as we go.

    strcpy (res, huns[val/100]); res += size[val/100]; val = val % 100;
    strcpy (res, tens[val/10]);  res += size[val/10];  val = val % 10;
    strcpy (res, ones[val]);     res += size[val];

    // Finish string off.

    *res="\0";
}

Esto manejará cualquier número entero sin signo, aunque los números grandes tendrán una gran cantidad de M caracteres al frente y la persona que llama debe asegurarse de que su búfer sea lo suficientemente grande.

Una vez que el número se ha reducido por debajo de 1000, es una simple búsqueda de 3 tablas, una para cada una de las centenas, decenas y unidades. Por ejemplo, tome el caso donde val es 314.

val/100 sera 3 en ese caso entonces el huns la búsqueda de matriz dará CCCluego val = val % 100 te dio 14 Para el tens buscar.

Luego val/10 sera 1 en ese caso entonces el tens la búsqueda de matriz dará Xluego val = val % 10 te dio 4 Para el ones buscar.

Luego val sera 4 en ese caso entonces el ones la búsqueda de matriz dará IV.

eso te da CCCXIV por 314.


Una versión de verificación de desbordamiento de búfer es un simple paso adelante desde allí:

// convertToRoman:
//   In:  val: value to convert.
//        res: buffer to hold result.
//   Out: returns 0 if not enough space, else 1.
//   Cav: n/a

int convertToRoman (unsigned int val, char *res, size_t sz) {
    char *huns[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
    char *tens[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
    char *ones[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
    int   size[] = { 0,   1,    2,     3,    2,   1,    2,     3,      4,    2};

    //  Add 'M' until we drop below 1000.

    while (val >= 1000) {
        if (sz-- < 1) return 0;
        *res++ = 'M';
        val -= 1000;
    }

    // Add each of the correct elements, adjusting as we go.

    if (sz < size[val/100]) return 0;
    sz -= size[val/100];
    strcpy (res, huns[val/100]);
    res += size[val/100];
    val = val % 100;

    if (sz < size[val/10]) return 0;
    sz -= size[val/10];
    strcpy (res, tens[val/10]);
    res += size[val/10];
    val = val % 10;

    if (sz < size[val) return 0;
    sz -= size[val];
    strcpy (res, ones[val]);
    res += size[val];

    // Finish string off.

    if (sz < 1) return 0;
    *res="\0";
    return 1;
}

aunque, llegados a ese punto, podría pensar en refactorizar el procesamiento de centenas, decenas y unidades en una función separada, ya que son muy similares. Lo dejaré como un ejercicio extra.

avatar de usuario
j. andres shusta

no utilice un mapa pre-calculado sissy para los casos difíciles.

/* roman.c */
#include <stdio.h>

/* LH(1) roman numeral conversion */
int RN_LH1 (char *buf, const size_t maxlen, int n)
{
  int S[]  = {    0,   2,   4,   2,   4,   2,   4 };
  int D[]  = { 1000, 500, 100,  50,  10,   5,   1 };
  char C[] = {  'M', 'D', 'C', 'L', 'X', 'V', 'I' };
  const size_t L = sizeof(D) / sizeof(int) - 1;
  size_t k = 0; /* index into output buffer */
  int i = 0; /* index into maps */
  int r, r2;

  while (n > 0) {
    if (D[i] <= n) {
      r = n / D[i];
      n = n - (r * D[i]);
      /* lookahead */
      r2 = n / D[i+1];
      if (i < L && r2 >= S[i+1]) {
        /* will violate repeat boundary on next pass */
        n = n - (r2 * D[i+1]);
        if (k < maxlen) buf[k++] = C[i+1];
        if (k < maxlen) buf[k++] = C[i-1];
      }
      else if (S[i] && r >= S[i]) {
        /* violated repeat boundary on this pass */
        if (k < maxlen) buf[k++] = C[i];
        if (k < maxlen) buf[k++] = C[i-1];
      }
      else
        while (r-- > 0 && k < maxlen)
          buf[k++] = C[i];
    }
    i++;
  }
  if (k < maxlen) buf[k] = '\0';
  return k;
}

/* gcc -Wall -ansi roman.c */
int main (int argc, char **argv)
{
  char buf[1024] = {'\0'};
  size_t len;
  int k;
  for (k = 1991; k < 2047; k++)
  {
    len = RN_LH1(buf, 1023, k);
    printf("%3lu % 4d %s\n", len, k, buf);
  }
  return 0;
}

en realidad no necesitas declarar S cualquiera. debería ser fácil ver por qué.

    static string ConvertToRoman(int num)
    {
        int d = 0;
        string result = "";
        while (num > 0)
        {
            int n = num % 10;
            result = DigitToRoman(n, d) + result;
            d++;
            num = num / 10;
        }
        return result;
    }
    static string DigitToRoman(int n, int d)
    {
        string[,] map = new string[3, 3] { { "I", "V", "X" }, { "X", "L", "C" }, { "C", "D", "M" } };
        string result="";
        if (d <= 2)
        {
            switch (n)
            {
                case 0:
                    result = "";
                    break;
                case 1:
                    result = map[d, 0];
                    break;
                case 2:
                    result = map[d, 0] + map[d, 0];
                    break;
                case 3:
                    result = map[d, 0] + map[d, 0] + map[d, 0];
                    break;
                case 4:
                    result = map[d, 0] + map[d, 1];
                    break;
                case 5:
                    result = map[d, 1];
                    break;
                case 6:
                    result = map[d, 1] + map[d, 0];
                    break;
                case 7:
                    result = map[d, 1] + map[d, 0] + map[d, 0];
                    break;
                case 8:
                    result = map[d, 1] + map[d, 0] + map[d, 0] + map[d, 0];
                    break;
                case 9:
                    result = map[d, 0] + map[d, 2];
                    break;
            }
        }
        else if (d == 3 && n < 5)
        {
            while (--n >= 0)
            {
                result += "M";
            }
        }
        else
        {
            return "Error! Can't convert numbers larger than 4999.";
        }
        return result;
    }

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad