Autor Tema: Concurso de programación: números romanos  (Leído 8007 veces)

0 Usuarios y 3 Visitantes están viendo este tema.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Concurso de programación: números romanos
« en: 28 de Mayo de 2013, 04:11:05 »
Hola amigos, he organizado un concurso de programación en MicroPIC en el que estaré encantado de que participéis, cuantos más mejor.

El objetivo es en diseñar el algoritmo más rápido de conversión a números romanos.

¡SUERTE!

http://www.micropic.es/mpblog/2013/05/primer-concurso-de-programacion-micropic-numeros-romanos/

Desconectado samshiel_pic

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 777
    • Electrónica·Ingenia
Re: Concurso de programación: números romanos
« Respuesta #1 en: 28 de Mayo de 2013, 09:08:46 »
 ((:-)) Voy a intentarlo, paisano!! buena idea de concurso para animar el foro en su cumple!!

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Concurso de programación: números romanos
« Respuesta #2 en: 28 de Mayo de 2013, 11:56:53 »
Yo no utilizo Proteus ni CCS, por lo que no puedo poner la captura de pantalla, pero aquí está mi código:
A ver si alguien se ofrece a compilarlo y probarlo.


Código: [Seleccionar]
#define PUTCH(c)  {while (!txif);  txreg = c; }

void ConvierteARomano(int16 Numero) {        
   int8 Num;
   if (Numero>>8) {
      while (Numero >= 1000) {
         PUTCH('M');
         Numero -= 1000;
      }
      if (Numero >= 900) {
         PUTCH('C');
         PUTCH('M');
         Numero -= 900;
      }
      if (Numero >= 500) {
         PUTCH('D');
         Numero -= 500;
      }
      if (Numero >= 400) {
         PUTCH('C');
         PUTCH('D');
         Numero -= 400;
      }
      while(Numero>>8) {
         PUTCH('C');
         Numero -= 100;
      };
   }
   Num = Numero;
   while(Num >= 100) {
      PUTCH('C');
      Numero -= 100;
   };
   if (Num >= 90) {
      PUTCH('X');
      PUTCH('C');
      Num -= 90;
   }
   if (Num >= 50) {
      PUTCH('L');
      Num -= 50;
   }
   if (Num >= 40) {
      PUTCH('X');
      PUTCH('L');
      Num -= 40;
   }
   while(Num >= 10) {
      PUTCH('X');
      Num -= 10;
   };
   if (Num >= 9) {
      PUTCH('I');
      PUTCH('X');
      Num -= 90;
   }
   if (Num >= 5) {
      PUTCH('V');
      Num -= 5;
   }
   if (Num >= 4) {
      PUTCH('I');
      PUTCH('V');
      Num -= 4;
   }
   while(Num > 0) {
      PUTCH('I');
      Num--;
   }  
}

El truco para optimizar mi algoritmo está en comenzar a transmitir cuanto antes el primer caracter.
Una vez que se está transmitiendo un caracter a 9600baud, tenemos tiempo suficiente para realizar los cálculos del siguiente caracter.

Saludos.
« Última modificación: 28 de Mayo de 2013, 12:00:32 por Picuino »

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Concurso de programación: números romanos
« Respuesta #3 en: 28 de Mayo de 2013, 13:01:16 »
Lo he probado y no funciona, Picuino.
Lo hace bien con el número 54, pero al convertir el 1238 sale una M seguida de infinitas C

Para poder compilarlo en CCS he tenido que modificar el define que tenías por este otro:
#define PUTCH(c)  putc(c)

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Concurso de programación: números romanos
« Respuesta #4 en: 28 de Mayo de 2013, 13:13:56 »
No conozco bien cómo acceder a los registros TXIF y TXREG en CCS, pero la idea es ahorrar un salto a putch(c) para ser más rápido.

Voy a intentar corregirlo.

Mientras tanto se me ha ocurrido otra idea para ahorrar pulsos: pasar al micro a idle después de enviar un caracter (el timer dejará de contar pulsos) y despertarle con la interrupción de la usart cuando termine de enviar el caracter.

Saludos.

P.D. Gracias por compilarlo Nocturno

