Foros - Stratos

Programadores => Código de la Semana => Mensaje iniciado por: ethernet en 23 de Febrero de 2003, 05:28:07 PM

Título: Parser hexadecimal - CordayUK
Publicado por: ethernet en 23 de Febrero de 2003, 05:28:07 PM




typedef unsigned long DW;   //es lo mismo que el DWORD definido en windows.h



inline unsigned char __CHAR2BYTE (unsigned char c)

{

  switch (c)

  {

     case '0': return 0x0;

     case '1': return 0x1;

     case '2': return 0x2;

     case '3': return 0x3;

     case '4': return 0x4;

     case '5': return 0x5;

     case '6': return 0x6;

     case '7': return 0x7;

     case '8': return 0x8;

     case '9': return 0x9;

     case 'A': return 0xA;

     case 'B': return 0xB;

     case 'C': return 0xC;

     case 'D': return 0xD;

     case 'E': return 0xE;

     case 'F': return 0xF;

  }

  return 0x0;

}



DW GetValueDW (char* pszValue)

{

DW dw = 0x00000000;





  //comprobar cadena

  if (!pszValue || strlen (pszValue)<8) return dw;



  //meter en el dword cada char de la cadena

  for (short int i=0; i<8; i++)

     dw = dw | (0x00000000 | __CHAR2BYTE (*(pszValue+i))<< (28-(i*4)));



  return dw;

}







Título: Parser hexadecimal - CordayUK
Publicado por: fiero en 23 de Febrero de 2003, 07:15:35 PM
                                Yo propondria un par de mejoras.

Que la función __CHAR2DW devuelva un DW, para evitarnos después la conversión (eso de hacer un | 0x00000000).

También almacenar la longitud de la cadena para poder convertir cadenas más cortas. Por ejemplo, poder escribir en el archivo "AABB" en vez de "0000AABB", si queremos guardar el numero 0x0000AABB

un saludo

typedef unsigned long DW;   //es lo mismo que el DWORD definido en windows.h



inline DW __CHAR2DW (unsigned char c)

{

  switch (c)

  {

     case '0': return 0x0;

     case '1': return 0x1;

     case '2': return 0x2;

     case '3': return 0x3;

     case '4': return 0x4;

     case '5': return 0x5;

     case '6': return 0x6;

     case '7': return 0x7;

     case '8': return 0x8;

     case '9': return 0x9;

     case 'A': return 0xA;

     case 'B': return 0xB;

     case 'C': return 0xC;

     case 'D': return 0xD;

     case 'E': return 0xE;

     case 'F': return 0xF;

  }

  return 0x0;

}



DW GetValueDW (char* pszValue)

{

  DW dw = 0x00000000;

  int num;



  //comprobar cadena

  if (!pszValue || (num=strlen (pszValue))>8) return dw;



  //meter en el dword cada char de la cadena

  for (int i=0; i<num; i++)

     dw = dw | __CHAR2DW(pszValue[i]) << ((num-i-1)*4);



  return dw;

}
                               
Título: Parser hexadecimal - CordayUK
Publicado por: Juan Mellado en 23 de Febrero de 2003, 10:32:38 PM
El uso de los índices dentro del bucle se puede simplificar un poco:



  for (int i = 0; i<num; ++i)

     dw = (dw << 4) | __CHAR2DW(pszValue[i]);

Título: Parser hexadecimal - CordayUK
Publicado por: fiero en 23 de Febrero de 2003, 11:10:33 PM
                                Ahá! , en cierto modo, es más lógico ir desplazando el resultado como  FIFO y meter el siguiente dígito siempre en la 1º posición. Si es que a veces nos complicamos la vida.... :)

un saludo                                
Título: Parser hexadecimal - CordayUK
Publicado por: Zaelsius en 23 de Febrero de 2003, 11:52:02 PM
                                Bueno, pues aquí está mi version de la rutina SUPER-OPTIMIZADA  :D





// Aquí está la clave :-D



#define __CHAR2BYTE(c)    ((c) >= '0' && (c) <= '9' ? (c) - '0' : (c) - 55 )



DWORD GetValueDW (char* pszValue)

{

DWORD dw = 0x00000000;



if (!pszValue || strlen (pszValue)<8) return dw;



// Bucle desenrrollado

dw = dw |  __CHAR2BYTE (*(pszValue))<< (28);

dw = dw |  __CHAR2BYTE (*(pszValue+1))<< (24);

dw = dw |  __CHAR2BYTE (*(pszValue+2))<< (20);

dw = dw |  __CHAR2BYTE (*(pszValue+3))<< (16);

dw = dw |  __CHAR2BYTE (*(pszValue+4))<< (12);

dw = dw |  __CHAR2BYTE (*(pszValue+5))<< (8);

dw = dw |  __CHAR2BYTE (*(pszValue+6))<< (4);

dw = dw |  __CHAR2BYTE (*(pszValue+7));



return dw;

}





¡A ver que tal os parece!                                
Título: Parser hexadecimal - CordayUK
Publicado por: fiero en 23 de Febrero de 2003, 11:59:25 PM
                                Todavia se puede optimizar más  :ojo: :

