Vamos a ver ahora la tercera operación aritmética, la multiplicación. Dados dos números, X e Y de n y m bits respectivamente, se trata de calcular el producto P como la multiplicación de X por Y. El valor más grande que puede tomar P corresponde al caso en que tanto la X como la Y tomen su valor máximo, 2 elevado a n-1 y 2 elevado a m-1. Haciendo unas pequeñas operaciones podemos ver que este valor es siempre menor que 2 elevado a n+m, es decir P siempre es un número que como máximo va a tener n+m bits. Veamos un primer algoritmo para realizar el producto, vamos a expresar Y como y_(m-1) por 2 elevado a (m-1) mas y_(m-2) por 2 elevado a (m-2), más y_1 por 2 más y_0, tengamos en cuenta que todas las y_i son simplemente 0s y 1s, y el producto lo vamos a escribir como X multiplicado por todo el número Y. El algoritmo simplemente lo que hace es calcular cada uno de estos productos parciales, esto sería p_0, esto sería p_1, esto sería p_(m-1) y finalmente sumarlos todos. Estos productos parciales son muy sencillos de realizar porque las y_i siempre son o 0s o 1s, es decir, el resultado será simplemente X por 2 o 0, o X por 2 al cuadrado o 0, y además sabemos que multiplicar por 2 elevado a i en general es añadir i 0s a la derecha del número resultante. Puesto que las y_i hemos dicho que son 0s o 1s, calcular cada uno de estos productos, calcular el producto del número X por y_i es algo tan sencillo como utilizar n puertas AND para ir generando los productos booleanos, porque las y_i sólo son o 0s o 1s. Oor otro lado, hacer los productos por las potencias de 2 quiere decir simplemente ir colocando 0s a la derecha, es decir, el producto p_0, X por y_0, imaginemos que nos da este resultado, lo colocaríamos aquí. El producto p_1, imaginemos que nos de este resultado, estamos haciendo este ejemplo, ¿vale? Lo colocaríamos para sumarlo pero habiéndole añadido previamente a la derecha un 0, o dicho de otra manera, desplazando previamente el producto p_1 una posición hacia la izquierda; p_2, que hay que multiplicarlo por 2 al cuadrado, lo pondríamos añadiéndole dos 0s; en este caso, fijaros que el bit del multiplicando es 0, es por eso que todo el resultado es 0. p_3, es cuando multiplicamos por este 1 y consistiría en multiplicar el resultado que hemos obtenido aquí por 2 elevado a 4, sería colocar este resultado con 3 ceros a la derecha. Aquí tenemos este segundo algoritmo que implementa de una manera digamos condensada los productos parciales más la suma de todos los productos parciales. Aquí tenemos un loop que va acumulando en una variable acc que inicialmente se ha inicializado a 0 los productos de X por y_i por 2 elevado a i. Este tipo de algoritmos sabemos bien como implementarlos, se trata en primer lugar de construir un módulo básico que implemente las operaciones internas al loop. Se tratará de este módulo básico donde va a entrar el producto del número X, esto serán n bits por el y_i correspondiente a un módulo que lo irá acumulando, que lo irá sumando habiendo añadido los 0s a la derecha que sean necesarios en cada momento, a un valor acumulador de entrada y generará el valor de acumulador de salida. En general este acumulador de salida en el caso máximo tendrá un total de n+m bits y por lo tanto el de entrada también. Y puesto que esto es una estructura loop que se repite m veces lo que hemos de hacer es concatenar o conectar un total de m módulos como el que acabamos de definir para tener el multiplicador que deseamos. Tengamos en cuenta, como siempre, que las líneas representan buses de tamaños n en este caso y m+n en el resultado final y en todos los resultados parciales, n+m, n+m, n+m, y las entradas X siempre son de n bits. Pues ya tenemos una manera de implementar la multiplicación con un sistema digital. Vamos a ver la última operación aritmética, la división. El planteamiento es el siguiente: dados dos números, X e Y de n bits se trata de calcular dos valores Q y R, cociente y resto, tal que se cumple esta condición. El cociente Q va a ser en general un número fraccionario. Para evitar el tener que ir controlando en cada momento cuántas cifras enteras y cuántas cifras fraccionarias tiene el cociente vamos a imponer la condición de que X sea menor que Y, o dicho de otra manera, vamos a forzar que Q sea un número fraccionario puro. Puesto que Q será un número fraccionario, de alguna manera hemos de determinar cuándo acabaremos la división, en el fondo, cuántos bits vamos a permitir que tenga el cociente Q. El número de bits de Q lo vamos a limitar a p bits, o lo que es lo mismo, vamos a definir o a forzar que la precisión del resultado será 2 elevado a menos p. Que la precisión sea 2 elevado a -p quiere decir que el error que cometemos al decir que Q es el resultado de la división de X partido por Y, el error este, va a ser menor que 2 elevado a -p o, lo que es lo mismo, X/Y-Q, que es lo mismo que R/Y, esto será menor que 2 elevado a -p; es decir, R será siempre menor que Y por 2 elevado a -p. Para calcular la división cuando no se cumpla esta condición de que la X sea menor que Y, será necesario alinear previamente los operandos y corregir el resultado obtenido. Lo que vamos a hacer en el caso de que la X sea mayor que la Y es sustituir la Y por una nueva Y que será igual a la original multiplicada por una cierta potencia de 2, digamos 2 elevado a k, tal que la X sí que sea menor a Y por 2 elevado a k. Una vez hecho esto, haremos la división de X entre Y', que ya cumple la condición de que X sea menor que Y', y a continuación el cociente que obtendremos tendremos que corregirlo multiplicándolo por 2 elevado a k. Para que la precisión del resultado sea de Q sea 2 elevado a -p necesitaremos calcular Q' con una precisión de 2 elevado a -p más k. Esta definición es equivalente a la que tenemos aquí a la derecha: Se trata de calcular una pareja de números, Q y R, cociente y resto, tal que X partido por Y sea igual al cociente más el resto partido por Y, donde Q es un múltiplo de 2 elevado a -p, es decir, la precisión de Q es 2 elevado a -p, sabiendo que el error cometido es siempre menor 2 elevado a -p. Aquí tenemos un algoritmo que refleja bastante fielmente el proceso manual de división. Inicializamos el resto, las r's son resto y las q's son los distintos bits del cociente, inicializamos el resto al valor de X y entramos en un loop que se repite p veces; recordemos que p es el número de bits del cociente Q. En cada iteración lo que hacemos es coger el resto, añadirle un 0 por la derecha y restarle el divisor Y. Si el resultado de esta resta es positivo, ponemos un 1 en el cociente y dejamos el resultado de la resta como resto. Si la d es negativa, ponemos un 0 en el cociente y añadimos un 0 más a la derecha del resto, ... y esto lo repetimos p veces. El resultado será una serie de valores binarios de bits q(i), que, puesto que sabemos que el número q es un número fraccionario puro, tendremos que multiplicar por 2 elevado a -p. Este sería el bit p-ésimo, y este sería el bit 1. Por la misma razón, el resto tendremos que calcularlo como el último valor calculado, el valor del resto calculado en la iteración p multiplicado por 2 elevado a p. Aquí tenemos un ejemplo cuando la X vale 21, la Y vale 35 y forzamos que la precisión del resultado sea 2 elevado a -6. Inicialmente en r pondremos el valor de X, y a continuación en la primera iteración en i=1, calculamos d como 2 por r, es decir, 21 por 2 = 42 menos 35, que es 7. Aquí tenemos el valor de d. Puesto que d es positivo, ponemos 1 en el cociente y dejamos esta diferencia en el resto. Pasamos a la siguiente iteración, i=2, calculamos de nuevo la d como 2 veces el resto anterior, es decir 14, dos por siete 14 menos 35 nos da -21. Como este valor es negativo ponemos un 0 en el cociente, y dejamos como resto el valor anterior multiplicado por 2. Tercera iteración, volvemos a multiplicar el último resto, 14 por 2, 28; le restamos 35, da -7. Como el resultado es negativo ponemos un 0 en el cociente y dejamos como resto el valor anterior multiplicado por 2, etc. Así podríamos continuar en la iteración número 4 calculamos d como 2 por 28 menos 35, que es 21; 21 es un número positivo, ponemos un uno en el cociente y dejamos este valor de d en el resto. Bien, así hasta la iteración sexta. Estos valores nos están diciendo cual será el cociente. El cociente será 1 0 0 1 1 0; 1 0 0 1 1 0 en base 2 multiplicado por 2 elevado a -p; es decir, este será el cociente; mientras que R será el último valor calculado de R, 14, dividido por 2 elevado a 6. Esto es un circuito capaz de realizar la división binaria. Como siempre, lo que hemos de hacer es crear un módulo básico capaz de implementar las operaciones internas al loop, este es el módulo básico, donde lo que podemos ver es que coge el número r, al que previamente se le ha concatenado un 0 por la derecha, es decir, coge 2 multiplicado por r, le resta el valor de Y, y obtiene un resultado d. Este resultado d puede ser positivo o negativo. En el caso de que sea positivo estaríamos en esta situación. En el cociente ha de aparecer un 1, de ahí que necesitemos este inversor, y en el resto colocamos el valor de d puesto que aquí tenemos un 0 se establece esta conexión, y en r me aparece d. Si por el contrario, la resta d ha sido un número negativo estamos en esta situación, hemos de poner un 0 en el cociente y, puesto que aquí tendremos un 1, establecemos esta conexión y en el resto colocamos el valor anterior del resto multiplicado por 2. Este 2 por r, otra vez, lo podremos implementar como r a la que hemos concatenado un 0 por la derecha. Puesto que el loop se ejecuta p veces, lo que hemos de hacer es utilizar p módulos como los que acabamos de definir concatenados de esta manera, conectados de esta manera, y este será el circuito capaz de realizar la división binaria. Valga decir que X e Y son números de n bits, por lo tanto estas líneas van a ser buses de n bits y, en general, el resto siempre es un valor menor que X. Puesto que aquí inicializamos el resto al valor de exactamente X, las salidas r van a ser también buses de n bits. Bien, pues este es el diseño final del divisor binario. Con esto acabamos esta lección. Hemos visto un conjunto de circuitos capaces de ejecutar las operaciones de suma, resta, multiplicación y división, y hemos introducido, aunque muy brevemente, la representación de números negativos mediante el complemento a 2.