PDA

Ver la versión completa : Ayuda con aritmetica binaria (punto fijo)



Locke
14/04/2005, 23:51
A ver si alguno me puede echar una mano, que tengo unas dudas sobre aritmetica binaria que no me acabo de aclarar...

Un numero de 16 bits en punto fijo con formato 1.3.12 tiene rango (9, -8] o me estoy confundiendo?

Como seria la macro para multiplicar dos numeros en ese formato? Y para multiplicar un numero en ese formato con un entero unsigned char?

Venga, muxas gracias por adelantado.

Wave
15/04/2005, 08:34
Bueno, el rango seria (9,-9), no? en cuanto a lo de la macro para multiplicar es question de ponerse, multiplicas los 15 bits por los 15 bits y te saldria un numero de 30 bits donde los 6 primeros serian la parte entera, algo asi como:
000100,11101010101101101101101 entonces depende de como quieras representarlo en 1.3.12, si quieres truncar o redondearpero la cosa seria que el signo es = a la xor de los dos (siendo 1 negativo) y los 12 bits de decimales coges los 12 primeros de la parte decimal multiplicacion (redondeando o truncando).

bitrider
15/04/2005, 09:56
Fale que estoy un poco tonto, y hace mucho que no utilizo punto fijo. Pero si cogemos 3 bits para la parte entera... 2³ - 1 = 7, luego el rango no sería (-8, 8) (cuidao que confundo parentesis abiertos y cerrados XD)?

mortimor
15/04/2005, 10:02
Pues yo tampoco lo tengo muy claro, pero si es 1,3,12 -> signo + natural + decimal ....
no sera (-8,8( o lo que es lo mismo (1-000-000000000000,0-111-111111111111), ojo con el 8 que está excluido (para los puristas podria ser [-8,8)).

Quizas este equivocado :)

mortimor
15/04/2005, 10:16
La multiplicacion deberia de ser la misma que la de dos WORD con signo, asi que solo tendrias que hacer la multiplicacion tal cual (ojo con los posibles overflow o underflow, no se si podrian dar problemas).

Para multiplicar por un unsigned char. No estoy muy seguro, pero podria ser que si haces una macro en la que pegue el char a un WORD con signo y luego multipliques tal cual como en el primer caso... no estoy seguro de si el compilador hara esta conversion o existira una operacion o una forma mas optima de hacerlo.

/*siempre que b sea menor de 8, porque sino... saldra mal, eso lo puedes comprobar tu en el macro añadiendo un par de cosas*/

#define mul_sword_uchar(a,b) ((b<<12) * a)


PD: por favor si alguien ve que estoy poniendo burradas que lo diga cuanto antes, ya que estoy poniendome en modo imaginativo :) lo cual no quiere decir que este equivocado.

oankali
15/04/2005, 10:47
No recuerdo haber estudiado aritmética binaria, aunque probablemente lo haya hecho, pero ¿cuando?

Me parece que el rango para 4 bits con signo es: (7,-8)
No conozco la fórmula, pero si sabemos que 4 bits nos dan 2^4 = 16 valores, y partimos por 2 los valores (positivos y negativos), tenemos 8 en la zona positiva (0,7) y ocho en la zona negativa (-1,-8). O sea (7,-8).

Nota: es mi lógica, si me equivoco, no hagáis caso.

Oankali

mortimor
15/04/2005, 10:53
Tu logica esta muy bien oankali, pero olvidas la parte decimal, entonces el 7 se convierte en 7,xxxxx. Esas 12 'x' son la parte decimal del numero y si tenemos 0111 en los 4 primeros y 111111111111 en los 12 siguientes tendremos algo parecido a 7'999... segun los decimales que sean.

Lo que realmente dudo es la solucion que he intentado imaginarme para la multiplicacion. :rolleyes:

Propeller
15/04/2005, 10:57
Hola,

