Si un hardware no admite operaciones de módulo o división, se necesitan muchos más ciclos de CPU para simular módulo / división por software. ¿Hay alguna forma más rápida de calcular la división y el módulo si el operando es 10?
En mi proyecto, con frecuencia necesito calcular el módulo entero 10. En particular, estoy trabajando en PIC16F y necesito mostrar un número en una pantalla LCD. Hay 4 dígitos para admitir, por lo que hay 4 llamadas a la función de módulo y división (implementación de software). Es decir, como el siguiente:
digit = number % 10; // call to an expensive function
number /= 10; // call to an expensive function
somehow_lit_segments();
digit = number % 10; // call to an expensive function
number /= 10; // call to an expensive function
somehow_lit_segments();
digit = number % 10; // call to an expensive function
number /= 10; // call to an expensive function
somehow_lit_segments();
digit = number % 10; // call to an expensive function
number /= 10; // call to an expensive function
somehow_lit_segments();
Hay otras áreas que usan un código similar.
Respuestas:
Aquí hay un algoritmo binario a BCD que utilicé hace varios años basado en uno encontrado aquí . Estaba usando un controlador de pantalla BCD externo a 7 seg para que el resultado pudiera escribirse en los puertos adecuados directamente como BCD empaquetado para la salida.
Esto es bastante rápido si tiene un multiplicador de hardware en el PIC, estaba usando un PIC18F97J60. Si no tiene un multiplicador de hardware en su PIC, considere usar shift + add para la multiplicación.
Esto toma un 16bit int sin firmar y devuelve BCD empaquetado con 5 dígitos, podría modificarse y hacerse más rápido para 4 dígitos. Utiliza las adiciones shift + para aproximar la división por 10, pero dado el rango de entrada limitado, es exacto para este uso. Es posible que desee empacar el resultado de manera diferente para alinearse con la forma en que usa el resultado.
fuente
Suponiendo enteros sin signo, la división y la multiplicación se pueden formar a partir de cambios de bits. Y a partir de la división (entera) y la multiplicación, se puede derivar el módulo.
Para multiplicar por 10:
Dividir por 10 es más difícil. Sé de varios algoritmos de división. Si recuerdo correctamente, hay una manera de dividir por 10 rápidamente usando cambios de bit y sustracción, pero no recuerdo el método exacto. Si eso no es cierto, entonces este es un algoritmo de división que administra <130 ciclos . No estoy seguro de qué micro está usando, pero puede usarlo de alguna manera, incluso si tiene que portarlo.
EDITAR: Alguien dice más en Stack Overflow , si puede tolerar un poco de error y tener un registro temporal grande, esto funcionará:
Suponiendo que tiene división y multiplicación, el módulo es simple:
fuente
Puede convertir de BCD a BCD empaquetado sin ninguna división utilizando el algoritmo de doble oscilación . Utiliza solo shift y add 3 .
Por ejemplo, convertir 243 10 = 11110011 2 a binario
Este algoritmo es muy eficiente cuando no hay un divisor de hardware disponible. Se usa más sobre solo el desplazamiento a la izquierda en 1, por lo que es rápido incluso cuando no hay una palanca de cambios de barril disponible
fuente
Dependiendo de la cantidad de dígitos que necesite, puede usar el método de fuerza bruta (
d
- número de entrada,t
- cadena ASCII de salida):También puede cambiar los if múltiples en un bucle, con potencias de diez obtenidas por multiplicación o una tabla de búsqueda.
fuente
Esta nota de aplicación describe algoritmos para aritmética BCD, incluida la conversión de binario a BCD y viceversa. La nota de aplicación es de Atmel, que es AVR, pero los algoritmos descritos son independientes del procesador.
fuente
No tengo una buena respuesta, pero hay una gran discusión en nuestro sitio hermano Stack Overflow sobre exactamente el mismo tema de división y optimización de módulos.
¿Tiene suficiente memoria para implementar una tabla de búsqueda?
Hackers Delight tiene un documento sobre algoritmos de división óptimos.
fuente
¿Ha considerado mantener ese valor como BCD todo el tiempo (usando simples subrutinas especiales "Incremento de BCD" y "Añadir BCD"), en lugar de mantener ese valor en forma binaria y convertirlo a BCD según sea necesario (usando una conversión más difícil de entender de binario a BCD "subrutina)?
En un momento, todas las computadoras almacenaron todos los datos como dígitos decimales (engranajes de diez posiciones, tubos de vacío de código de dos de cinco, BCD, etc.), y ese legado aún perdura en la actualidad. (vea ¿Por qué los chips de reloj en tiempo real usan BCD? )
fuente
La PICList es un recurso increíble para las personas que programan procesadores PIC.
Conversión BCD
¿Ha considerado utilizar una subrutina binaria a BCD probada y probada, optimizada específicamente para el PIC16F?
En particular, las personas en la PICList han pasado mucho tiempo optimizando las conversiones de binario a BCD en un PIC16F. Esas rutinas (cada una optimizada a mano para un tamaño específico) se resumen en "Métodos matemáticos de conversión de radix de microcontoller PIC" http://www.piclist.com/techref/microchip/math/radix/index.htm
división entera y mod
En una CPU como la PIC16F, una subrutina especializada para dividir por una constante es a menudo mucho más rápida que una rutina de "división de variable A por variable B" de propósito general. Es posible que desee colocar su constante (en este caso, "0.1") en la "Generación de código para la multiplicación / división constante" http://www.piclist.com/techref/piclist/codegen/constdivmul.htm o consulte el rutinas enlatadas cerca de http://www.piclist.com/techref/microchip/math/basic.htm .
fuente
Dada una multiplicación de hardware de 8x8, se puede calcular un divmod-10 de un número de tamaño arbitrario mediante una rutina que lo calcula para un número de 12 bits en el rango de 0-2559 a través del procedimiento:
Sugeriría escribir una rutina divmod en la que el MSB del número estará en W, y el LSB señalado por FSR; la rutina debe almacenar el cociente en FSR con post-decremento y dejar el resto en W. Para dividir un largo de 32 bits por 10, uno usaría algo como:
Un paso divmod-6 sería muy similar, excepto el uso de constantes de 85 y 6 en lugar de 51 y 10. En cualquier caso, esperaría que divmod10_step sea 20 ciclos (más cuatro para la llamada / retorno), por lo que un breve divmod10 sería sería de aproximadamente 50 ciclos y un divmod10 largo sería de aproximadamente 100 (si un caso especial es el primer paso, se podrían ahorrar algunos ciclos).
fuente
Esto puede no ser el más rápido, pero es una forma simple.
fuente