Enviar respuesta 
[TUT] Compresión de digitos
Autor Mensaje
meTaLiCroSS Sin conexión
Miembro Destacado


Buen Tutorial AMXX Support Pensador Trebol verde 1k
Mensajes: 1,420
Registro en: Oct 2013
Reputación: 52
Mensaje: #1
[TUT] Compresión de digitos
NOTA: Antes de dedicarte a leer lo que pondre en este tutorial, debes manejar bien toda la materia de los Bits, Bitsums y Operadores Bitwise.

Ya que no esta puesto como algo, y pocos saben al respecto, aqui les explicare como funciona la compresion de dígitos, o tambien conocido como packing.

Recalcaremos un par de cosas, las cuales nos serviran en el lapso del tema.

► En PAWN las variables creadas (pedorramente) utilizan 4 bytes, a excepcion de las catalogadas char.
1 byte equivale a 8 bits, lo que podria ser entendido a la ligera como 8 pequeñas casillas las cuales son o 0 o 1.
1 byte rellenado entero equivale a 255 (bin=11111111)

Ahora con estos 3 puntos recalcados, podrán entender la idea que postularé ahora. Les dare a mostrar el ejemplo más comun de packing.

Hagamos que tengo un array de 3 casillas, las cuales contienen un color RGB. Lo puedo demostrar de la siguiente forma.

