Autor Tema: Jugando con Binarios - Multiplicacion y Coma Flotante  (Leído 6949 veces)

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

Desconectado SavageChicken

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 916
Jugando con Binarios - Multiplicacion y Coma Flotante
« en: 15 de Octubre de 2010, 00:40:52 »
  Bien, vamos a jugar un poco con números binarios, y aprovechar ciertas ventajas que ellos tienen sobre todo al manipularlos con un microcontrolador.

  Un tema recurrente en este foro es la multiplicación en assembler, si usan el buscador verán que en una gran cantidad de post, se pide o se entrega alguna rutina para multiplicar, incluso yo tengo publicada una rutina (que por cierto me quedó muy chula :D :D).

  La mayoría de estas rutinas se basan en la siguiente lógica, "para multiplicar dos números entre ellos basta tomar una de las cifras y sumarla tantas veces como lo indique la segunda cifra". Este método funciona muy bien, pero no es para nada eficiente, imaginen multiplicar 17987 x 30653, estamos hablando de sumar "treinta mil seicientas cincuena y tres veces un número" por muy veloz que sea un PIC esto tomaría un buen tiempo, incluso el gasto en recursos (memoria, registros, ciclos, etc.) es enorme.

  Gracias a Dios tengo varios años, y si bien no me considero viejo, manejé una Sinclair TS-1000, con solo 2K de memoria, y muchos de los trucos y maravillas que se lograban con estas "home computers" se debían a la destreza de los programadores para aprovechar "las ventajas" de trabajar con los números binarios directamente.

  Muchos estarán bostezando y preguntándose hacia donde va toda esta cháchara, bueno dejemos la charla y vemos lo sustancial.

  Cuando trabajamos en binario, algunas cosas son más sencillas, en especial porque todos los números solo pueden tomar dos valores. Una ventaja por ejemplo es que para multiplicar cualquier número por 2, basta solo con desplazar los bit de dicho número un lugar hacia la izquierda, si no me creen vemos algunos ejemplos sencillos.

                     Decimal        Binario
                      3                 00011
(3 x 2)            6                 00110
(6 x 2)            12               01100

Probemos con otro número
                     Decimal         Binario
                      5                  00101
(5 x 2)            10                01010
(10 x 2)          20                 10100

  Descubierto esta detalle interesante, podemos deducir, que si nos encontráramos con la necesidad de multiplicar un número por alguna potencia de 2, bastaría con correr los bits de dicho número tantas veces como lo indique el exponente y nos ahorraríamos muchas sumas.

  Por ejemplo si debo multiplicar 37 x 64, no necesito sumar 64 veces 37, ya que 2^6=64 basta con rotar a la izquierda 6 veces el valor binario de 37 y "voile"  obtengo el resultado de dicho producto (reduje 64 bucles de suma a solo 6 bucles de rlf), si no estan convencidos lo probemos...

                Decimal       Binario
                37                          100101
(37 x 64)   2368            100101000000   (el 37 movido 6 lugares a la izquierda ¡increible!)

  Como curiosidad está buena, es más, podría ser útil si siempre tenemos que hacer multiplicaciones en donde alguna de las dos cifras es potencia de 2, pero en la vida real esto es de poca utilidad. Pero a no desesperar, que el binario nos tiene preparadas más sorpresas aún...

  ¿Cómo nos pueden ayudar estos 1 y 0 en los productos de números cualesquiera?
  Bueno, veamos primero, la manera en que haríamos una multiplicación en binario de dos números, tal como nos enseñaron en el colegio. Utilizaremos dos números pequeños para no complicarnos, pero el método sirve para cualquier número:

                 Decimal              Binario
                 5                                 0101
                 x 11                          x 1011
                                            -------------
                                                    0101      <- El número 5 sin corrimiento
                                                  0101        <- El número 5 corrido 1 lugar a la izquierda
                                                0000          <- En este cáso el dígito del segundo factor es 0, no se suma nada
                                              0101            <- El número 5 corrido 3 lugares a la izquierda
                                            -------------
                 = 55                      0110111

  Como podrán ver hay algo que salta a la vista y es que el producto de dos números en binario no es otra cosa que ir desplazando a la izquierda el valor binario de uno de los factores tantas veces como dígitos tenga el segundo factor, y hacer la suma sucesiva de estos valores desplazados, sólamente cuando el dígito del segundo factor valga 1.

  Con esta información ya podemos hacer un código bastante sencillo que realice multiplicaciones de números tan grandes como queramos, fácilmente podemos trabajar con números de 16, 32 o 64 bits, bastará con hacer rotaciones y sumas. Pensemos ahora en el producto que pusimos de ejemplo en un principio (17987 x 30653), estos son números de 16 bits, y hemos reducido la operatoria de más de 30000 sumas a solo 16 rotaciones y alrededor de 16 sumas ¡Valía la pena usar binarios verdad!.

  Bien pero aún hay más. Muchas consultas son por números decimales y no solo por enteros y sinceramente es más sencillo de lo que parece, cuando uno multiplica dos números enteros como 31416 x 27182 obtiene 853949712 y si multiplicamos 3,1416 x 2,7182 obtenemos 8,53949712 ¿acaso no es el mismo número? todo lo que los diferencia es una coma, simplemente debemos multiplicar los factores como si ellos fueran enteros, guardar en un par de registros la posición de la coma de cada factor a multiplicar y despues desplazar en el resultado la posición de la coma el equivalente a la suma de las posiciones que tenían las comas en los factores que fueron multiplicados, tal cual lo hacemos cuando multiplicamos en forma manual.

  Finalmente nos queda algo relativamente sencillo, habiendo entendido esto hay que hacer el código.
  Les lanzo un desafío, ¿quién se anima a realizar un código en assembler, que multiplique con este sistema números de 32 bits y de coma flotante?.
  Yo pienso publicar el mío en una semana, queda la invitación hecha.

  Espero les haya gustado y como siempre... Salud  8)