#define __CHAR2BYTE(c)    ((c) > '9' ? (c) - 'A' : (c) - '0' )

un saludo                                
Título: Parser hexadecimal - CordayUK
Publicado por: Zaelsius en 24 de Febrero de 2003, 12:03:48 AM
Joer fiero, no me has dejado ni editar el post en un momento....XD
¿Pues quedaría algo así, no?



// Mega optimized XD

#define __CHAR2BYTE(c)    ((c) > '9' ? (c) - 'A' : (c) - '0' )



DWORD GetValueDW (char* pszValue)

{

DWORD dw = 0x00000000;



if (!pszValue || strlen (pszValue)<8) return dw;



dw = (dw << 4) |  __CHAR2BYTE (pszValue[0]);

dw = (dw << 4) |  __CHAR2BYTE (pszValue[1]);

dw = (dw << 4) |  __CHAR2BYTE (pszValue[2]);

dw = (dw << 4) |  __CHAR2BYTE (pszValue[3]);

dw = (dw << 4) |  __CHAR2BYTE (pszValue[4]);

dw = (dw << 4) |  __CHAR2BYTE (pszValue[5]);

dw = (dw << 4) |  __CHAR2BYTE (pszValue[6]);

dw = (dw << 4) |  __CHAR2BYTE (pszValue[7]);



return dw;

}

Título: Parser hexadecimal - CordayUK
Publicado por: fiero en 24 de Febrero de 2003, 12:52:50 AM
                                ups, perdón ZaelSiuS, mi  - 'A' está mal, tu -55 primero está bien                                
Título: Parser hexadecimal - CordayUK
Publicado por: CordayUK en 24 de Febrero de 2003, 04:34:19 AM
                                Donde os mando las mujeres y el vino?????? XDDDDD

muchas gracias, me mola la optimizacion. Ya sabia yo que se podia hacer mejor!!! thx                                
Título: Parser hexadecimal - CordayUK
Publicado por: Zaelsius en 24 de Febrero de 2003, 04:58:51 PM
Y ya para rematar el COTW me he marcado un pequeño programa que testea las dos funciones(original y optimizada).

Lo podeis bajar de aquí:
http://www.alu.ua.es/j/jgf8/files/download...d/getdwtest.zip

A mí me saca un 520% de rendimiento más la funcion optimizada( en un Athlon 1600+).

El código de test es casi todo de un artículo de Game Programming Gems 2.

¡Que aproveche!
Título: Parser hexadecimal - CordayUK
Publicado por: ethernet en 24 de Febrero de 2003, 06:48:32 PM
No rularia mas rapido con una tabla asi ->

char tabla[256];

tabla['1'] = 1;
tabla['2'] = 2;
..
..
tabla['A'] = 10;

desperdicias memoria pero mola XD.
Despues de hacer eso usar

#define __CHAR2BYTE©    tabla[c];



es una idea, quizas sea mas rapido hacer lo q haceis vosotros q usar la memoria para ello.

NOTA: las funciones q proponeis NO hacen los mismo q la de corday...
EDIT: error, mire el codigo de fiero del numero de caracteres exacto 0:DDD, lo siento XD

saludos
Título: Parser hexadecimal - CordayUK
Publicado por: ethernet en 24 de Febrero de 2003, 07:03:54 PM
Ejem, he mirado el codigo para probar la rapidez y no seria mejor tener:

__int64 cuentatiempo(void (*fn)(dword )); ?

el programa de contar el tiempo si  q lo optimizaba yo XDD

saludos
Título: Parser hexadecimal - CordayUK
Publicado por: Juan Mellado en 24 de Febrero de 2003, 11:59:04 PM
                                Je, je, como nos picamos.  :D

Ethernet, lo de las tablas está bien para CPUs sin problemas de caché y todas esas cosistas.

"Ofuscando" un poco el código se evita además las rotaciones:



unsigned char odd[]  = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,

                       0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

                       0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};



unsigned char even[] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,

                       0x80, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

                       0x00, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0};



#define __CHAR_ODD(c)  ( (odd - '0')[c])

#define __CHAR_EVEN(c) ( (even -'0')[c])



DWORD GetValueDW(char * pszValue)

{

  DWORD dw = 0x00000000;

 

  if ( !pszValue || strlen(pszValue) < 8) return dw;



  ( (char *)(&dw) )[3] = __CHAR_EVEN(pszValue[0]) | __CHAR_ODD(pszValue[1]);

  ( (char *)(&dw) )[2] = __CHAR_EVEN(pszValue[2]) | __CHAR_ODD(pszValue[3]);

  ( (char *)(&dw) )[1] = __CHAR_EVEN(pszValue[4]) | __CHAR_ODD(pszValue[5]);

  ( (char *)(&dw) )[0] = __CHAR_EVEN(pszValue[6]) | __CHAR_ODD(pszValue[7]);

   

  return dw;

}



El siguiente paso podría ser crear tablas con WORD y DWORD desplazando un byte cada vez.  Pero no merece la pena dedicarle más tiempo, como se suele decir: "hay que preocuparse en optimizar lo que realmente necesite ser optimizado". Aunque dedicarle un rato a pesar en cosas como esta es divertido, ¿verdad?.