Código PHP:
new iColor[3] = { 12864255 

Lo cual en binario se vería mostrado como si fuese:

Código:
iColor[0] -> 10000000
iColor[1] -> 01000000
iColor[2] -> 11111111

TIP: Usando de prefijo 0b estamos declarando un numero en binario. Esto nos ayudaría a redactarlo directamente como:

Código PHP:
new iColor[3] = { 0b100000000b010000000b11111111 

Pero ahora, intentaremos usar la menor cantidad de memoria y vamos a querer reducir esos 3 numeros. (ya que se ve enfermo de horrible tener 3 simples bloques de datos en tu super base de datos para solo guardar un podrido color.)

Conociendo los operadores >> , << , | e & y además recordando que una variable creada en pawn es un signed de 4 bytes, pasaremos ahora a la aplicacion.

Probaremos lo siguiente: Sabemos, que un color no puede valer más de 255. No es por magia o por algun hechizo de antaño, es simplemente porque es 1 byte relleno, y el computador los entiende asi.

Es por esto que un color RGB no tendrá más de 8 bits. En memoria, iColor se visualiza asi:


iColor[0]
00000000000000000000000010000000
iColor[1]
00000000000000000000000001000000
iColor[2]
00000000000000000000000011111111


En una simple variable usamos 8 bits, cuando tenemos 24 disponibles. ¡Podriamos perfectamente poner los otros 2 bytes en 1 variable! ¿Como?

Pues claro, si sabemos que cada uno ocupara 8 bits, peguemos los otros 2 delante de este. Partamos por el B de RGB, osea, iColor[2]. Crearemos una var auxiliar para ver el procedimiento paso a paso.

Código PHP:
new iPacked

iPacked
00000000000000000000000000000000


Añadamosle el B:

Código PHP:
iPacked iColor[2

iPacked
00000000000000000000000011111111


Genial, una asignacion sencilla. Pero el drama, es, como metemos los otros 2? Roflmao

Para eso existe el tan lerdo operador <<. Los primeros 8 espacios de iPacked estan siendo usados por el color B. Entonces, usaremos los 8 siguientes disponibles, moviendo 8 veces los bits a la izquierda. Usaremos el operador | para poder unir ambos contenidos.

Código PHP:
iPacked iPacked | (iColor[1] << 8

iPacked
00000000000000000000000011111111
iColor[1]
00000000000000000000000001000000
iColor[1] << 8
00000000000000000100000000000000 (lo que está en negrita, son los 8 bits saltados)
iPacked | (iColor[1] << 8)
00000000000000000100000011111111


¿Captas la idea?

La variable iPacked ahora esta usando 16 bits. Necesitamos guardar a R en la variable. Siendo que hay 16 bits ocupados, nos saltaremos esos mismo 16 bits para ocupar 8 de los 16 que estan desocupados. (16 desocupados, 16 libres, si, leiste bien)

Código PHP:
iPacked iPacked | (iColor[0] << 16

iPacked
00000000000000000100000011111111
iColor[0]
00000000000000000000000010000000
iColor[0] << 16
00000000100000000000000000000000
iPacked | (iColor[0] << 16)
00000000100000000100000011111111


Cutecry

Si lo pasamos por un convertidor, el resultado en decimal nos daria 8405247, pero eso no nos importa Yao ming

Evitando explicaciones, lo podemos hacer funcion facilmente.

Código PHP:
stock PackRGB(const iColors[3])
{
   
//      B               G                    R
   
return iColors[2] | (iColors[1]<<8) | (iColors[0]<<16)
}

// O también macro, para los fanaticos
#define PackRGB(%1) (%1[2] | (%1[1]<<8) | (%1[0]<<16)) 

Ahora que supimos comprimirlo, usaremos la misma ingenieria para descomprimirlo. Para esto solo se requiere imaginacion.

Si anteriormente, movimos a la izquierda y unimos, ahora moveremos a la derecha y quitamos. ¿Como?

Tenemos a iPacked como:


iPacked
00000000100000000100000011111111


Partamos por lo facil. Tenemos los 8 bits de B al principio.

11111111

Debemos separar este tramo del trozo entero. ¿Pero como?

Aqui es donde entramos con el operador &. El operador & o 'AND' retornara los bits que en ambos lados esten asignados. Si uno de los 2 lados no es 1, devolvera 0.

Es por eso que para poder sustraer todos los bits de un tramo, debemos preguntar crear la condicion necesaria. Debemos obtener todo posible bit en esa area, entonces: 1 byte rellenado = 255 = 0b11111111.

Pero se ve mejor expresado como 0xFF, en hexadecimal.


iPacked
00000000100000000100000011111111
0xFF
00000000000000000000000011111111
iPacked & 0xFF
00000000000000000000000011111111


Excellent. Ahora, debemos sustraer los otros 8 bits que quedan en iPacked. Pero ojo, los 8 bits del color B siguen ahí. Debemos mover los 8 bits de G a la derecha para sustraerlos como lo hicimos con B. Ahi es donde usamos el operador >> (a la derecha).

OJO: Al mover bits a un lado, si por alguna razon mueves una cierta cantidad que no encajasen, estos simplemente desaparecen.

Pero como ya obtuvimos los 8 primeros bits de iPacked, ya dan lo mismo. Podemos eliminarlos facilmente moviendo todo a la derecha.


iPacked
00000000100000000100000011111111
iPacked >> 8
00000000000000001000000001000000
0xFF
00000000000000000000000011111111
(iPacked >> 8) & 0xFF
00000000000000000000000001000000


Listo, ya tenemos a G. Falta R, usemos la misma ingenieria: Ya que los valores persisten en iPacked, ignoraremos a G y B moviendo 16 bits a la derecha, para que me queden los 8 bits de R al principio.


iPacked
00000000100000000100000011111111
iPacked >> 16
00000000000000000000000010000000
0xFF
00000000000000000000000011111111
(iPacked >> 16) & 0xFF
00000000000000000000000010000000


Voilà, tenemos a R, pero... ¿Te percataste que hay algo inutil en el ultimo procedimiento? Si, al hacer desaparecer los primeros 16 bits, quedan solo 8 bits. Entonces, ¿para que usamos & 0xFF si no iba a tener más de 8 bits?

Depende de que tipo de valores estes sacando. Si sabes que no habran mas bits, pues no lo utilices. Pero si por alguna extraña razon sabes que habra algun bit asignado despues de los 24 bits que deduces que forman un color, pues utilizalo. (y es probable quizas, porque los sobrantes 8 bits pueden ser usado como alpha, formando un color RGBA, pero es un por decir, por eso depende del caso)

Ya con todo explicado, procedamos a hacerlo funcion.

Código PHP:
stock UnpackRGB(iPackediOutcolor[3])
{
   
iOutcolor[2] = iPacked 0xFF
   iOutcolor
[1] = (iPacked >> 8) & 0xFF
   iOutcolor
[0] = (iPacked >> 16) & 0xFF


Lo explicado aqui es un ejemplo de esta manera de pensar. Otro buen ejemplo de esto, son las Direcciones IP que, mediante este mismo metodo (ya que sus rangos de valores son [0, 255] al igual que un color) pueden ser comprimidos.

La manera de realizar esto con cualquier cosa que queramos comprimir, es la siguiente.

1) Calcula/deduce el rango de valores que tendran esos valores, valga la redundancia. Si incluye valores negativos, incluye un bit extra (el cual estara en cada particion, este definira su signo)
2) Al decimal máximo posible que pueda contener cada valor, obten su potencia de 2 inferior más cercana (valor binario).
3) A este valor, calculale sus bits posibles.
4) Obten cuantos valores vas a comprimir. Si la cantidad de bits por valor, multiplicado la cantidad de valores, excede a 32, puedes partir por ver otro metodo, o usar otra variable.

Por ejemplo:

Tengo un Sistema de puntos, y sé que no pueden exceder los 500 puntos, y en si no pueden tener puntos negativos.

1) Rango de valores: [0, 500]
2) Mi decimal maximo es 500, esta entre los binarios 256 y 512, por lo que su potencia de 2 inferior más cercana vendria siendo 256.
3) 256 = 100000000, son 9 bits, los cuales rellenados (bin=111111111) son equivalentes a 511, es decir, que 500 puede encajar en 9 bits. (todo calza)
4) Son 3 valores los que quiero guardar (ej.: puntos de Kills, puntos de Precision, y puntos de Asistencia), osea, 9 bits * 3 = 27 bits, no superamos 32, estamos bien.