« Última modificación: 15 de Octubre de 2010, 10:22:19 por SavageChicken »
No hay preguntas tontas...
Solo hay tontos que no preguntan.

Desconectado fabianjsm

  • PIC18
  • ****
  • Mensajes: 255
    • fabianjsm is on twitter
Re: Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #1 en: 15 de Octubre de 2010, 03:12:36 »
Un diez SavageChicken!
Me sumo al desafio, a multiplicar se ha dicho!
@fabianjsm is on twitter

Desconectado martincnc

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 352
Re: Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #2 en: 15 de Octubre de 2010, 12:25:02 »
Excelente explicación SavageChicken!. Muchas gracias por compartirlo  ;-)

La facilidad del manejo de coma flotante en C es uno de los factores mas importantes que a veces que me obliga a utilizarlo aunque no me guste para nada, pero ahora que veo lo sencillo que es hacer estas operaciones en binario no me queda mas opción que sumarme al desafío   :evil:   Jaja

Saludos!

Desconectado SavageChicken

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 916
Re: Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #3 en: 16 de Octubre de 2010, 13:00:42 »
  Bueno, acá estoy de nuevo.

  Francamente pensé que el desafío tendría mayor convocatoria, asíque mis felicitaciones a los valientes que se animaron a sumarse al desafío.

  Por mi parte estoy más contento que rescatista minero (Advertencia para quién lea esto dentro de diez años: este chiste surgió a raíz del rescate que se hizo en Chile de 33 mineros atrapados a 700 mts. de profundidad, hoy puede que la broma resulte graciosa, quizá para ti amigo del futuro no lo sea), la rutina funciona en forma impecable y he disfrutado mucho al hacerla.

  La tengo implementada para un 16F648A, dado que quería hacer pruebas y ver su funcionamiento, pero es simple de adaptar a otras necesidades o como una subrutina.

  Le he incorporado algunos detalles para hacerlo más entretenido, como es la conversión de hexadecimal a decimal (hay que tener en cuenta que si se usa la conversión, se destruye en el proceso el resultado en hexadecimal).

  Pienso agregarle también una sección para que nos muestre el resultado como una cadena de caracteres tal como lo mostraría una calculadora en un display.

  Lo que le falta es una rutina para el ingreso de los factores a multiplicar, el programa asume que estos valores fueron cargados en las variables dispuestas para recibir los factores a multiplicar, lo que en un simulador es fácil de hacer antes de echar a correr la rutina.

  Ok, basta de tanto preludio y aquí esta el resultado y una última acotación, la rutina es grande sobre todo por los chiches anexos y no por la rutina de multiplicación en si misma.
