Quelle est la meilleure façon de le faire en virgule fixe les mathématiques?
J'ai besoin pour accélérer un programme pour la Nintendo DS qui n'a pas de FPU, donc j'ai besoin de changer de mathématiques à virgule flottante (qui est émulé et lent) à virgule fixe.
Comment j'ai commencé, j'ai changé de flotteurs pour ints et chaque fois que je besoin de les convertir, j'ai utilisé x>>8 pour convertir le point fixe, variable x le nombre réel et x<<8 à se convertir à virgule fixe. J'ai vite constaté qu'il était impossible de garder une trace de ce que doit être converti et j'ai aussi réalisé qu'il serait difficile de changer la précision des nombres (8 dans ce cas.)
Ma question est, comment dois-je faire cela plus facile et toujours rapide? Devrais-je faire un FixedPoint classe, ou tout simplement un FixedPoint8 typedef ou struct avec certaines fonctions/macros pour les convertir, ou quelque chose d'autre? Dois-je mettre quelque chose dans le nom de la variable de montrer que c'est à point fixe?
- Il peut être utile de nous dire ce que vous êtes à l'aide de la flotte de.
Vous devez vous connecter pour publier un commentaire.
En C++ moderne implémentations, il n'y aura pas de perte de performances pour l'utilisation simple et maigre abstractions, telles que les classes de béton. Point fixe, le calcul est précisément l'endroit où l'utilisation d'un bien conçu classe va vous sauver de beaucoup de bugs.
Par conséquent, vous devriez écrire un FixedPoint8 classe. Test et débogage de fond en comble. Si vous avez à vous convaincre de sa performance par rapport à l'aide de la plaine des entiers, de les mesurer.
Il vous sauver de bien des ennuis par le déplacement de la complexité de point fixe de calcul à un seul endroit.
Si vous le souhaitez, vous pouvez augmenter encore plus l'utilité de votre classe en faisant d'elle un modèle pour remplacer l'ancien
FixedPoint8
avec, disons,typedef FixedPoint<short, 8> FixedPoint8;
Mais sur votre architecture cible ce n'est probablement pas nécessaire, afin d'éviter la complexité des modèles au premier abord.Il y a probablement un bon point fixe de la classe quelque part dans l'internet, j'ai commencé à la recherche de la Boost bibliothèques.
Votre virgule flottante code fait usage de la virgule? Si oui:
Vous devez d'abord lire Randy Yates du papier sur l'Intro de Point Fixe de Mathématiques:
http://www.digitalsignallabs.com/fp.pdf
Alors vous devez faire de "profilage" sur votre virgule flottante code pour comprendre la gamme appropriée de point fixe des valeurs à des points "critiques" dans votre code, par exemple U(5,3) = 5 bits vers la gauche, de 3 bits vers la droite, non signé.
À ce stade, vous pouvez appliquer les règles arithmétiques dans le document mentionné ci-dessus; les règles de préciser comment interpréter les bits qui résultent d'opérations arithmétiques. Vous pouvez écrire des macros ou des fonctions pour effectuer les opérations.
C'est très pratique pour garder la virgule flottante version autour de, afin de comparer la virgule flottante vs point fixe de résultats.
Je ne voudrais pas utiliser de virgule flottante sur un CPU sans matériel spécial pour la traiter. Mon conseil est de traiter TOUS les nombres entiers mise à l'échelle à un facteur spécifique. Par exemple, toutes les valeurs monétaires sont en cents comme des entiers plutôt que des dollars que des flotteurs. Par exemple, de 0,72 est représenté par l'entier 72.
L'Addition et la soustraction sont ensuite très simple d'entiers tels que (0.72 + 1 devient 72 + 100 devient 172 devient de 1,72).
La Multiplication est un peu plus complexe, car elle a besoin d'un nombre entier multiplier suivie d'une ampleur telle que (0.72 * 2 devient 72 * 200 devient 14400 devient 144 (une réduction) devient 1.44).
Qui peut exiger des fonctions spéciales pour l'exécution de mathématiques complexes (sinus, cosinus, etc), mais même ceux-ci peuvent être accéléré en utilisant les tables de recherche. Exemple: depuis que vous utilisez fixe-2 la représentation, il y a seulement 100 les valeurs de la plage (0.0,1] (0-99) et sin/cos répéter en dehors de cette plage si vous avez seulement besoin de 100 entiers table de recherche.
Cheers,
Pax.
Changement de point fixe des représentations est communément appelé "scaling".
Si vous pouvez le faire avec une classe sans perte de performance, alors que c'est le chemin à parcourir. Il dépend fortement de le compilateur et comment il inlines. Si il y a une perte de performance à l'aide de classes, alors vous avez besoin d'une approche plus traditionnelle de style C approche. L'approche de la programmation orientée objet vous donnera le compilateur forcée de sécurité de type traditionnel la mise en œuvre n'est qu'une approximation.
@cibyr a une bonne mise en œuvre de la programmation orientée objet. Maintenant, pour le plus traditionnel.
À garder la trace des variables sont mises à l'échelle, vous devez utiliser une convention cohérente. Une note à la fin de chaque nom de variable pour indiquer si la valeur est mise à l'échelle ou non, et d'écrire des macros SCALE() et UNSCALE() qui s'étendent à x>>8 et x<<8.
Il peut sembler comme un travail supplémentaire pour utiliser la notation, mais vous constaterez que vous pouvez voir en un coup d'œil que n'importe quelle ligne est correcte, sans regarder les autres lignes. Par exemple:
est évidemment faux, par l'inspection.
C'est une variante de la Apps hongrois idée que Joel mentionne dans ce post.
xPositionScaled = SCALE(SCALE(xPositionUnscaled * multUnscaled));
M.N
formats. Je suggère l'ajout de la exactM.N
format, par exemplespeed_fraction_F7_25 = fix_udiv(25, speed_percent << 25, 100 << 25); squared_speed_F7_25 = fix_umul(25, speed_fraction_F7_25, speed_fraction_F7_25); tmp1_F7_25 = fix_umul(25, squared_speed_F7_25, SQRT_3_F7_25); tmp2_F20_12 = fix_umul(12, tmp.F7_25 >> (25-12), motor_volt << 12);
(/100
est mieux réalisé que*0.01
). Oui c'est assez verbeux mais vous laisse avec le plein contrôle.Quand je l'ai rencontré pour la première fois de point fixe de chiffres que je trouve Joe Lemieux article, Point fixe de Mathématiques en C, très utile, et il n'en suggère un mode de représentation à virgule fixe des valeurs.
Je n'ai pas de liquidation à l'aide de sa représentation de l'union pour les nombres à virgule si. J'ai surtout de l'expérience avec point fixe dans C, donc je n'ai pas eu la possibilité d'utiliser une classe. Pour la plupart cependant, je pense que la définition de votre numéro de fraction de bits dans une macro et l'aide descriptif, les noms de variables rend assez facile de travailler avec. Aussi, j'ai trouvé qu'il est préférable d'avoir des macros ou des fonctions de multiplication et en particulier de la division, ou vous obtenez rapidement illisible code.
Par exemple, avec de 24,8 valeurs:
Qui écrit
Noter qu'il existe toutes sortes de dépassement d'entier problèmes avec ces macros, je voulais juste garder les macros simples. C'est juste un moyen rapide et sale exemple de la façon dont je l'ai fait en C. En C++, vous pourriez faire quelque chose de beaucoup plus propre en utilisant la surcharge d'opérateur. En fait, vous pouvez facilement faire que du code C beaucoup plus jolie aussi...
Je suppose que c'est un travail de longue haleine manière de dire: je pense que c'est OK pour utiliser un typedef et macro approche. Tant que vous êtes clair sur ce que les variables contiennent point fixe de valeurs, il n'est pas trop difficile à maintenir, mais il ne sera probablement pas aussi jolie qu'une classe C++.
Si j'étais dans votre position, je voudrais essayer d'obtenir un certain profilage des nombres pour montrer où les goulets d'étranglement. S'il y a relativement peu d'eux, puis aller avec un typedef et des macros. Si vous décidez que vous avez besoin d'un remplacement global de tous les flotteurs avec point fixe de maths même si, alors vous aurez probablement être mieux avec une classe.
La version originale de Astuces du Jeu Gourous de la Programmation a un chapitre entier sur la mise en œuvre de mathématique à virgule fixe.
Selon la façon dont vous décidez d'aller (j'avais pencher vers une définition de type et de certains RPC macros pour la conversion de), vous devez être prudent pour convertir en arrière avec une certaine discipline.
Vous trouverez peut-être que vous n'avez jamais besoin de les convertir en arrière et en avant. Imaginez toutes les choses dans l'ensemble du système est x256.