Arithmétique à virgule fixe sur les microcontrôleurs

12

Souvent, nous utilisons des microcontrôleurs pour faire des choses dans nos robots, mais nous devons faire des calculs en décimal. L'utilisation de variables à virgule flottante est très lente, car une bibliothèque logicielle de virgule flottante est automatiquement incluse (sauf si vous avez un microcontrôleur haut de gamme). Par conséquent, nous utilisons généralement l'arithmétique à virgule fixe.

Chaque fois que je fais cela, j'utilise simplement un entier et je me souviens où se trouve la décimale. Cependant, il prend un certain soin pour s'assurer que tout est cohérent, en particulier lorsque les calculs impliquent des variables où le point décimal est à un endroit différent.

J'ai implémenté une fonction atan2 à virgule fixe, mais comme j'essayais de presser chaque dernière goutte de précision limitée (16 bits), je changeais souvent la définition de l'endroit où se trouve le point décimal, et cela changerait au fur et à mesure que je le peaufinais. De plus, j'aurais certaines constantes, comme une table de quasi-recherche, qui elles-mêmes ont un point décimal implicite quelque part.

Je veux savoir s'il y a une meilleure façon. Existe-t-il une bibliothèque ou un ensemble de macros qui peuvent simplifier l'utilisation des variables à virgule fixe, facilitant la multiplication et la division entre les variables mixtes, et permettant la déclaration de nombres décimaux ou d'expressions constantes, mais convertissant automatiquement la représentation en virgule fixe souhaitée lors de la compilation temps?

ronalchn
la source
1
Je pense que cela est en fait mieux pour stackoverflow car la solution est plutôt générique et n'a pas grand-chose à voir avec la robotique.
Shahbaz
1
@Jakob - Notez que ces deux questions ont été fermées car non constructives.
Mark Booth
1
C'est le genre de chose qui rendrait le C ++ très utile pour les systèmes embarqués. Les modèles généreraient automatiquement le code correct et optimal.
Rocketmagnet
1
Puis-je voir votre fonction atan? J'essaie de résoudre le problème de la conversion en virgule flottante en virgule fixe dans mes recherches universitaires et je serais heureux de tenter le coup.
Joe Hass
1
Pièces @ronalchn d'Arduino (un AVR micro) langue sont implémentés en C ++. Il existe également une bibliothèque AVR C ++ . Et ce fil sur lequel les compilateurs à utiliser.
embedded.kyle

Réponses:

7

Ce serait bien si nous pouvions dire au compilateur la plage et la précision de chaque variable d'entrée à virgule fixe (peut-être pas deux ayant le point de radix au même endroit), et il utiliserait automatiquement - au moment de la compilation - la plage correcte et des opérations de précision et de redimensionnement pour les valeurs intermédiaires et les valeurs finales dans une série de calculs. J'ai entendu des rumeurs selon lesquelles il serait possible de le faire dans le langage de programmation Ada ou dans les modèles C ++.

Hélas, le plus proche que j'ai vu est les bibliothèques arithmétiques à virgule fixe qui vous obligent, le programmeur, à choisir manuellement la représentation correcte et à vérifier manuellement que chaque opération conserve une plage et une précision adéquates. Parfois, ils facilitent la multiplication et la division entre les variables mixtes. Tel que:

David Cary
la source
Il est presque certainement possible de le faire en utilisant des modèles C ++.
Rocketmagnet
Je travaille en fait sur quelque chose comme votre commentaire "ce serait bien si ...". Il s'agit d'un plugin pour gcc qui convertit le code C à virgule flottante en virgule fixe, optimisant tous les emplacements de points binaires en cours de route. J'ai un article soumis à un journal ACM, et un autre en préparation. Si vous avez du code C pour la fonction atan, je serais heureux de lui donner un coup de feu ... Je pourrais vous rendre le code C qui utilise des variables entières et fait toutes les choses en virgule fixe.
Joe Hass
+1 pour une réponse beaucoup plus complète que la mienne. J'ai modifié le lien dans le mien pour inclure un lien vers un endroit pour demander le code source pour répondre au commentaire de Mark Booth. Vous pouvez également mettre à jour votre lien. Je le ferais moi-même mais une modification suggérée est dans la file d'attente et me bloque.
embedded.kyle
1
@Rocketmagnet Il est très certainement possible d'implémenter des points fixes en utilisant des modèles, voir FixedPoints (clause de non-responsabilité: j'ai écrit ceci, et c'est toujours très «jeune»).
Pharap
le lien gcc "a" est cassé
Lesto
2

J'ai utilisé la bibliothèque TI IQMath pour implémenter des virgules flottantes virtuelles sur leurs DSP à virgule fixe.