Código: Microchip Assembler
  1. ;**********************************************************************
  2. ;                                                                     *
  3. ;    Filename:      Multiplicar.asm                                   *
  4. ;    Date:          30/10/2010                                        *
  5. ;    File Version:  1.1                                               *
  6. ;                                                                     *
  7. ;    Author:        Ruben Arranz                                      *
  8. ;    Company:       Electronics Design                                *
  9. ;                                                                     *
  10. ;                                                                     *
  11. ;**********************************************************************
  12. ;                                                                     *
  13. ;    Files required:                                                  *
  14. ;                    16F648A.lkr                                      *
  15. ;                                                                     *
  16. ;                                                                     *
  17. ;**********************************************************************
  18. ;                                                                     *
  19. ;    Notes:                                                           *
  20. ;                                                                     *
  21. ;                                                                     *
  22. ;                                                                     *
  23. ;                                                                     *
  24. ;**********************************************************************
  25.  
  26.         list      p=16F648A           ; list directive to define processor
  27.         #include <p16F648A.inc>       ; processor specific variable definitions
  28.  
  29.         errorlevel  -302              ; suppress message 302 from list file
  30.  
  31.         __CONFIG   _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT
  32.  
  33.  
  34. ; Para numeros de 32 bits, necesitamos colocar el resultado en un numero de 64 bits es decir 8 Registros de Memoria
  35. Resultado_B7    equ 0x20        ; Byte mas significativo del Resultado
  36. Resultado_B6    equ 0x21
  37. Resultado_B5    equ 0x22
  38. Resultado_B4    equ 0x23
  39. Resultado_B3    equ 0x24
  40. Resultado_B2    equ 0x25
  41. Resultado_B1    equ 0x26
  42. Resultado_B0    equ 0x27        ; Byte menos significativo del Resultado
  43. ValInt_B7               equ 0x28        ; Byte mas significativo del Valor Intermedio
  44. ValInt_B6               equ 0x29
  45. ValInt_B5               equ 0x2A
  46. ValInt_B4               equ 0x2B
  47. ValInt_B3               equ 0x2C
  48. ValInt_B2               equ 0x2D
  49. ValInt_B1               equ 0x2E
  50. ValInt_B0               equ 0x2F        ; Byte menos significativo del Valor Intermedio
  51. Factor_A_B3             equ 0x30        ; Byte mas significativo del Factor A
  52. Factor_A_B2             equ 0x31
  53. Factor_A_B1             equ 0x32
  54. Factor_A_B0             equ 0x33        ; Byte menos significativo del Factor A
  55. Factor_B_B3             equ 0x34        ; Byte mas significativo del Factor B
  56. Factor_B_B2             equ 0x35
  57. Factor_B_B1             equ 0x36
  58. Factor_B_B0             equ 0x37        ; Byte menos significativo del Factor B
  59. Coma_R                  equ 0x38        ; Posicion de la coma del Resultado
  60. Coma_A                  equ 0x39        ; Posicion de la coma del Factor A
  61. Coma_B                  equ 0x3A        ; Posicion de la coma del Factor B
  62. Contador                equ     0x3B    ; Esta variable sera el contador de los desplazamientos que debemos hacer
  63. Auxiliar_A              equ 0x03C       ; Variable Auxiliar para propositos generales
  64. Auxiliar_B              equ 0x03D       ; Variable Auxiliar para propositos generales
  65. Auxiliar_C              equ 0x03E       ; Variable Auxiliar para propositos generales
  66. Auxiliar_D              equ 0x03F       ; Variable Auxiliar para propositos generales
  67. ResDec_9                equ     0x040
  68. ResDec_8                equ     0x041
  69. ResDec_7                equ     0x042
  70. ResDec_6                equ     0x043
  71. ResDec_5                equ     0x044
  72. ResDec_4                equ     0x045
  73. ResDec_3                equ     0x046
  74. ResDec_2                equ     0x047
  75. ResDec_1                equ     0x048
  76. ResDec_0                equ     0x049
  77. ResASC_20               equ 0x050
  78. ResASC_19               equ 0x051
  79. ResASC_18               equ 0x052
  80. ResASC_17               equ 0x053
  81. ResASC_16               equ 0x054
  82. ResASC_15               equ 0x055
  83. ResASC_14               equ 0x056
  84. ResASC_13               equ 0x057
  85. ResASC_12               equ 0x058
  86. ResASC_11               equ 0x059
  87. ResASC_10               equ 0x05A
  88. ResASC_9                equ 0x05B
  89. ResASC_8                equ 0x05C
  90. ResASC_7                equ 0x05D
  91. ResASC_6                equ 0x05E
  92. ResASC_5                equ 0x05F
  93. ResASC_4                equ 0x060
  94. ResASC_3                equ 0x061
  95. ResASC_2                equ 0x062
  96. ResASC_1                equ 0x063
  97. ResASC_0                equ 0x064
  98. Espacio                 equ     0x065
  99.  
  100. ;**********************************************************************
  101. RESET_VECTOR    CODE    0x000                   ;Vector de Reset del Procesador
  102.                                 goto    Multiplicar
  103. VECT_INT                CODE    0x004                   ;Vector de Interrupcion del Procesador
  104.                                 goto    Multiplicar
  105.  
  106. MAIN                    CODE    0x005
  107. Multiplicar
  108. ; Me gusta partir explicandome a mi mismo lo que quiero hacer, y luego realizar las lineas de comando
  109. ; En pocas palabras vamos a tomar el valor almacenado en Factor A y lo desplazaremos a la izquierda tantas veces...
  110. ; ...como digitos binarios tenga el Factor B, este desplazamiento quedara almacenado en Valor Intermedio, en cada...
  111. ; ..ocacion  que el digito binario analizado del factor B sea "1" sumaremos el valor intermedio al Resultado
  112. ; No tendremos en consideracion cual de los dos factores es mayor, siempre se tomara el valor del factor A...
  113. ; ... para hacer el desplazamiento y se analizara el factor B para hacer las sumas.
  114. ; Comenzamos limpiando las variables que usaremos
  115.                                 clrf    Resultado_B0
  116.                                 clrf    Resultado_B1
  117.                                 clrf    Resultado_B2
  118.                                 clrf    Resultado_B3
  119.                                 clrf    Resultado_B4
  120.                                 clrf    Resultado_B5
  121.                                 clrf    Resultado_B6
  122.                                 clrf    Resultado_B7
  123.                                 clrf    ValInt_B0
  124.                                 clrf    ValInt_B1
  125.                                 clrf    ValInt_B2
  126.                                 clrf    ValInt_B3
  127.                                 clrf    ValInt_B4
  128.                                 clrf    ValInt_B5
  129.                                 clrf    ValInt_B6
  130.                                 clrf    ValInt_B7
  131.                                 clrf    Contador
  132.                                 clrf    Auxiliar_A
  133.                                 clrf    Auxiliar_B
  134.                                 movlw   0x30
  135.                                 movwf   Espacio
  136. ; Esta rutina considera que las variables Factor_A y Factor_B fueron previamente cargadas
  137. ; Siendo que en virtud del valor de B se realizaran las sumas sucesivas, intentaremos ver cual es el bit mas significativo...
  138. ; ...de este factor para no hacer loops innecesarios.
  139. ; Esto evitara que hagamos por ejemplo 32 loops cuando estamos multiplicando numeros peque&#241;os.
  140.                                 movfw   Factor_B_B3             ; Me fijo si hay algun bit en "1" en el byte mas significativo
  141.                                 movwf   Auxiliar_A              ; Aprovecho la pasada para guardar este dato en la Variable Auxiliar
  142.                                 btfsc   STATUS,Z                ; La existencia de algun bit en "1" la puedo detectar en el valor Z del Status
  143.                                 goto    TestByte2               ; No habiendo ninguno bit en "1" sigo con el siguiente byte
  144.                                 movlw   0x18                    ; Habiendo algun bit en "1" el "0x18" corresponde al valor minimo de loops que debere hacer
  145.                                 movwf   Contador                ; Almaceno este dato en el Contador
  146.                                 goto    DeterminaLoops  ; Vamos a ver en forma mas detallada cuantos loops deberemos hacer
  147. TestByte2               movfw   Factor_B_B2             ; Me fijo si hay algun bit en "1" en el byte siguiente
  148.                                 movwf   Auxiliar_A              ; Aprovecho la pasada para guardar este dato en la Variable Auxiliar
  149.                                 btfsc   STATUS,Z                ; La existencia de algun bit en "1" la puedo detectar en el valor Z del Status
  150.                                 goto    TestByte1               ; No habiendo ninguno bit en "1" sigo con el siguiente byte
  151.                                 movlw   0x10                    ; Habiendo algun bit en "1" el "0x10" corresponde al valor minimo de loops que debere hacer
  152.                                 movwf   Contador                ; Almaceno este dato en el Contador
  153.                                 goto    DeterminaLoops  ; Vamos a ver en forma mas detallada cuantos loops deberemos hacer
  154. TestByte1               movfw   Factor_B_B1             ; Me fijo si hay algun bit en "1" en el byte siguiente
  155.                                 movwf   Auxiliar_A              ; Aprovecho la pasada para guardar este dato en la Variable Auxiliar
  156.                                 btfsc   STATUS,Z                ; La existencia de algun bit en "1" la puedo detectar en el valor Z del Status
  157.                                 goto    TestByte0               ; No habiendo ninguno bit en "1" sigo con el siguiente byte
  158.                                 movlw   0x08                    ; Habiendo algun bit en "1" el "0x08" corresponde al valor minimo de loops que debere hacer
  159.                                 movwf   Contador                ; Almaceno este dato en el Contador
  160.                                 goto    DeterminaLoops  ; Vamos a ver en forma mas detallada cuantos loops deberemos hacer
  161. TestByte0               movfw   Factor_B_B0             ; En este caso veremos solo el detalle del byte
  162.                                 movwf   Auxiliar_A              ; Guardamos este dato en la Variable Auxiliar
  163. DeterminaLoops  movlw   0x08                    ; En la ultima etapa, del valor maximo de loops probables ("0x08")...
  164.                                 movwf   Auxiliar_B              ; ...deberemos descontarle al contador de loops una vuelta por cada bit en "0"...
  165. DetLoop_A               rlf             Auxiliar_A,f    ; ...y deteniendonos en el primer bit en "1", esto visto desde el bit de mayor peso hacia abajo
  166.                                 btfsc   STATUS,C                ; Por eso vamos sacando los bit de mayor peso y chequeamos si estan en "1"
  167.                                 goto    SumaLoop                ; Si esta en "1" paramos de decrementar
  168.                                 decfsz  Auxiliar_B,f    ; Por el contrario si tenemos un "0" decrementamos el valor que se le sumara al contador...
  169.                                 goto    DetLoop_A               ; ...y volvemos para chequear el siguiente bit
  170. SumaLoop                movfw   Auxiliar_B              ; Finalmente ponemos en el contador el valor de loops...
  171.                                 addwf   Contador,f              ; Que deberan realizarse para efectuar el producto
  172.  
  173. ; Si lo preferimos podemos cargar el contador con los 32 loops, esto ahorrara memoria en el PIC...
  174. ; ...Pero tomara mas ciclos la ejecucion total de la multiplicacion, la decicion es nuestra.
  175. ;                               movlw   0x20                    ; Cargo el Contador de loops
  176. ;                               movwf   Contador
  177.  
  178. ; Bien llego el momento de multiplicar
  179. ; En primera instancia, pasamos el Factor A a la variable ValInt
  180.                                 movfw   Factor_A_B0
  181.                                 movwf   ValInt_B0
  182.                                 movfw   Factor_A_B1
  183.                                 movwf   ValInt_B1
  184.                                 movfw   Factor_A_B2
  185.                                 movwf   ValInt_B2
  186.                                 movfw   Factor_A_B3
  187.                                 movwf   ValInt_B3
  188. ; Luego generamos el loop
  189. ; La idea es ir testeando uno a uno los bits del Factor B, para descubrir si son "1" o "0"
  190. ; Del bit menos significativo al mas significativo
  191. LoopMultip              bcf             STATUS,C                ; Utilizamos el bit de acarreo para testear esto, por eso primero lo ponemos a"0"
  192.                                 rrf             Factor_B_B3,f   ; Rotamos ahora los 4 bytes
  193.                                 rrf             Factor_B_B2,f
  194.                                 rrf             Factor_B_B1,f
  195.                                 rrf             Factor_B_B0,f
  196.                                 btfsc   STATUS,C                ; No fijamos que salio en el ultimo bit
  197.                                 call    SumarFactor_A   ; Si hay un uno llamamos a la rutina de Suma...
  198.                                 call    RotaFactor_A    ; ... mientras que en cualquier caso "1" o "0" debemos rotar el factor A
  199.                                 decfsz  Contador,f              ; Finalmente decrementamos el contador hasta llegar a "0"
  200.                                 goto    LoopMultip              ; Si todavia no llegamos a "0" nos mantenemos en este loop
  201. ; Si se requiere convertimos la cifra a un valor decimal
  202. ; ATENCION: La convercion del valor Hexadecimal a Decimal destruye el resultado en Hexadecimal
  203.                                 call    Hexadec_BDC
  204. ;Finalmente lo mas sencillo, decidir que posicion ocupa la coma en el resultado final
  205.                                 clrf    Coma_R
  206.                                 movfw   Coma_A
  207.                                 addwf   Coma_B,w
  208.                                 movwf   Coma_R
  209. ; Si se requiere acomodar el resultado para mostrarlo en un display o algo similar
  210.                                 call    BCD_ASCII
  211.                                 goto    Finalizar               ; Terminada la multiplicacion, salimos de la subrutina
  212.  
  213.  
  214. ; Simplemente rotamos todos los bytes para la proxima etapa
  215. RotaFactor_A    bcf             STATUS,C
  216.                                 rlf             ValInt_B0,f
  217.                                 rlf             ValInt_B1,f
  218.                                 rlf             ValInt_B2,f
  219.                                 rlf             ValInt_B3,f
  220.                                 rlf             ValInt_B4,f
  221.                                 rlf             ValInt_B5,f
  222.                                 rlf             ValInt_B6,f
  223.                                 rlf             ValInt_B7,f
  224.                                 return
  225.  
  226. ; Vamos sumando en la variable resultado los valores intermedios cuando corresponde
  227. ; Esta suma se hace byte a byte y en caso de suceder un acarreo se llama a una subrutina que incrementa el siguiente byte
  228. SumarFactor_A   bcf             STATUS,C
  229.                                 movfw   ValInt_B0
  230.                                 addwf   Resultado_B0,f
  231.                                 btfsc   STATUS,C
  232.                                 call    Incremento_B1
  233.                                 bcf             STATUS,C
  234.                                 movfw   ValInt_B1
  235.                                 addwf   Resultado_B1,f
  236.                                 btfsc   STATUS,C
  237.                                 call    Incremento_B2
  238.                                 bcf             STATUS,C
  239.                                 movfw   ValInt_B2
  240.                                 addwf   Resultado_B2,f
  241.                                 btfsc   STATUS,C
  242.                                 call    Incremento_B3
  243.                                 bcf             STATUS,C
  244.                                 movfw   ValInt_B3
  245.                                 addwf   Resultado_B3,f
  246.                                 btfsc   STATUS,C
  247.                                 call    Incremento_B4
  248.                                 bcf             STATUS,C
  249.                                 movfw   ValInt_B4
  250.                                 addwf   Resultado_B4,f
  251.                                 btfsc   STATUS,C
  252.                                 call    Incremento_B5
  253.                                 bcf             STATUS,C
  254.                                 movfw   ValInt_B5
  255.                                 addwf   Resultado_B5,f
  256.                                 btfsc   STATUS,C
  257.                                 call    Incremento_B6
  258.                                 bcf             STATUS,C
  259.                                 movfw   ValInt_B6
  260.                                 addwf   Resultado_B6,f
  261.                                 btfsc   STATUS,C
  262.                                 call    Incremento_B7
  263.                                 bcf             STATUS,C
  264.                                 movfw   ValInt_B7
  265.                                 addwf   Resultado_B7,f
  266.                                 return
  267.  
  268. ; Esta seccion es llamada cuando en la suma ocurre un acarreo, este acarreo se traslada al siguiente byte...
  269. ; ...incrementandolo, en caso de que este incremento genere otro acarreo, se sigue trasladando el acarreo al byte siguiente
  270. Incremento_B1   incf    Resultado_B1,f
  271.                                 btfss   STATUS,Z
  272.                                 return
  273. Incremento_B2   incf    Resultado_B2,f
  274.                                 btfss   STATUS,Z
  275.                                 return
  276. Incremento_B3   incf    Resultado_B3,f
  277.                                 btfss   STATUS,Z
  278.                                 return
  279. Incremento_B4   incf    Resultado_B4,f
  280.                                 btfss   STATUS,Z
  281.                                 return
  282. Incremento_B5   incf    Resultado_B5,f
  283.                                 btfss   STATUS,Z
  284.                                 return
  285. Incremento_B6   incf    Resultado_B6,f
  286.                                 btfss   STATUS,Z
  287.                                 return
  288. Incremento_B7   incf    Resultado_B7,f
  289.                                 return
  290.  
  291. ; Rutina de Conversion de Hexadecima a Decimal (Esta rutina no es mia, solo la adapte)
  292. ; Hexadecimal (Resultado_B7 a Resultado_B0) -> Decimal (ResDec_9-ResDec_0)
  293. ; Para una Multiplicacion de FFFFFFFF x FFFFFFFF (Que es el maximo numero a multiplicar por nosotros)
  294. ; obtenemos FFFFFFFE00000001 y en decimal 18446744065119617025 para representar este numero utilizamos u nibble por digito
  295. ; por lo tanto necesitaremos 10 bytes para almacenarlo
  296. Hexadec_BDC             bcf             STATUS,C
  297.                                 movlw   0x40            ; este valor es la cantidad de bits del numero hexadecimal a convertir (64 bits)
  298.                                 movwf   Contador
  299.                                 clrf    ResDec_9
  300.                                 clrf    ResDec_8
  301.                                 clrf    ResDec_7
  302.                                 clrf    ResDec_6
  303.                                 clrf    ResDec_5
  304.                                 clrf    ResDec_4
  305.                                 clrf    ResDec_3
  306.                                 clrf    ResDec_2
  307.                                 clrf    ResDec_1
  308.                                 clrf    ResDec_0
  309.  
  310. Hex_BCD_1               rlf             Resultado_B0,f
  311.                                 rlf             Resultado_B1,f
  312.                                 rlf             Resultado_B2,f
  313.                                 rlf             Resultado_B3,f
  314.                                 rlf             Resultado_B4,f
  315.                                 rlf             Resultado_B5,f
  316.                                 rlf             Resultado_B6,f
  317.                                 rlf             Resultado_B7,f
  318.                                 rlf             ResDec_0,f
  319.                                 rlf             ResDec_1,f
  320.                                 rlf             ResDec_2,f
  321.                                 rlf             ResDec_3,f
  322.                                 rlf             ResDec_4,f
  323.                                 rlf             ResDec_5,f
  324.                                 rlf             ResDec_6,f
  325.                                 rlf             ResDec_7,f
  326.                                 rlf             ResDec_8,f
  327.                                 rlf             ResDec_9,f
  328.  
  329.                                 decfsz  Contador,f
  330.                                 goto    Hex_BCD_2
  331.                                 return
  332.  
  333. Hex_BCD_2               movlw   ResDec_0
  334.                                 call    Hex_BCD_3
  335.                                 movlw   ResDec_1
  336.                                 call    Hex_BCD_3
  337.                                 movlw   ResDec_2
  338.                                 call    Hex_BCD_3
  339.                                 movlw   ResDec_3
  340.                                 call    Hex_BCD_3
  341.                                 movlw   ResDec_4
  342.                                 call    Hex_BCD_3
  343.                                 movlw   ResDec_5
  344.                                 call    Hex_BCD_3
  345.                                 movlw   ResDec_6
  346.                                 call    Hex_BCD_3
  347.                                 movlw   ResDec_7
  348.                                 call    Hex_BCD_3
  349.                                 movlw   ResDec_8
  350.                                 call    Hex_BCD_3
  351.                                 movlw   ResDec_9
  352.                                 call    Hex_BCD_3
  353.                                 goto    Hex_BCD_1
  354.  
  355. Hex_BCD_3               movwf   FSR
  356.                                 movlw   0x03
  357.                                 addwf   INDF,f
  358.                                 btfss   INDF,3
  359.                                 subwf   INDF,f
  360.                                 movlw   30H
  361.                                 addwf   INDF,f
  362.                                 btfss   INDF,7
  363.                                 subwf   INDF,f
  364.                                 return
  365.  
  366.  
  367. ; Esta seccion convierte el n&#250;mero de decimal a caracteres ASCII para mostrar en un display (Seccion Nueva)
  368. BCD_ASCII               movlw   0x15                    ;Limpiamos la conversion ASCII anterior, llenando de "0" todos los d&#237;gitos"
  369.                                 movwf   Auxiliar_A
  370.                                 movlw   ResASC_0
  371.                                 movwf   FSR
  372. LimpiaASCII             movlw   0x30
  373.                                 movwf   INDF
  374.                                 decf    FSR,f
  375.                                 decfsz  Auxiliar_A,f
  376.                                 goto    LimpiaASCII
  377.                                 movlw   0x0A                    ; Meto en elcontador la cantidad de BCD&#180;s a transformar
  378.                                 movwf   Contador
  379.                                 movlw   ResASC_20               ; Cargo en Auxiliar_B la direccion con valores de m&#225;s peso de los ASCII
  380.                                 movwf   Auxiliar_B
  381.                                 movlw   ResDec_9                ; Hago lo mismo pero ahora con las direccion de los valores de m&#225;s peso de los BCD en Auxiliar_A
  382.                                 movwf   Auxiliar_A
  383. ASCII_Loop_1    movwf   FSR                             ; Direcciono indirectamente al resultado en BCD
  384.                                 movfw   INDF                    ; Cargo el dato en BCD
  385.                                 swapf   INDF,w                  ; Ttrabajamos con la parte alta de este BCD
  386.                                 andlw   0x0F                    ; limpio la parte que no me sirve...
  387.                                 addlw   0x30                    ; ...y lo convierto en un valos ASCII
  388.                                 movwf   Auxiliar_C              ; Guardo la conversion en Auxiliar_C
  389.                                 call    VerifComa               ; Rutina que chequ&#233;a si corresponde colocar la coma
  390.                                 movfw   Auxiliar_B              ; Direcciono indirectamente la actual posici&#243;n ASCII
  391.                                 movwf   FSR
  392.                                 movfw   Auxiliar_C              ; Meto el valor convertido en la direcci&#243;n correspondiente
  393.                                 movwf   INDF
  394.                                 incf    Auxiliar_B,f    ; Apunto a donde se dejar&#225; el pr&#243;ximo valor ASCII
  395.                                 movfw   Auxiliar_A              ; Direcciono indirectamente al resultado en BCD de nuevo
  396.                                 movwf   FSR                             ; Cargo el dato en BCD, Ahora trabajaremos con la parte baja
  397.                                 movfw   INDF
  398.                                 andlw   0x0F                    ; limpio la parte que no me sirve...
  399.                                 addlw   0x30                    ; ...y lo convierto en un valos ASCII
  400.                                 movwf   Auxiliar_C              ; Guardo la conversion en Auxiliar_C
  401.                                 call    VerifComa               ; Rutina que chequ&#233;a si corresponde colocar la coma
  402.                                 movfw   Auxiliar_B              ; Direcciono indirectamente la actual posici&#243;n ASCII
  403.                                 movwf   FSR
  404.                                 movfw   Auxiliar_C              ; Meto el valor convertido en la direcci&#243;n correspondiente
  405.                                 movwf   INDF
  406.                                 incf    Auxiliar_A,f    ; Apunto a donde se tomaran los dos siguientes valores BCD
  407.                                 incf    Auxiliar_B,f    ; Apunto a donde se dejara el proximo valor ASCII
  408.                                 movfw   Auxiliar_A              ; Dejo en w el valor de la proxima direcci&#243;n BCD
  409.                                 decfsz  Contador,f              ; Verifico si hemos llegado al final del loop
  410.                                 goto    ASCII_Loop_1
  411. ; En esta seccion eliminamos los ceros antes del primer valor significativo o antes de la coma y los ceros despues del...
  412. ; ...&#250;ltimo valor significativo.
  413.                                 movlw   ResASC_20               ; Direcciono indirectamente la actual posici&#243;n ASCII
  414.                                 movwf   FSR
  415.                                 movlw   0x00                    ; Utilizo Auxiliar_A como un contador para saber desde donde debo desplazar los d&#237;gitos m&#225;s significativos
  416.                                 movwf   Auxiliar_A
  417. ASCII_Loop_2    movfw   INDF
  418.                                 xorlw   0x30                    ; Comparo d&#237;gito a d&#237;gito de izquierda a derecha...
  419.                                 btfss   STATUS,Z                ; ...si los valores son "0"
  420.                                 goto    ASCII_Loop_3    ; si llego a un d&#237;gito que no es "0" salgo del loop
  421.                                 incf    FSR,f                   ; si es "0" direcciono el siguiente digito...
  422.                                 incf    Auxiliar_A,f    ;... e incremento el contador que indica cuantos digitos hay en "0"
  423.                                 goto    ASCII_Loop_2    ; y seguimos testeando
  424. ASCII_Loop_3    movfw   INDF                    ; Antes de terminar esta seccion
  425.                                 xorlw   0x2C                    ; comparo el &#250;ltimo d&#237;gito que no fue "0" para ver...
  426.                                 btfsc   STATUS,Z                ; si el d&#237;gito tenia una ","
  427.                                 decf    Auxiliar_A,f    ; tomo el d&#237;gito anterior para que el resultado quede "0,XXXX"
  428.                                 call    Corre_ASCII             ; Llamamos a la rutina que desplaza los d&#237;gitos
  429.                                 movlw   ResASC_0
  430.                                 movwf   FSR
  431. ASCII_Loop_4    movfw   INDF
  432.                                 xorlw   0x30
  433.                                 btfss   STATUS,Z
  434.                                 goto    ASCII_Loop_5
  435.                                 movlw   0x20
  436.                                 movwf   INDF
  437.                                 decf    FSR,f
  438.                                 goto    ASCII_Loop_4
  439. ASCII_Loop_5    movfw   INDF
  440.                                 xorlw   0x2C
  441.                                 btfss   STATUS,Z
  442.                                 return
  443.                                 movlw   0x20
  444.                                 movwf   INDF
  445.                                 return
  446. VerifComa               movfw   Coma_R
  447.                                 sublw   ResASC_0
  448.                                 xorwf   Auxiliar_B,w
  449.                                 btfss   STATUS,Z
  450.                                 return
  451.                                 movfw   Auxiliar_B              ; Direcciono indirectamente la actual posici&#243;n ASCII
  452.                                 movwf   FSR
  453.                                 movlw   0x2C                    ; Meto una coma en la posici&#243;n adecuada
  454.                                 movwf   INDF
  455.                                 incf    Auxiliar_B,f
  456.                                 return
  457. Corre_ASCII             movlw   0x15
  458.                                 movwf   Auxiliar_B
  459.                                 movlw   ResASC_19
  460.                                 movwf   FSR
  461. Loop_C_ASC_2    movfw   INDF
  462.                                 decf    FSR,f
  463.                                 movwf   INDF
  464.                                 incf    FSR,f
  465.                                 incf    FSR,f
  466.                                 decfsz  Auxiliar_B,f
  467.                                 goto    Loop_C_ASC_2
  468.                                 decfsz  Auxiliar_A,f
  469.                                 goto    Corre_ASCII
  470.                                 return
  471.  
  472. Finalizar
  473.                                 end
  474. ; Si la estamos ocupando como una subrutina en lugar del end colocamos un return
  475.  