« Última modificación: 28 de Mayo de 2013, 13:26:06 por Picuino »

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Concurso de programación: números romanos
« Respuesta #5 en: 28 de Mayo de 2013, 13:32:41 »
Así es como se usan los registros en CCS, pero se queda parado sin imprimir nada.

#byte PIR1=0xF9E
#bit txif=PIR1.4
#byte txreg=0xFAD
#define PUTCH(c)  {while(!txif);txreg=c;}

El truco que comentas para alterar el Timer es interesante, pero no haría más rápido al algoritmo, sólo falsearía el recuento del timer.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Concurso de programación: números romanos
« Respuesta #6 en: 28 de Mayo de 2013, 13:38:19 »
El código tenía dos erratas.
Este está probado en un compilador de c y funciona.

Código: [Seleccionar]
void ConvierteARomano(int16 Numero) {
   unsigned char Num;

   if (Numero>>8) {
      while (Numero >= 1000) {
         PUTCH('M');
         Numero -= 1000;
      }
      if (Numero >= 900) {
         PUTCH('C');
         PUTCH('M');
         Numero -= 900;
      }
      if (Numero >= 500) {
         PUTCH('D');
         Numero -= 500;
      }
      if (Numero >= 400) {
         PUTCH('C');
         PUTCH('D');
         Numero -= 400;
      }
      while(Numero>>8) {
         PUTCH('C');
         Numero -= 100;
      };
   }
   Num = Numero;
   while(Num >= 100) {
      PUTCH('C');
      Num -= 100;
   };
   if (Num >= 90) {
      PUTCH('X');
      PUTCH('C');
      Num -= 90;
   }
   if (Num >= 50) {
      PUTCH('L');
      Num -= 50;
   }
   if (Num >= 40) {
      PUTCH('X');
      PUTCH('L');
      Num -= 40;
   }
   while(Num >= 10) {
      PUTCH('X');
      Num -= 10;
   };
   if (Num >= 9) {
      PUTCH('I');
      PUTCH('X');
      Num -= 9;
   }
   if (Num >= 5) {
      PUTCH('V');
      Num -= 5;
   }
   if (Num >= 4) {
      PUTCH('I');
      PUTCH('V');
      Num -= 4;
   }
   while(Num > 0) {
      PUTCH('I');
      Num--;
   }
}

Habría que definir PUTCH(c) como una macro muy rápida que compruebe TXIF y escriba TXREG. En C18 se hace asi:
#define PUTCH(c)  {while (PIR1bits.TXIF == 0);   TXREG = c; }

Nocturno: probablemente no funciona porque la primera vez hay que forzar TXIF a uno:


Saludos.
« Última modificación: 28 de Mayo de 2013, 13:47:43 por Picuino »

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Concurso de programación: números romanos
« Respuesta #7 en: 28 de Mayo de 2013, 13:45:21 »
txif hay que forzarlo a uno antes del programa principal. Este es el programa completo:

Código: [Seleccionar]
#include <18F458.h>
#device adc=16

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES OSCSEN                   //Oscillator switching is enabled
#FUSES PUT                      //Power Up Timer
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#use delay(clock=8000000)

#use rs232(baud=9600,XMIT=PIN_C6)
#include <string.h>

int16 ListaNumeros[10]={54,1238,41,2500,640,99,1,999,1001,2666};

int16 Contador=0;


#byte PIR1=0xF9E
#bit txif=PIR1.4
#byte txreg=0xFAD
#define PUTCH(c)  { while(txif==0); txreg=c; }

void ConvierteARomano(int16 Numero) {
   unsigned char Num;

   if (Numero>>8) {
      while (Numero >= 1000) {
         PUTCH('M');
         Numero -= 1000;
      };
      if (Numero >= 900) {
         PUTCH('C');
         PUTCH('M');
         Numero -= 900;
      }
      if (Numero >= 500) {
         PUTCH('D');
         Numero -= 500;
      }
      if (Numero >= 400) {
         PUTCH('C');
         PUTCH('D');
         Numero -= 400;
      }
      while(Numero>>8) {
         PUTCH('C');
         Numero -= 100;
      };
   }
   Num = Numero;
   while(Num >= 100) {
      PUTCH('C');
      Num -= 100;
   };
   if (Num >= 90) {
      PUTCH('X');
      PUTCH('C');
      Num -= 90;
   }
   if (Num >= 50) {
      PUTCH('L');
      Num -= 50;
   }
   if (Num >= 40) {
      PUTCH('X');
      PUTCH('L');
      Num -= 40;
   }
   while(Num >= 10) {
      PUTCH('X');
      Num -= 10;
   };
   if (Num >= 9) {
      PUTCH('I');
      PUTCH('X');
      Num -= 9;
   }
   if (Num >= 5) {
      PUTCH('V');
      Num -= 5;
   }
   if (Num >= 4) {
      PUTCH('I');
      PUTCH('V');
      Num -= 4;
   }
   while(Num > 0) {
      PUTCH('I');
      Num--;
   };
}