La bibliothèque IQmath de Texas Instruments TMS320C28x est une collection de fonctions mathématiques hautement optimisées et de haute précision pour les programmeurs C / C ++ afin de porter de manière transparente un algorithme à virgule flottante en code à virgule fixe sur les appareils TMS320C28x. Ces routines sont généralement utilisées dans des applications en temps réel à forte intensité de calcul où une vitesse d'exécution optimale et une grande précision sont essentielles. En utilisant ces routines, vous pouvez atteindre des vitesses d'exécution considérablement plus rapides que le code équivalent écrit en langage C ANSI standard. De plus, en fournissant des fonctions de haute précision prêtes à l'emploi, la bibliothèque TI IQmath peut réduire considérablement le temps de développement de votre application DSP.

Cela utilise des éléments spécifiques à TI, mais j'ai également utilisé ce code comme base pour implémenter des mathématiques virtuelles à virgule flottante sur d'autres microcontrôleurs. Il faut un peu de travail pour mettre en communication, mais c'est beaucoup plus facile que de partir de zéro.

embedded.kyle
la source
@downvoter Care pour commenter ce qui n'allait pas avec ma réponse?
embedded.kyle
+1: Cette bibliothèque est meilleure que ce qu'il utilise actuellement ("utilisez simplement un entier"). Il ne fait pas tout ce que la question initiale demandait, mais je pense qu'une réponse comme celle-ci (utile, mais pas une solution complète) ne mérite pas un vote négatif - à moins qu'une solution complète n'existe réellement (ce dont je doute dans ce cas ).
David Cary
Il me semble qu'une réponse spécifique à une seule gamme d'appareils et gratuite uniquement comme dans la bière plutôt que dans la parole est d'une utilité limitée pour les futurs visiteurs.
Mark Booth
@MarkBooth J'ai changé le lien de la bibliothèque C28x vers la bibliothèque C64x. Si vous suivez ce lien, vous pouvez demander le code source. Vous avez besoin d'une entreprise ou d'un e-mail universitaire pour y accéder. Toujours gratuit comme dans la bière et le discours. Il vous suffit de lever la main et d'attendre d'être appelé avant de pouvoir parler. Un peu ennuyeux, mais une fois que vous avez le code source, il peut être adapté à n'importe quel processeur que vous aimez.
embedded.kyle
Le code source de Thanks @ embedded.kyle est certainement meilleur que le binaire uniquement, mais reste de peu d'utilité générale si la licence ne vous permet de l'utiliser que de manière limitée. Selon la page des bibliothèques de logiciels C6x, cette source n'est publiée que sous la licence commerciale TI , qui n'est certainement pas gratuite comme dans la parole .
Mark Booth
1

Il existe un certain nombre d'implémentations (pas de bibliothèques que je connaisse immédiatement) de la mise à l'échelle binaire (aka B-scaling)

En cela, vous gardez une note mentale (ou encore mieux, documentez le code ...) de l'endroit où se trouve le point décimal, en utilisant des décalages pour déplacer le point décimal vers le haut ou vers le bas.

J'ai utilisé la mise à l'échelle B dans l'assembleur sur des projets de défense, même sur les plus petits processeurs, donc je peux garantir sa pertinence pour autre chose ...

Andrew
la source
Probablement quelque chose comme ça, mais je ne l'ai jamais vu appelé b-scaling. Je le considère comme un point fixe - la décimale n'est jamais flottante car même si la virgule décimale peut changer au cours des calculs, une variable a toujours la virgule fixe à un endroit particulier
ronalchn
0

Si vous utilisez un entier pour vous rappeler où se trouve le «point», ils utilisent en quelque sorte l' arithmétique à virgule flottante. Point fixe, a vraiment un point fixe .

atancosππ

Cela dépend de la plage de valeurs dont votre application a besoin, mais vous souhaiterez peut-être passer complètement à une représentation à point fixe. C'est, par exemple, au lieu de garder un nombre comme celui-ci:

struct num
{
    uint16_t number;
    uint16_t decimal_point;
};

numberest le nombre entier et decimal_pointindique où se trouve le point décimal, vous pouvez le stocker comme ceci:

struct num
{
    uint16_t integer;
    uint16_t fraction;
};

où le nombre entier est integer.fraction, qui a la même utilisation de la mémoire, une plage de valeurs plus élevée et en général plus simple à utiliser.

Shahbaz
la source
En fait, le stockage du point décimal le rend plus comme un point flottant. Normalement, le point décimal est défini au moment de la compilation et vous changez de représentation en fonction de votre opération.
Jakob
Je ne veux pas dire se souvenir comme dans stocké dans une variable, je veux dire me rappeler comme dans je me souviens comment interpréter le résultat (en sachant où est le point décimal)
ronalchn
@ronalchn, je vois. Vous vouliez dire quelque chose comme avec un #define, non? Je pensais que vous le stockiez réellement et qu'il pouvait varier en fonction de la taille de votre numéro.
Shahbaz
@ronalchn - pensez-vous à l'échelle B? (voir ma réponse)
Andrew