Bueno, espero les guste y como siempre Salud 8)
« Última modificación: 30 de Octubre de 2010, 17:23:16 por SavageChicken »
No hay preguntas tontas...
Solo hay tontos que no preguntan.

Desconectado Veguepic

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2116
    • El Rincon de Veguepic
Re: Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #4 en: 16 de Octubre de 2010, 15:41:56 »
Hola SavageChiken

se me paso inadvertido el tema, pero esta muy sabroso y con muchas cosas que desconocia, gracias por la informacion!

Que pena no tener tiempo para retomar el asembler que me quedo inconcluso. :(

“Si la gente es buena sólo porque temen al castigo y porque esperan una recompensa, entonces verdaderamente somos un grupo lastimoso." Albert Einstein.

Saludos desde Lima , Peru    -    Hugo

Desconectado SavageChicken

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 916
Re: Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #5 en: 16 de Octubre de 2010, 19:11:28 »
Gracias Veguepic.
A todos nos tiene a mal traer el tiempo, hay que aprovechar un minutito cuando se pueda.

Salud 8)
No hay preguntas tontas...
Solo hay tontos que no preguntan.

Desconectado tapi8

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1506
Re: Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #6 en: 17 de Octubre de 2010, 05:13:37 »
Eres un artista, muy bueno  :-/ :-/
Yo lo vi cuando lanzaste el desafio, pero reconozco que me acojone, y preferi esperar que lo hicieras tu  :lol: :lol:
Muchas gracias.

