Aritmética de punto fijo en microcontroladores

12

A menudo usamos microcontroladores para hacer cosas en nuestros robots, pero necesitamos hacer algunos cálculos en decimal. El uso de variables de punto flotante es muy lento, ya que se incluye automáticamente una biblioteca de punto flotante de software (a menos que tenga un microcontrolador de gama alta). Por lo tanto, generalmente usamos aritmética de punto fijo.

Cada vez que hago esto, solo uso un número entero y recuerdo dónde está el lugar decimal. Sin embargo, se debe asegurar que todo sea consistente, especialmente cuando los cálculos involucran variables donde el punto decimal está en un lugar diferente.

He implementado una función de punto fijo atan2, pero debido a que estaba tratando de exprimir hasta la última gota de precisión limitada (16 bits), a menudo cambiaba la definición de dónde está el punto decimal, y cambiaba a medida que lo ajustaba. Además, tendría algunas constantes, como una tabla de cuasi búsqueda, que tienen un punto decimal implícito en alguna parte.

Quiero saber si hay una mejor manera. ¿Existe una biblioteca, o conjunto de macros, que pueda simplificar el uso de variables de punto fijo, facilitando la multiplicación y división entre variables mixtas y permitiendo la declaración de números decimales o expresiones constantes, pero convirtiendo automáticamente a la representación de punto fijo deseada en la compilación ¿hora?

ronalchn
fuente
1
Creo que esto en realidad es mejor para stackoverflow ya que la solución es algo genérica y no tiene mucho que ver con la robótica.
Shahbaz
1
@Jakob: tenga en cuenta que ambas preguntas se cerraron por no ser constructivas.
Mark Booth
1
Este es el tipo de cosa que haría que C ++ sea muy útil para sistemas embebidos. Las plantillas generarían el código correcto y óptimo automáticamente.
Rocketmagnet
1
¿Puedo echar un vistazo a su función atan? Estoy tratando de abordar el problema de conversión de punto flotante a fijo en mi investigación académica y me encantaría resolverlo.
Joe Hass
1
Piezas @ronalchn de Arduino (un micro AVR) idioma se implementan en C ++. También hay una biblioteca AVR C ++ . Y este hilo en el que compiladores para usar.
embedded.kyle

Respuestas:

7

Sería bueno si pudiéramos decirle al compilador el rango y la precisión de cada variable de entrada de punto fijo (tal vez no hay dos que tengan el punto de radix en la misma ubicación), y usaría automáticamente el rango correcto en tiempo de compilación. y operaciones de precisión y reescalado para los valores intermedios y valores finales en una serie de cálculos. He escuchado rumores de que puede ser posible hacerlo en el lenguaje de programación Ada o en plantillas C ++.

Por desgracia, lo más cercano que he visto son las bibliotecas aritméticas de punto fijo que requieren que usted, el programador, elija manualmente la representación correcta y verifique manualmente que cada operación mantenga un rango y precisión adecuados. A veces facilitan la multiplicación y la división entre variables mixtas. Como:

David Cary
fuente
Es casi seguro hacer esto usando plantillas C ++.
Rocketmagnet
De hecho, estoy trabajando en algo como tu comentario de "sería bueno si ...". Es un complemento para gcc que convierte el código C de coma flotante en punto fijo, optimizando todas las ubicaciones de puntos binarios en el camino. Tengo un artículo enviado a una revista de ACM y otro en preparación. Si tiene código C para la función atan, me encantaría intentarlo ... Podría devolverle el código C que utiliza variables enteras y hace todo el material de punto fijo.
Joe Hass el
+1 para una respuesta mucho más completa que la mía. He editado el enlace en el mío para incluir un enlace a un lugar para solicitar el código fuente para abordar el comentario de Mark Booth. Es posible que también desee actualizar su enlace. Lo haría yo mismo, pero una edición sugerida está en la cola y me está bloqueando.
embedded.kyle
1
@Rocketmagnet Sin duda es posible implementar puntos fijos usando plantillas, vea FixedPoints (descargo de responsabilidad: escribí esto, y todavía es muy 'joven').
Pharap
enlace gcc "a" está roto
Lesto
2

He usado la Biblioteca TI IQMath para implementar punto flotante virtual en sus DSP de punto fijo.

Texas Instruments TMS320C28x IQmath Library es una colección de funciones matemáticas altamente optimizadas y de alta precisión para programadores C / C ++ para portar sin problemas un algoritmo de punto flotante en código de punto fijo en dispositivos TMS320C28x. Estas rutinas se usan típicamente en aplicaciones de tiempo real intensivas en cómputo donde la velocidad de ejecución óptima y la alta precisión son críticas. Al usar estas rutinas, puede alcanzar velocidades de ejecución considerablemente más rápidas que el código equivalente escrito en lenguaje ANSI C estándar. Además, al proporcionar funciones de alta precisión listas para usar, la biblioteca TI IQmath puede acortar significativamente el tiempo de desarrollo de la aplicación DSP.

