[TUT] Compresión de digitos
#1
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
Responder
#2
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.
Responder
#3
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
Responder
#4
(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.
[Imagen: paypalqr.png]
Responder
#5
Me gustó mucho, ya no más putos parses para separar los datos de un mismo campo!

Muchas gracias y muy bien redactado!
Responder
#6
(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.
Responder
#7
(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.
[Imagen: paypalqr.png]
Responder
#8
gracias por el tutorial, creo que tengo que recodear un poco mi mod Whatever
Ingeniero agrónomo y desarrollador de Software.

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"

Merci Alliedmodders pour m'introduire dans la programmation.
Responder
#9
Ahi edité un pequeño error de tipeo en el tut. Gracias por los comentarios
Responder
#10
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:
STEAM: https://steamcommunity.com/id/Metrikcz/
FB: fb.com/rwoong
Venta plugins a pedido en México mándame MP
Responder
#11
Edite ahí, creo que es normal confundir la simplesa de que te enrredas solo con decir 8 bits y 8 bytes Roflmao una variable contendra 4 bytes, 4*8 bits, 32 bits, ahi esta bien

EDIT: @alan_el_more, lo que preguntaste en si, es lo mismo que las variables de referencia en C. Si lees el manual, verás que es lo mismo que dijo pelotuneeeel.
Responder
#12
Osea
"En una simple variable usamos 8 bits, cuando tenemos 24 disponibles"

Te contradices me dices que tiene 32 bits pero en el tut hay 24 disponibles que pasa con el ultimo byte
Todos los MODS VHL totalmente gratuitos  Descarga Aqui

Mis plugins:
STEAM: https://steamcommunity.com/id/Metrikcz/
FB: fb.com/rwoong
Venta plugins a pedido en México mándame MP
Responder
#13
*Contando los 8 bits* quedarian 24. A eso referia.
Responder
#14
Bueno tuto; la parte de descomprimir me quedo muy poco jaja.

Saludos
NUEVO ZOMBIE PLAGUE + LVLS!! UNETE A LA COMUNIDAD
[Imagen: b_350_20_ffad41_e98100_000000_591f11.png]


Responder
#15
(14/09/2014, 07:30 PM)Evil Spiret escribió: Bueno tuto; la parte de descomprimir me quedo muy poco jaja.

Saludos

¿Que no captaste?
Responder
#16
(14/09/2014, 07:30 PM)Evil Spiret escribió: Bueno tuto; la parte de descomprimir me quedo muy poco jaja.

Saludos
Si entendiste lo de comprimir, descomprimir es lo mismo pero al revez... es el proceso inverso.
[Imagen: paypalqr.png]
Responder
#17
Ahhahh mi cabeza, muchos numeros, bits, ect... Dafuq

P.D: Buen tutorial, tal vez algun dia lo entienda y lo use Whatever
Responder
#18
(15/09/2014, 09:24 PM)Heber[$]ource escribió: Ahhahh mi cabeza, muchos numeros, bits, ect... Dafuq

P.D: Buen tutorial, tal vez algun dia lo entienda y lo use Whatever
Si no entendiste postea que no entendiste, no nos importa saber si no lo entendiste, sino porque no lo entendiste. Sino nunca lo vas a enteder xd
(19/06/2014, 11:08 PM)01011001 escribió: No tiene niveles infinitos, llega hasta 2147483648 (Y despues hace un integer overflow)

(19/06/2014, 11:08 PM)[R]ak escribió: Mis conocimientos aumentaron un 500% con este post
Responder
#19
(15/09/2014, 09:24 PM)Heber[$]ource escribió: Ahhahh mi cabeza, muchos numeros, bits, ect... Dafuq

P.D: Buen tutorial, tal vez algun dia lo entienda y lo use Whatever

Esto es muy basico e incluso te lo enseñan en la escuela.
Si no lo entiendes todo puedes buscar en google:
- Desplazamiento de bits u operadores de desplazamiento
- Operadores logicos u operadores de asignacion
- Conversion entre bases (binario, ternario, octal, hexadecimal, etc)
- UTF8 encoding
- Y si no me equivoco IEEE 745
Hi [R]ak CrabCrab
Responder
#20
(15/09/2014, 10:08 PM)Milashkasiya escribió:
(15/09/2014, 09:24 PM)Heber[$]ource escribió: Ahhahh mi cabeza, muchos numeros, bits, ect... Dafuq

P.D: Buen tutorial, tal vez algun dia lo entienda y lo use Whatever

Esto es muy basico e incluso te lo enseñan en la escuela.
Si no lo entiendes todo puedes buscar en google:
- Desplazamiento de bits u operadores de desplazamiento
- Operadores logicos u operadores de asignacion
- Conversion entre bases (binario, ternario, octal, hexadecimal, etc)
- UTF8 encoding
- Y si no me equivoco IEEE 745

Velo en partes donde no se enseña nada sobre operaciones binarias o informaticas. Por lo menos aquí en Chile no, y lo unico que necesitas asi como lo explique en el mismo tema, es saber sobre Bits, Bitsums y Operadores Bitwise (<<, >>, &, |, ~, ^), el resto es pan al horno, no hace falta tanta cabeza para leer tanta cantidad de cosas.

La idea es compartir conocimiento, no encararlo
Responder
#21
(15/09/2014, 10:26 PM)meTaLiCroSS escribió:
(15/09/2014, 10:08 PM)Milashkasiya escribió:
(15/09/2014, 09:24 PM)Heber[$]ource escribió: Ahhahh mi cabeza, muchos numeros, bits, ect... Dafuq

P.D: Buen tutorial, tal vez algun dia lo entienda y lo use Whatever

Esto es muy basico e incluso te lo enseñan en la escuela.
Si no lo entiendes todo puedes buscar en google:
- Desplazamiento de bits u operadores de desplazamiento
- Operadores logicos u operadores de asignacion
- Conversion entre bases (binario, ternario, octal, hexadecimal, etc)
- UTF8 encoding
- Y si no me equivoco IEEE 745

Velo en partes donde no se enseña nada sobre operaciones binarias o informaticas. Por lo menos aquí en Chile no, y lo unico que necesitas asi como lo explique en el mismo tema, es saber sobre Bits, Bitsums y Operadores Bitwise (<<, >>, &, |, ~, ^), el resto es pan al horno, no hace falta tanta cabeza para leer tanta cantidad de cosas.

La idea es compartir conocimiento, no encararlo
El tipo no entendio nada, de que le sirve leer el tutorial si no sabe las conversiones entre bases, ademas de los otros puntos. Todo lo que sugeri es para que pueda entenderlo bien porque de esos puntos estas hablando en tu tutorial.
Hi [R]ak CrabCrab
Responder
#22
(15/09/2014, 10:32 PM)Milashkasiya escribió:
(15/09/2014, 10:26 PM)meTaLiCroSS escribió:
(15/09/2014, 10:08 PM)Milashkasiya escribió:
(15/09/2014, 09:24 PM)Heber[$]ource escribió: Ahhahh mi cabeza, muchos numeros, bits, ect... Dafuq

P.D: Buen tutorial, tal vez algun dia lo entienda y lo use Whatever

Esto es muy basico e incluso te lo enseñan en la escuela.
Si no lo entiendes todo puedes buscar en google:
- Desplazamiento de bits u operadores de desplazamiento
- Operadores logicos u operadores de asignacion
- Conversion entre bases (binario, ternario, octal, hexadecimal, etc)
- UTF8 encoding
- Y si no me equivoco IEEE 745

Velo en partes donde no se enseña nada sobre operaciones binarias o informaticas. Por lo menos aquí en Chile no, y lo unico que necesitas asi como lo explique en el mismo tema, es saber sobre Bits, Bitsums y Operadores Bitwise (<<, >>, &, |, ~, ^), el resto es pan al horno, no hace falta tanta cabeza para leer tanta cantidad de cosas.

La idea es compartir conocimiento, no encararlo
El tipo no entendio nada, de que le sirve leer el tutorial si no sabe las conversiones entre bases, ademas de los otros puntos. Todo lo que sugeri es para que pueda entenderlo bien porque de esos puntos estas hablando en tu tutorial.

Y es normal que no entienda nada (lo que no es normal es que lo haya posteado), yo no entendi al pie de la letra los bits ni con 3 tutoriales encima Roflmao fue con el tiempo donde empeze a jugar como enano con ellos, e imaginate que no tengo idea de UTF8 Encoding ni de la notacion IEEE 745, y vez lo que escribi. No todos parten con la misma capacidad, no lo digo por mi, pero hay que ser más suave
Responder
#23
Buenas! Metal, me quedo una duda con respecto al tema de unpacking, paso a citar esta parte

Cita: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
00000000000000000000000001000000

Si al hacer el primer movimiento (iPacked >> 8), el valor previo a ese movimiento seria: 00000000100000000100000011111111
y el valor posterior: 00000000000000001000000001000000

Si hasta ahora estoy en lo correcto, cuando haces (iPacked >> 16) estarias cometiendo un error, ya que lo desplazas 16 lugares, por ende quedaria todo en 0, no deberia desplazarse 8 lugares nuevamente?? Ya que actualmente tenemos lo siguiente:
00000000000000001000000001000000
Si lo desplazo 8 lugares, me quedaria lo siguiente, o no? 00000000000000000000000010000000

Bueno, espero que se haya entendido a lo que me refiero metal, un saludo y gran tutorial maestro!
Responder
#24
iPacked nunca se asigna a si mismo como iPacked >> 8, fijate bien

Cita:iPacked // siempre tendra el mismo valor
00000000100000000100000011111111
iPacked >> 16
00000000000000000000000010000000

Whatever
Responder
#25
Si, tenes razon, lo pensé pero no estaba seguro, x eso pregunté, asi que gracias por responder!
Responder


Salto de foro:


Usuarios navegando en este tema: 2 invitado(s)