Saludos

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 17671
    • MicroPIC
Re: Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #7 en: 17 de Octubre de 2010, 06:23:26 »
Muy bueno, pollo. ¡Qué malo es el aburrimiento y las ganas de complicarse la vida!  :D
Un saludo desde Sevilla, España.
Visita MicroPIC                                                                                        ɔ!doɹɔ!ɯ ɐʇ!s!ʌ

Desconectado SavageChicken

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 916
Re: Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #8 en: 17 de Octubre de 2010, 13:19:18 »
Eres un artista, muy bueno  :-/ :-/

Gracias por el halago Tapi.

Muy bueno, pollo. ¡Qué malo es el aburrimiento y las ganas de complicarse la vida!  :D

Hola Nocturno, tantas lunas sin toparnos en algún post.
Lo que dices es totalmente cierto, pero lo malo ahora es más bien la irresponsabilidad,  :D :D , porque tengo un montón de cosas importantes que hacer y me he puesto ha programar en assembler para sacarme el stress de encima, a veces esto de programar es un vicio.

Salud  8)
No hay preguntas tontas...
Solo hay tontos que no preguntan.

Desconectado SavageChicken

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 916
Re: Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #9 en: 30 de Octubre de 2010, 17:21:16 »
  Acabo de actualizar el código, le añadía una rutinita para convertir el resultado en un número que puede mostrarse en un display o transmitirse si se desea, pero el resultado queda como lo mostraría una calculadora.

  Para los que tengan la versión anterior, les recomiendo bajarse esta nueva, ya que también había un bug en mi código lo que causaba algunas multiplicaciones erroneas.