Eso usa algunas cosas específicas de TI, pero también he usado ese código como base para implementar matemáticas virtuales de punto flotante en otros microcontroladores. El puerto requiere un poco de trabajo, pero es mucho más fácil que comenzar desde cero.

Embedded.kyle
fuente
@downvoter ¿Le gustaría comentar sobre lo que estaba mal en mi respuesta?
embedded.kyle
+1: Esta biblioteca es mejor de lo que está usando ahora ("solo usa un número entero"). No hace todo lo que pedía la pregunta original, pero creo que una respuesta como esta (útil, pero no una solución completa) no merece un voto negativo, a menos que exista una solución completa (lo cual dudo en este caso )
David Cary
Me parece que una respuesta que es específica para una única gama de dispositivos y que solo es gratuita como en cerveza y no como en discurso es de uso limitado para futuros visitantes.
Mark Booth
@ MarkBooth Cambié el enlace de la biblioteca C28x a la biblioteca C64x. Si sigue ese enlace, puede solicitar el código fuente. Necesita una empresa o un correo electrónico de la universidad para obtener acceso. Todavía libre como en cerveza y discurso. Solo necesita levantar la mano y esperar a que lo llamen antes de poder hablar. Un poco molesto, pero una vez que tenga el código fuente, puede adaptarse a cualquier procesador que desee.
embedded.kyle
Gracias @ embedded.kyle el código fuente es definitivamente mejor que solo binario, pero aún de poco uso general si la licencia solo le permite usarlo de manera limitada. Según la página de Bibliotecas de software C6x , esa fuente solo se publica bajo la licencia comercial de TI , que casi con certeza no es gratuita como en el discurso .
Mark Booth
1

Hay una serie de implementaciones (no hay bibliotecas de las que tenga conocimiento inmediato) de Binary Scaling (también conocido como B-scaling)

En esto, mantienes una nota mental (o incluso mejor, documenta el código ...) de dónde está el punto decimal, usando los cambios para mover el punto decimal hacia arriba o hacia abajo.

He utilizado la escala B en ensamblador en proyectos de defensa, incluso en las CPU más pequeñas, por lo que puedo garantizar su idoneidad para cualquier otra cosa ...

Andrew
fuente
Probablemente algo como esto, pero nunca lo he visto referido como escala b. Pienso en ello como punto fijo - el decimal nunca está flotando porque a pesar de la coma decimal podría cambiar en el transcurso de los cálculos, cualquier variable siempre tiene el punto decimal fijo en un lugar determinado
ronalchn
0

Si utiliza un número entero de recordar dónde el "punto" es, ellos son la clase de uso de la aritmética de coma flotante. Punto fijo, realmente tiene punto fijo .

Sospecho que para cada función habrá un "preprocesamiento" diferente para que su número de punto "flotante" sea adecuado para la función. Por ejemplo, para atan, desearía cambiar el número para que su punto decimal coincida con el de su función de punto fijo. Para cos, es posible que desee obtenerlo en el rango de y y luego cambiarlo.- πππ

Esto depende del rango de valores que necesita su aplicación, pero es posible que desee moverse por completo a una representación de punto fijo. Es decir, por ejemplo, en lugar de mantener un número como este:

struct num
{
    uint16_t number;
    uint16_t decimal_point;
};

donde numberestá el número entero y decimal_pointdice dónde está el punto decimal, puedes almacenarlo así:

struct num
{
    uint16_t integer;
    uint16_t fraction;
};

donde está el número entero integer.fraction, que tiene el mismo uso de memoria, mayor rango de valores y, en general, más simple de usar.

Shahbaz
fuente
El almacenamiento real del punto decimal lo hace más parecido a un punto flotante. Normalmente, el punto decimal se define en el momento de la compilación, y usted cambia entre representaciones dependiendo de su operación.
Jakob
No me refiero a recordar como está almacenado en una variable, me refiero a recordar como en Recuerdo cómo interpretar el resultado (sabiendo dónde está el punto decimal)
ronalchn
@ronalchn, ya veo. Querías decir algo como con un #define, ¿verdad? Pensé que realmente lo almacenabas y puede variar según cuán grande o pequeño sea tu número.
Shahbaz
@ronalchn: ¿estás pensando en la escala B? (ver mi respuesta)
Andrew