#INT_TIMER1
void Incrementa_Contador() {
   Contador++;
}

void main()
{
   int i;
   int16 Duracion;
  
   setup_timer_1 ( T1_INTERNAL);


   printf ("Primer concurso de programacion. NUMEROS ROMANOS\n\r");
   printf ("www.micropic.es\n\r\n\r");
   set_timer1(0);
   enable_interrupts(INT_TIMER1);
   enable_interrupts(GLOBAL);

   txif = 1;   // Reset de la USART

   for (i=0;i<10;i++) {
      printf ("%LU = ",ListaNumeros[i]);
      ConvierteARomano(ListaNumeros[i]);
      printf ("\n\r");
   }
   Duracion=get_timer1();
   printf ("Ha tardado %LU ticks\n\r",make32(Contador,Duracion));
   while(TRUE);

}


Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Concurso de programación: números romanos
« Respuesta #8 en: 28 de Mayo de 2013, 13:47:41 »
Pues sigue pasando lo mismo, no imprime. Pero es posible que se trate de un bug de Proteus, no me fío mucho.

Si quieres, lo dejo con el putc, que al menos imprimía, aunque falla al traducir el número 1238.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Concurso de programación: números romanos
« Respuesta #9 en: 28 de Mayo de 2013, 13:51:51 »
 :shock: esta vez no sé porqué falla.
en mi compilador de c el 1238 lo traduce como MCCXXXVIII

Puede que esté relacionado con la asignación a Num del byte bajo de Numero. ¿Quizás hay que definir Num como un unsigned int8?

Si no funciona, pon el putch(), aunque va a ser mucho más lento.

Gracias por compilarlo.

Saludos.
« Última modificación: 28 de Mayo de 2013, 13:54:09 por Picuino »

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Concurso de programación: números romanos
« Respuesta #10 en: 28 de Mayo de 2013, 13:54:38 »
Tienes razón, el algoritmo ya funciona, no había leído tu comentario de las dos erratas.
Pero para imprimir he tenido que usar el putc.

Aquí dejo la captura de pantalla provisional, si consigo resolver lo del tratamiento de registros volveré a informar.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Concurso de programación: números romanos
« Respuesta #11 en: 28 de Mayo de 2013, 14:09:19 »
Así es como lo compila CCS.
....................          PUTCH('C');
00F4:  BTFSS  F9E.4
00F6:  BRA    00F4
00F8:  MOVLW  43
00FA:  MOVWF  FAD
....................          PUTCH('M');
00FC:  BTFSS  F9E.4
00FE:  BRA    00FC
0100:  MOVLW  4D
0102:  MOVWF  FAD

Se queda enganchado en el BTFSS y BRA. Se ve que el bit no cambia de valor.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Concurso de programación: números romanos
« Respuesta #12 en: 28 de Mayo de 2013, 14:20:48 »
No creo que se pueda mejorar.

Esas instrucciones equivalen a lo que yo quería hacer.


y he conseguido un buen tiempo  :-/

Saludos.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Concurso de programación: números romanos
« Respuesta #13 en: 28 de Mayo de 2013, 14:24:49 »
No, esas instrucciones es como compila tu código original, pero no funciona en la simulación.
El tiempo que has conseguido en la captura de pantalla que antes adjunté está logrado con putc.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Concurso de programación: números romanos
« Respuesta #14 en: 28 de Mayo de 2013, 14:29:26 »
Bueno, por ahora sólo queda que alguien aporte uno mejor  ;-)


Saludos