Salud  8)
No hay preguntas tontas...
Solo hay tontos que no preguntan.

Desconectado fabianjsm

  • PIC18
  • ****
  • Mensajes: 255
    • fabianjsm is on twitter
Re: Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #10 en: 30 de Octubre de 2010, 20:05:50 »
Buen trabajo SavageChicken, felicitaciones!
Tengo pendiente cumplir con el desafío  :mrgreen:
@fabianjsm is on twitter

Desconectado SavageChicken

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 916
Re: Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #11 en: 30 de Octubre de 2010, 21:26:20 »
  Hola Fabián.
  Me alegra que no hayas abandonado la idea de hacer tu código, te animo a hacerlo, ya que es entretenido ver como cada quién resuelve un mismo problema de formas distintas.

Salud  8)
No hay preguntas tontas...
Solo hay tontos que no preguntan.

Desconectado williamiprz

  • PIC10
  • *
  • Mensajes: 1
Re:Jugando con Binarios - Multiplicacion y Coma Flotante
« Respuesta #12 en: 27 de Octubre de 2019, 16:10:01 »
Hola SavageChicken, solo quería agradecerte el que compartas tus conocimientos, es bueno encontrarse con personas como tú. Casi 10 años después de tu publicación y sigue siendo un conocimiento valioso para los que estamos aprendiendo. Eres un capo. Muy agradecido. Una solución y una explicación muy buena y ahora una lección bien aprendida para mí.  ;-)