Autor Tema: Como multiplicar con números que tienen decimales en assembler  (Leído 566 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado jls_80

  • PIC10
  • *
  • Mensajes: 9
Como multiplicar con números que tienen decimales en assembler
« en: 13 de Julio de 2018, 09:10:01 »
Saludos a todos,

Espero por favor que me puedan ayudar, necesito saber como puedo hacer en assembler para multiplicar un número con otro que tenga decimales, como el siguiente caso:

Numero*0.48828125

Muchas gracias si alguien me puede ayudar dándome una idea de como hacerlo.
« Última modificación: 13 de Julio de 2018, 09:12:02 por jls_80 »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 6943
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #1 en: 13 de Julio de 2018, 10:00:43 »
Primero necesitas representar ese numero en binario.. Luego lo voy a explicar para tratar de que entiendas porque es lo mismo que multiplicar 2 numeros comunes

Con 9 bits podes hacer:

Código: [Seleccionar]
0.011111010... = 0.48828125
Si lo desplazamos 9 veces a la izquierda (multiplicamos por 512) nos queda el binario:

Código: [Seleccionar]
11111010 = 250
Ahora podemos hacer la misma operación pero de esta forma:

Código: [Seleccionar]
Numero * 250 / 512
Ya que 250/512 es nuestro 0.4488285, Ese 512 nos va a decir donde se encuentra la COMA en nuestro resultado. El orden de los factores no altera el producto

Ahora procedemos a multiplicar como si fueran 2 numeros comunes, para seguir el ejemplo supongamos que Numero es 150, el resultado de multiplicar 2 de 8 bits es de 16bits

Código: [Seleccionar]
150*250 = 37500 = 1001 0010 0111 1100
Entonces ahora deberia dividirlo por 512, es decir dezplazar a la derecha 9 veces, pero rotar 8 veces es ponerlo en otro registro asi que no tiene sentido, asi que en realidad lo vamos a dezplazar 1 sola ves. Quedandonos:

Código: [Seleccionar]
0100 1001 0011 1110
Los primeros 8 bits son nuestro entero, y los demas son los decimales:

Código: [Seleccionar]
01001001.0011111 = 73.2421875
150 * 0.48828125 = 73.2421875

En resumen para hacer esa multiplicacion, necesitas:

Tener el codigo para realizar una multiplicacion 8bits x 8bits, rotar 1 ves a la derecha el resultado. Y ya tenes en la parte alta el entero, y en la parte baja el decimal.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4918
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #2 en: 13 de Julio de 2018, 12:40:19 »
Se puede hacer trabajando en coma fija, de manera que todos los números están multiplicados por una cantidad fija.
De esta forma todos los números siempre permanecen multiplicados por ejemplo por 512 (tomando el ejemplo de Killer).


Pero hoy en día trabajar de esta forma es demasiado lento y lleno de errores. Es mejor pasarte al C y trabajar en coma flotante.
Si el microcontrolador es demasiado lento, puedes pasar a otro más potente.

Por último, Microchip tiene rutinas gratuitas para trabajar en coma flotante con ensamblador:
ww1.microchip.com/downloads/en/AppNotes/00575.pdf
IEEE 754 Compliant Floating Point Routines - Microchip Technology

Desconectado Eduardo2

  • PIC16
  • ***
  • Mensajes: 107
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #3 en: 13 de Julio de 2018, 15:07:29 »
....
Espero por favor que me puedan ayudar, necesito saber como puedo hacer en assembler para multiplicar un número con otro que tenga decimales, como el siguiente caso:

Numero*0.48828125


Lo general es un arsenal de librerías de multiplicación/división enteras/punto_fijo/punto_flotante y utilizarlas.

Pero se dan casos particulares donde la operación es con números muy especiales y se pueden hacer algunos trucos.

Fijate que tu número es especial:  0.48828125 = 1000/2048 = 125/256 

O sea que  Numero*0.48828125 = Numero*125 / 256      --> Es lo mismo que multiplicar Numero por 125 y correr 8 lugares a la derecha.

O también como   Numero*125 / 256 = Numero*(128-3) / 256 = Numero/2 - (3*Numero)/256  --> Multiplicar por 3, correr y restar.

Desconectado jls_80

  • PIC10
  • *
  • Mensajes: 9
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #4 en: 13 de Julio de 2018, 19:39:18 »
Muchas gracias por su ayuda. KILLERJC por favor me podrías ayudar explicando a mas a detalle el tema de cuando se tiene que desplazar a la derecha 9 veces (división por 2^9)  pero al final solo de desplaza una vez, eso no lo entiendo.

También si tengo que presentar esos datos en un displays,  01001001.0011111 la  parte entera no tendría problemas, ya que   01001001 es igual a 73, pero la padre decimal como la presentaría? Ya que 0011111 es igual a 31 y el decimal correcto es 0.2421875. Tendría tal vez que hacer un juego de instrucciones para pasar esta parte fraccionaria de binario a decimal?




Primero necesitas representar ese numero en binario.. Luego lo voy a explicar para tratar de que entiendas porque es lo mismo que multiplicar 2 numeros comunes

Con 9 bits podes hacer:

Código: [Seleccionar]
0.011111010... = 0.48828125
Si lo desplazamos 9 veces a la izquierda (multiplicamos por 512) nos queda el binario:

Código: [Seleccionar]
11111010 = 250
Ahora podemos hacer la misma operación pero de esta forma:

Código: [Seleccionar]
Numero * 250 / 512
Ya que 250/512 es nuestro 0.4488285, Ese 512 nos va a decir donde se encuentra la COMA en nuestro resultado. El orden de los factores no altera el producto

Ahora procedemos a multiplicar como si fueran 2 numeros comunes, para seguir el ejemplo supongamos que Numero es 150, el resultado de multiplicar 2 de 8 bits es de 16bits

Código: [Seleccionar]
150*250 = 37500 = 1001 0010 0111 1100
Entonces ahora deberia dividirlo por 512, es decir dezplazar a la derecha 9 veces, pero rotar 8 veces es ponerlo en otro registro asi que no tiene sentido, asi que en realidad lo vamos a dezplazar 1 sola ves. Quedandonos:

Código: [Seleccionar]
0100 1001 0011 1110
Los primeros 8 bits son nuestro entero, y los demas son los decimales:

Código: [Seleccionar]
01001001.0011111 = 73.2421875
150 * 0.48828125 = 73.2421875

En resumen para hacer esa multiplicacion, necesitas:

Tener el codigo para realizar una multiplicacion 8bits x 8bits, rotar 1 ves a la derecha el resultado. Y ya tenes en la parte alta el entero, y en la parte baja el decimal.
« Última modificación: 14 de Julio de 2018, 00:00:10 por jls_80 »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 6943
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #5 en: 13 de Julio de 2018, 23:38:45 »
En una arquitectura de 8 bits, no posee sentido "rotar 8 veces" Voy a darte un ejemplo para hacerlo mas practico..

Supongamos que tengo el numero 0100 1001 0011 1110 en 2 lugares de la memoria, empezando desde 0x20:

Código: [Seleccionar]
0x20: 0100 1001
0x21: 0011 1110
Si quisiera desplazarlo 8 lugares a la derecha y aun asi no perder ningun bit(si quiero conservar la parte decimal), necesitaria algun otro lugar donde poner esos 8 bits, supongamos que voy desplazandolos para la direccion 0x22
Al desplazar los 8 vas a notar esto:

Código: [Seleccionar]
0x20: 0000 0000
0x21: 0100 1001
0x22: 0011 1110

Ahora tengo en 0x21 y en 0x22 lo mismo que tenia antes en 0x20 y 0x21.. Rotarlo 8 veces lo unico que logre mover los 2 datos a otra posicion de memoria.Entonces era mas simple no rotarlo, si se que voy a tener el mismo resultado pero en otro lugar.

Todavia me falta rotar 1 ves mas... pero es 1 solo bit, que si no necesitas gran exactitud, no importaria que la expresion decimal no sea tan exacta. Entonces para no utilizar 2 registros para la parte decimal, simplemente lo roto y me olvido de ese bit. Quedandome con 1 registro para la parte entera, y uno para la parte decimal. Estoy perdiendo 1 bit, es un "riesgo" que asumi que no iba a ser un factor decisivo, por eso lo hice.

De todas formas siempre vas a tener un "error", ya que son pocos los numeros decimales poseen una representacion binaria finita.. Por ejemplo:

Código: [Seleccionar]
n       1/n  representado en binario

2 .1
3 .010101......
4 .01
5 .001100110011....
6 .0010101.....
7 .001001001.....
8 .001
9 .000111000111.....
10 .0001100110011......
11 .000101110100010111.....
12 .00010101.....
13 .0001001110110001001.....
14 .0001001001.....
15 .000100010001.....

Todos los que tienen puntos continuan hasta el infinito, nunca lo vas a poder representar con un numero finito de bits.. A pesar que por ejemplo 1/10 en decimal lo podes representar con un solo lugar 0.1

Dio la casualidad que tu numero al multiplicarlo por 512 diera un numero entero. Y que se puede representar por 8 bits.
Sino se deberia haber buscado el numero que mejor se aproxima con 8 bits al que queres. Y de alli operar.


Desconectado jls_80

  • PIC10
  • *
  • Mensajes: 9
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #6 en: 14 de Julio de 2018, 00:08:08 »
Muchas gracias KILLERJC tu explicación es muy precisa. Una última consulta :

Ahora si tengo que presentar esos datos en un displays,  01001001.0011111 la  parte entera no tendría problemas, ya que   01001001 es igual a 73, pero la padre decimal como la presentaría? Ya que 0011111 es igual a 31 y el decimal correcto es 0.2421875. Tendría tal vez que hacer un juego de instrucciones para pasar esta parte fraccionaria de binario a decimal?




En una arquitectura de 8 bits, no posee sentido "rotar 8 veces" Voy a darte un ejemplo para hacerlo mas practico..

Supongamos que tengo el numero 0100 1001 0011 1110 en 2 lugares de la memoria, empezando desde 0x20:

Código: [Seleccionar]
0x20: 0100 1001
0x21: 0011 1110
Si quisiera desplazarlo 8 lugares a la derecha y aun asi no perder ningun bit(si quiero conservar la parte decimal), necesitaria algun otro lugar donde poner esos 8 bits, supongamos que voy desplazandolos para la direccion 0x22
Al desplazar los 8 vas a notar esto:

Código: [Seleccionar]
0x20: 0000 0000
0x21: 0100 1001
0x22: 0011 1110

Ahora tengo en 0x21 y en 0x22 lo mismo que tenia antes en 0x20 y 0x21.. Rotarlo 8 veces lo unico que logre mover los 2 datos a otra posicion de memoria.Entonces era mas simple no rotarlo, si se que voy a tener el mismo resultado pero en otro lugar.

Todavia me falta rotar 1 ves mas... pero es 1 solo bit, que si no necesitas gran exactitud, no importaria que la expresion decimal no sea tan exacta. Entonces para no utilizar 2 registros para la parte decimal, simplemente lo roto y me olvido de ese bit. Quedandome con 1 registro para la parte entera, y uno para la parte decimal. Estoy perdiendo 1 bit, es un "riesgo" que asumi que no iba a ser un factor decisivo, por eso lo hice.

De todas formas siempre vas a tener un "error", ya que son pocos los numeros decimales poseen una representacion binaria finita.. Por ejemplo:

Código: [Seleccionar]
n       1/n  representado en binario

2 .1
3 .010101......
4 .01
5 .001100110011....
6 .0010101.....
7 .001001001.....
8 .001
9 .000111000111.....
10 .0001100110011......
11 .000101110100010111.....
12 .00010101.....
13 .0001001110110001001.....
14 .0001001001.....
15 .000100010001.....

Todos los que tienen puntos continuan hasta el infinito, nunca lo vas a poder representar con un numero finito de bits.. A pesar que por ejemplo 1/10 en decimal lo podes representar con un solo lugar 0.1

Dio la casualidad que tu numero al multiplicarlo por 512 diera un numero entero. Y que se puede representar por 8 bits.
Sino se deberia haber buscado el numero que mejor se aproxima con 8 bits al que queres. Y de alli operar.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 6943
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #7 en: 14 de Julio de 2018, 08:40:31 »
Citar
Tendría tal vez que hacer un juego de instrucciones para pasar esta parte fraccionaria de binario a decimal?

Acordate que vas a necesitar de un registro de 8 bits por cada numero decimal.
Una de las formas mas simples de hacerlo y que vi es preguntar por cada bit y sumar el valor que corresponde.. para la parte decimal tenes que:

Código: [Seleccionar]
2^-1 = 0.5 es el bit de mayor peso
2^-2 = 0.25
2^-3 = 0.125
2^-4 = 0.0625
2^-5 = 0.03125
2^-6 = 0.015625
2^-7 = 0.0078125

Entonces para que sea mas simple, lo mejor es guardarlo como texto. Vas a crear una "tabla" con RETLW o DT con esos valores

Código: [Seleccionar]
UNO: DT "5",0x00
DOS: DT "25",0x00
TRES: DT "125",0x00
CUATRO: DT "625",0x00
CINCO: DT "03125",0x00
SEIS: DT "015625",0x00
SIETE: DT "0078125",0x00

Luego en tu programa preguntas:

¿bit 7 en 1?
 Si esta en un tomo las letras de UNO y las voy sumando a los registros, siendo ahora el primer lugar "5"
 Sigo hasta que encuentro el 0x00 en el string que me dice parar
 Si no esta en 1, no hago nada
 Arreglo por si alguno paso el 9
¿bit 6 en 1?
 Si esta en un tomo las letras de DOS y las voy sumando a los registros, siendo ahora los primeros 2 registros "2" y "5" , o si antes se habia sumado el 5, deberia tener "7" y "5"
 Sigo hasta que encuentro el 0x00 en el string que me dice parar
 Si no esta en 1, no hago nada y dejo como esta todo.
 Arreglo por si alguno paso el 9
........ Asi para todos

Y antes que nada:
Lo mas seguro es que uses los FSR para moverte por los registros decimales.
Tenes que recordar que los valores que tomas de la string, estan en ASCII, por lo que para sumarlos aunque sea a 1 deberias restarle '0' y luego arreglar en caso de que pase de '9' la suma.
La otra forma es usar numeros en ves de letras, haciendo mas sencilla la operacion y luego procedes a sumarlo '0' para mostrarlo. Vas a tener que cambiar el limite a 0xFF por ejemplo en ves de 0x00.Es decir:

Código: [Seleccionar]
UNO: DT 0x5,0xFF
DOS: DT 0x2,0x5,0xFF
TRES: DT 0x1,0x2,0x5,0xFF

Tal ves esta te convenga mas

Desconectado jls_80

  • PIC10
  • *
  • Mensajes: 9
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #8 en: 14 de Julio de 2018, 22:10:59 »
KILLERJC en verdad me ayudo mucho tu información. Gracias por compartir tus conocimientos.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4918
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #9 en: 15 de Julio de 2018, 15:12:03 »
Hay que tener mucho ánimo para programarlo a mano en Assembler sin utilizar las rutinas de Microchip ni pasarte al C.
Yo hice en una ocasión esas rutinas en C para utilizar números de alta precision en un pic pequeño y es un camino bastante difícil. También tendrás que programar rutinas de test para depurar los errores, que aparecen con más facilidad de lo que se espera.

Un saludo.

Desconectado jls_80

  • PIC10
  • *
  • Mensajes: 9
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #10 en: 15 de Julio de 2018, 16:18:44 »
Soy nuevo en esto y la idea es a futuro poder programar en C, pero primero quiero formar una base solida en assembler para luego migrar. Pero no deja de ser fascinante el mundo del assembler



Hay que tener mucho ánimo para programarlo a mano en Assembler sin utilizar las rutinas de Microchip ni pasarte al C.
Yo hice en una ocasión esas rutinas en C para utilizar números de alta precision en un pic pequeño y es un camino bastante difícil. También tendrás que programar rutinas de test para depurar los errores, que aparecen con más facilidad de lo que se espera.

Un saludo.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 6943
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #11 en: 15 de Julio de 2018, 19:17:50 »
Mientras aprendas el ASM para saber como funciona el microcontrolador pienso que esta bien. Pero tampoco te dediques a hacer cosas que llevarian demasiado tiempo siendo que en C lo podrias hacer mucho mas facil. Es decir, es lindo para aprender, pero no te detengas ahi a hacer de todo con ASM.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4918
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #12 en: 16 de Julio de 2018, 02:35:38 »
Soy nuevo en esto y la idea es a futuro poder programar en C, pero primero quiero formar una base solida en assembler para luego migrar. Pero no deja de ser fascinante el mundo del assembler

Yo creo que es al revés. En C puedes aprender una base sólida de programación estructurada (no es solo aprender el lenguaje, tambien hay que aprender a utilizarlo bien).
A partir de ahí puedes utilizar assembler cuando lo necesites.
Para la aplicación que tienes que hacer ahora, yo utilizaría C y librerias estandar. Nada de assembler ni de programar rutinas matemáticas.
Hoy en día el assembler solo se necesita en pocas ocasiones y para pocas líneas.
Los micros tienen suficiente memoria y periféricos hardware para soportarlo. Además cada poco tiempo cambiarás de arquitectura y con el programa en c cambiar de micro es inmediato.
Ya hace 50 años que se invento el C por esa razón.

Saludos.

Desconectado jls_80

  • PIC10
  • *
  • Mensajes: 9
Re:Como multiplicar con números que tienen decimales en assembler
« Respuesta #13 en: 17 de Julio de 2018, 16:37:02 »
KILLERJC y PICUINO, gracias por sus consejos y ayuda y por compartir sus conocimientos que es muy importante para personas como yo que están recién iniciándose en este fabuloso mundo de los microcontroladores. En base a sus indicaciones logré resolver el problema.