miércoles, 18 de marzo de 2020

Programa en C, algoritmo de la división de enteros usando acarreos o corrimientos (bitewise shift operator)

¡Buenas las tengan y mejor las pasen!

Desde hace meses tenía la inquietud de subir este programa, pero por fin hoy a estas horas de la madrugada en México me animo, si no lo hago ahora, ya no lo hago nunca…



Motivación


Bien es sabido por todos que existen 4 operaciones aritméticas elementales, suma, resta, producto y división. Pero en el caso de la división aunque esta bien definida sobre cualquier número real y hasta complejo (excepto la división sobre 0), puede que nos enfrentemos en algún momento al caso en el que solo necesitemos la parte entera de una división. 

Aunque hay algoritmos que pueden determinar cuantas veces un número se puede dividir sobre otro (incluso yo ya he manejado algunos), debemos hablar ya sobre algunas optimizaciones.

A saber, existen 4 operaciones aritméticas elementales, igual por breviario cultural sabemos que estas han sido llevadas ya a la computación (incluso originalmente, las computadoras eran calculadoras).
Pero no muchos sabemos que, al ser la operación división un tanto extravagante (es la única operación aritmética elemental que no es cerrada, es decir, que si operamos 2 enteros puede que no dé como resultado un entero), esta no ha sido portada a las computadoras de manera eficiente.

Por ello me he dedicado a buscar un programa que lo haga, y aunque lo encontré tuve que mejorarlo, ya que quien lo hizo tuvo un detalle que aunque a nivel personal me desagradó, pero a nivel operacional se podía hacer más eficiente un poquito más.

Explicación


Como primer paso, debemos entender que para cualquier procesador solo existen 2 operaciones comunes, los corrimientos; es decir, corrimiento a la izquierda y corrimiento a la derecha. Si bien otros más modernos ya operan con suma y resta, y otros más lujosos ya incluyen hasta producto o en algunos casos división, lo elemental son los corrimientos.

Pero para esto, debemos de saber algo de numeración base 2...




Sabemos que todo número base 10 tiene una representación en base N. Tomando un ejemplo, sabemos que el 7 en base 10 se representa como 111 en base 2 (o bien, en binario).

Un corrimiento hace que los dígitos en binario de un número se muevan hacia la izquierda o hacia la derecha, cambiando así el valor numérico de la cantidad.



Retomando el ejemplo del 7:
  • 1 corrimiento del 7 a la izquierda, hará que el 111 binario se convierta en 1110 binario, quedando el número 14 en base 10.
  • 2 corrimientos del 7 a la izquierda, harán que el 111 binario se convierta en 11100 binario, quedando el 28 en base 10.
  • 1 corrimiento del 7 a la derecha, hará que el 111 se convierta en 11, quedando el 3 en base 10.
    (NOTA: contrario al corrimiento izquierdo, en el derecho se pierden dígitos).
Aunque en binario es fácil de entender, en decimal tampoco es complicado, solo hace falta fijarnos que, si hacemos un corrimiento a la izquierda, en decimal la cantidad se multiplica por 2, y si hacemos corrimiento a la derecha, la cantidad se divide sobre 2, solo en caso de que la división no sea exacta, se pierde la parte decimal.


¿Por qué no simplemente usar el operador división?


Se puede, sin embargo, el operador división requiere 6 ciclos de reloj y el uso del co-procesador matemático. La operación corrimiento en cambio, ocupa solo 1 ciclo de reloj y en particular este programa, al no ocupar nunca operaciones producto o división nunca necesita de un co-procesador matemático, es decir, a nivel hardware se va a ejecutar mucho más rápido, con menos pesadez, y encima se puede llevar a cualquier chicharrón de hace 50 años que tenga un compilador de C y que no tenga tantos recursos. 😉


Manos a la obra



Como bien mencioné arriba, encontré alguien que implementaba un algoritmo de la división usando corrimientos, su programa no es malo, lo que hace (como en cualquier otro algoritmo de división) es que compara 2 cantidades, si el dividendo (el que divide) es más grande que el divisor (a quien se divide), se incrementa x2 el dividendo y se vuelve a comparar, este proceso se repite hasta que el dividendo es más grande que el divisor y se toma por tanto el anterior que aún no rebasaba al divisor. 
El problema con este programa es que para recorrer los números faltantes usaba un ciclo for, lo que lo convertía en un algoritmo de división tradicional.

Mi mejora consiste en que, usando 2 ciclos for, con el ciclo for anidado hago lo mismo que en el original, y con el for externo repito el proceso únicamente con acarreos, de modo que se reduce el tiempo de ejecución.

Sin más por el momento, les dejo el código en cuestión. Algunas cuestiones ya van saneadas, pero hace falta sanear si el idiota del usuario mete una letra o pendejadas de esas. :v



Link del programa: 




 Si tienen dudas, dejen un comentario y esperen a que se me quite la hueva de contestar, se me cuidan y que diosito me los bendiga xddd

No hay comentarios:

Publicar un comentario