Venga, buenas noches                                
Título: Parser hexadecimal - CordayUK
Publicado por: fiero en 25 de Febrero de 2003, 03:11:16 PM
                               
CitarAunque dedicarle un rato a pesar en cosas como esta es divertido, ¿verdad?.

Si, divertido e instructivo, por eso es recomendable empezar a hacer comecocos y cosas así en modo texto, porque se aprende realmente a programar con estas cosas sencillitas...

un saludo                                
Título: Parser hexadecimal - CordayUK
Publicado por: ethernet en 25 de Febrero de 2003, 06:46:17 PM
Muy c00l el ecodigo juan, q procesadores tienen problemas de cpu actualmente, en cuales no entran 256 bytes? o menos en el caso de tus tablas.
de todas maneras dudo cual de los metodos es mas rapido, si el de las tablas o el propuesto por zaelsius,

pd: todavia me estoy tirando de los pelos del codigo para probar la velocidad ... los de programming gems no tienen ni zorra de lo q es diseñar o q? XD

saludos
Título: Parser hexadecimal - CordayUK
Publicado por: Zaelsius en 26 de Febrero de 2003, 12:35:30 PM
El artículo en cuestión del Programming Gems 2 era sobre el uso de optimizaciones al usar floats y tablas de senos, etc. Ahora no tengo el libro, pero creo que era de un tal Yossarian King, programador de EA en canadá(creo).

Aunque últimamente no me gustan mucho la política de videojuegos de EA...
Título: Parser hexadecimal - CordayUK
Publicado por: Interlink en 03 de Marzo de 2003, 09:42:45 PM
                                Hola. Creo que el problema de convertir un string que representa un valor
hexadecimal a su correspondiente valor numérico ha quedado bastante claro en el foro, de todas formas aquí os envio mi pequeña aportación que supongo sería útil.

He partido de la idea de la composición numérica de base-n, basada en la
sucesión: c1*b^0 + c2*b^2 + .... + ci*b^(i-1)
Luego he creado dos versiones de la función, una recursiva que es más lenta pero mas reducida y otra no recursiva. El código es el siguiente:




#include <iostream.h>

#include <string.h>



#define __CHAR2BYTE(c)    ((c) >= '0' && (c) <= '9' ? (c) - '0' : (c) - 55)



typedef unsigned long DWORD;



DWORD power16(int i){

     if (i==0) return 1;

     return 16*power16(i-1);

}



DWORD recursiva(char *str, int i, int c = 0){

     DWORD hex_val = __CHAR2BYTE(str[c]);

     if (i==1) return hex_val;

     return hex_val*power16(i-1)+recursiva(str,i-1,c+1);

}



DWORD nopower16(int i){

     DWORD power = 1;

     for (int n=0;n<i;n++)

           power*=16;

     return power;

}



DWORD norecursiva(char *str,int i){

DWORD hex_delta = 0,hex_val;

for (int n=i-1;n>=0;n--){

 hex_val = __CHAR2BYTE(str[n]);

 hex_delta+=hex_val*nopower16(i-n-1);

}

return hex_delta;

}



int main(int argc, char* argv[])

{

      cout << "Valor decimal(R):" << recursiva(argv[1],strlen(argv[1]));

      cout << "nValor decimal(NR):" << norecursiva(argv[1],strlen(argv[1]));

      return 0;

}



                               
Título: Parser hexadecimal - CordayUK
Publicado por: Mars Attacks en 03 de Marzo de 2003, 09:47:33 PM
                                Curiosa forma de presentarse ;) Bienvenido seas XD                                
Título: Parser hexadecimal - CordayUK
Publicado por: Interlink en 03 de Marzo de 2003, 10:22:40 PM
                                                               
Título: Parser hexadecimal - CordayUK
Publicado por: Interlink en 03 de Marzo de 2003, 10:30:07 PM
                               
Cita de: "Interlink"Gracias Mars!  :ojo:
Título: Parser hexadecimal - CordayUK
Publicado por: Mars Attacks en 04 de Marzo de 2003, 12:35:00 AM
                                Cuando te he saludado aún no habías puesto tu código. Antes me caías bien, ahora me caes mejor XD
Alguien que no teme a la recursividad es un tío serio. Aunque creo que con algún problema con ¿el navegador? a la hora de poner posts :)                                
Título: Optimización
Publicado por: Interlink en 04 de Marzo de 2003, 11:35:29 AM
                                Mars, no conocía muy bien el editor!  :I  
Esta versión recursiva es más optimizada aún ya que los desplazamientos
consumen menos ciclos de CPU.



DWORD recursiva(char *str, int i){

     if (i==1) return __CHAR2BYTE(str[i-1]);

     return (__CHAR2BYTE(str[i-1]) | recursiva(str,i-1)<<4);

}



Un saludo                                
Título: Parser hexadecimal - CordayUK
Publicado por: CordayUK en 07 de Marzo de 2003, 07:57:33 PM
                                COOL !