después de leerme lo que habéis pensado, he de decir que estoy con el razonamiento de Wave, ya que según la notación que trabajas las posiciones son fijas y por tanto los intervalos han de ser simétricos. Por tanto, el signo por una parte, la parte entera por otra y la parte decimal por otra, trabajando con carry.

Propeller

mortimor
15/04/2005, 11:42
En lo del carry tienes razon, mi solucion es una mierda. Ya he dicho que lo del acarreo y los problemas de overflow.... una mierda vamos :D

Segun lo veo (entre lo que he estado dandole vueltas y lo que habeis dicho) deberia ser algo asi como hacer la multiplicacion por partes??? "c=a*b":

- A ver, primero el signo s = (((0x8000 & a) ^ (0x8000 & b))) seria algo asi no?
- luego realizamos la multiplicacion de todo menos el signo ... ufff esto empieza a ser complicado. pongamos que obtenemos 'm'
- Finamente trucamos las partes interesadas para que ocupen los 16 bits en vez de 32. c = s | ((m & 0x0e000000)>>13) | ((m & 0x01ffffff)>>13)

Seguro que esta mal, sobre todo teniendo en cuenta que no comprueba el overflow :rolleyes: Creo que esto se puede hacer de una forma mas sencilla :loco:

¿¿¿Por qué no usas sll, estan optimizadas en ensamblador y ya estan echas??? :)

Por cierto el intervalo de valores sigo creyendo que es [-8,8) esto no es exacto ya que habria que tener encuenta la precision de esos 12 bits para decimales.

Wave
15/04/2005, 12:54
Se me ha ido la olla, es (-8, 8) (7.mucho) porque trabajas con un bit de signo y no complemento a 2, ademas tienes el 0 duplicado (+-0)

Propeller
15/04/2005, 13:01
(+,-) 111.111111111111 = (+,-) 7.4095

Ese es el número más alto y más bajo representable en esa notación de punto fijo. Y, efectivamente, tienes -0 y +0, a no ser que la representación la hagas tú mismo y decidas que uno de los dos significa otra cosa.

Propeller

bitrider
15/04/2005, 13:35
poz ezo, lo que yo decía, al final resulta que no estoy tan tonto XD

Locke
15/04/2005, 13:47
Ok, el rango ya me ha quedao claro, muchas gracias a todos. Eso si, con lo de la multiplicacion todavia estoy liado...

Propeller
15/04/2005, 14:54
poz ezo, lo que yo decía, al final resulta que no estoy tan tonto XD

Pues-si-pues-tienes-razon-pues-estamos-de-acuerdo.

:brindis:

Locke, si tengo un rato me pienso lo de la función de multiplicar :)

Propeller

Wave
15/04/2005, 15:03
//signo
short s= (a ^ b) & 0x3fff;

//multiplicacion
int m=a * b;
m&=0x1fffffff;
m=(m<<12);

//pegado
short r= s | (short)m;

Mmm, creo que es algo asi;

Ahora lo intentamos como linea corta....
r= ( (a ^ b) & 0x3fff ) | ( ( (a * b) & 0x1fffffff ) <<12 );

Creo.

Locke
15/04/2005, 18:35
Creo que mas rapido y mas facil va a ser convertir el archivo que quiero usar a uno que ya tenga los datos descomprimidos y en el formato adecuado...

Aun asi me queda una ultima duda: si los floats que quiero transformar se salen del rango (7'x, -7'x) como hago para que queden todos dentro del rango pero que se sigan manteniendo las proporciones entre ellos? Creo que tendria que dividirlos todos por el resultado de dividir el mayor de ellos entre el limite del rango, pero me gustaria estar seguro... :)

La macro que voy a usar para la transformacion es esta:

#define floatov16(n) ((v16)((n) * (1 << 12)))

Logann
16/04/2005, 18:18
No seria dividir el mayor de ellos por la resta de (maximorango - mayor de ellos)?