Código PHP:
ComprimirPuntos(iPuntosKillsiPuntosPrecisioniPuntosAsistencia)
{

   return 
iPuntosKills | (iPuntosPrecision<<9) | (iPuntosAsistencia<<18)
   
// 9*0, 9*1, y 9*2 respectivamente


ComprimirPuntos()
00000000000000000000000000000000
(rojo -> iPuntosAsistencia)
(verde -> iPuntosPrecision)
(azul -> iPuntosKills)



Descomprimiendo sería:

Código PHP:
DescomprimirPuntos(iCompresion, &iPuntosKills, &iPuntosPrecision, &iPuntosAsistencia)
{
   
// 9 bits rellenos = 511 = 0x1FF en hexadecimal
   
iPuntosKills iCompresion0x1FF
   iPuntosPrecision 
= (iCompresion>> 9) & 0x1FF
   iPuntosAsistencia 
= (iCompresion>> 18) & 0x1FF


Arte.

Para facilitarles el trabajo, utilizen este sitio como referencia. Sirve mucho para este tipo de cosas.

Espero cualquier respuesta sobre el tema. Me llevo un buen tiempo redactarlo bien y que sea entendible. Crab

(Este mensaje fue modificado por última vez en: 05/01/2017 02:18 AM por meTaLiCroSS.)
12/09/2014 04:42 AM
Encuentra todos sus mensajes Cita este mensaje en tu respuesta
alan_el_more Sin conexión
Miembro Destacado


Plugin developer
Mensajes: 986
Registro en: Oct 2013
Reputación: 16
Mensaje: #2
RE: [TUT] Compresión de digitos
Excelente aporte.
Hay pequeñas cosas que no entendí del todo pero será de volver a leerlo.

PD: Una cosa que nunca llegué a comprender del todo fue esto:
Código PHP:
DescomprimirPuntos(iCompresion, &iPuntosKills, &iPuntosPrecision, &iPuntosAsistencia

&iPuntosKills - &iPuntosPrecision...

¿Por qué se utiliza el signo & y cuando habría que usarlo?


Ni te molestes en enviarme un mensaje privado para pedirme ayuda porque NO lo voy a contestar.
Gracias por su atención.
12/09/2014 07:38 AM
Encuentra todos sus mensajes Cita este mensaje en tu respuesta
mongito100 Sin conexión
Miembro Héroe


El protector
Mensajes: 1,566
Registro en: Feb 2014
Reputación: 28
Mensaje: #3
RE: [TUT] Compresión de digitos
Es raro pero me puse a leer esto cuando estaba en una clase viendo como funciona la ALU como solo sabe sumar y . flotante. Me aburio menos leer esto
En fin buen tut no lo leí entero pero la idea de comprimir me gusta.Rainbow

[TUT] Carnage

Fight

"El limite de los backdoors de gente q sabe programar como nostros lo impone nuestra maldad interior y creeme q soy muy malo en el interior"

Anónimo
12/09/2014 09:47 AM
Encuentra todos sus mensajes Cita este mensaje en tu respuesta
Neeeeeeeeeel.- Sin conexión
Administrador


El protector Plugin developer 1k
Mensajes: 1,976
Registro en: Oct 2013
Reputación: 38
Mensaje: #4
RE: [TUT] Compresión de digitos
(12/09/2014 07:38 AM)alan_el_more escribió:  Excelente aporte.
Hay pequeñas cosas que no entendí del todo pero será de volver a leerlo.

PD: Una cosa que nunca llegué a comprender del todo fue esto:
Código PHP:
DescomprimirPuntos(iCompresion, &iPuntosKills, &iPuntosPrecision, &iPuntosAsistencia

&iPuntosKills - &iPuntosPrecision...

¿Por qué se utiliza el signo & y cuando habría que usarlo?
El & es para pasar una variable como referencia. Las variables no son mas que una referencia hacia las direcciones de memoria que almacenan el dato, cuando vos le pasas un parámetro a una función esta reserva un nuevo espacio de memoria para almacenar el dato, por ende cambia la referencia. Usando el operador & lo que hace es decirle a la función que utilize las mismas referencias a la memoria que el dato original. Cuando se utiliza la misma referencia, si cambiás el valor de la variable dentro de la función también afecta afuera.

Un pequeño ejemplo:
Código PHP:
public ejemplo1(){
    new 
5;
    new 
10;
    
ejemplo2(a,b);
    
console_print(0,"%d - %d"ab);
}
public 
ejemplo2(a,&b){
    
25;
    
50;

El output sería "5 - 50".

Metal, muy interesante el tuto, no se me había ocurrido.

No contesto mensajes privados pidiendo soporte!

Donaciones en btc 1EcNJV2gTFDYr7BBAFpMQk7pVCFEZCaKX4
(Este mensaje fue modificado por última vez en: 12/09/2014 10:02 AM por Neeeeeeeeeel.-.)
12/09/2014 10:00 AM
Visita su sitio web Encuentra todos sus mensajes Cita este mensaje en tu respuesta
KISKE Sin conexión
Miembro Sr.


Plugin developer AMXX Support Medalla de aportes
Mensajes: 418
Registro en: May 2014
Reputación: 22
Mensaje: #5
RE: [TUT] Compresión de digitos
Me gustó mucho, ya no más putos parses para separar los datos de un mismo campo!

Muchas gracias y muy bien redactado!
12/09/2014 10:12 AM
Encuentra todos sus mensajes Cita este mensaje en tu respuesta
alan_el_more Sin conexión
Miembro Destacado


Plugin developer
Mensajes: 986
Registro en: Oct 2013
Reputación: 16
Mensaje: #6
RE: [TUT] Compresión de digitos
(12/09/2014 10:00 AM)Neeeeeeeeeel.- escribió:  El & es para pasar una variable como referencia. Las variables no son mas que una referencia hacia las direcciones de memoria que almacenan el dato, cuando vos le pasas un parámetro a una función esta reserva un nuevo espacio de memoria para almacenar el dato, por ende cambia la referencia. Usando el operador & lo que hace es decirle a la función que utilize las mismas referencias a la memoria que el dato original. Cuando se utiliza la misma referencia, si cambiás el valor de la variable dentro de la función también afecta afuera.

Un pequeño ejemplo:
Código PHP:
public ejemplo1(){
    new 
5;
    new 
10;
    
ejemplo2(a,b);
    
console_print(0,"%d - %d"ab);
}
public 
ejemplo2(a,&b){
    
25;
    
50;

El output sería "5 - 50".

Gracias Nelson. Con esto, preguntando y buscando, lo pude entender.
Estaría bueno que alguien más conocido en el tema, haga un tutorial porque es un tema que mucho no vi acá ni en AM.


Ni te molestes en enviarme un mensaje privado para pedirme ayuda porque NO lo voy a contestar.
Gracias por su atención.
12/09/2014 12:57 PM
Encuentra todos sus mensajes Cita este mensaje en tu respuesta
Neeeeeeeeeel.- Sin conexión
Administrador


El protector Plugin developer 1k
Mensajes: 1,976
Registro en: Oct 2013
Reputación: 38
Mensaje: #7
RE: [TUT] Compresión de digitos
(12/09/2014 12:57 PM)alan_el_more escribió:  Gracias Nelson. Con esto, preguntando y buscando, lo pude entender.
Estaría bueno que alguien más conocido en el tema, haga un tutorial porque es un tema que mucho no vi acá ni en AM.
Pasa que no es mucho mas de lo que yo comenté, ahí termina la cosa... me parece algo demasiado simple como para armar un tutorial.

No contesto mensajes privados pidiendo soporte!

Donaciones en btc 1EcNJV2gTFDYr7BBAFpMQk7pVCFEZCaKX4
12/09/2014 01:16 PM
Visita su sitio web Encuentra todos sus mensajes Cita este mensaje en tu respuesta
roccoxx Sin conexión
Miembro Destacado


Plugin developer Trebol purpura 1k
Mensajes: 1,159
Registro en: Oct 2013
Reputación: 18
Mensaje: #8
RE: [TUT] Compresión de digitos
gracias por el tutorial, creo que tengo que recodear un poco mi mod Whatever

futuro ingeniero agrónomo.

tutoriales-allied
buscas un zp?

"La imitación es la forma más sincera de admiración con la que puede pagar la mediocridad a la grandeza"

volví a vender plugins, contactame
12/09/2014 02:04 PM
Encuentra todos sus mensajes Cita este mensaje en tu respuesta
meTaLiCroSS Sin conexión
Miembro Destacado


Buen Tutorial AMXX Support Pensador Trebol verde 1k
Mensajes: 1,420
Registro en: Oct 2013
Reputación: 52
Mensaje: #9
RE: [TUT] Compresión de digitos
Ahi edité un pequeño error de tipeo en el tut. Gracias por los comentarios

12/09/2014 02:23 PM
Encuentra todos sus mensajes Cita este mensaje en tu respuesta
Metrikcz Sin conexión
Miembro Destacado


Plugin developer
Mensajes: 827
Registro en: Oct 2013
Reputación: 19
Mensaje: #10
RE: [TUT] Compresión de digitos
Buen tutorial Gran sonrisa

Me ha quedado una duda dices que en una variable contiene 8 bytes lo cual es equivalente a 64 bits, de donde sacas que ipacket tiene 24 o porque tiene 24 ceros?

Todos los MODS VHL totalmente gratuitos Descarga Aqui

Mis plugins:
FB: fb.com/rwoong
Venta plugins a pedido en México mándame MP
12/09/2014 04:31 PM
Encuentra todos sus mensajes Cita este mensaje en tu respuesta
Enviar respuesta 


Salto de foro:


Usuario(s) navegando en este tema: 1 invitado(s)

Contáctanos | Allied Modders en español | Volver arriba | Volver al contenido | Archivo (Modo simple) | Sindicación RSS