Bienvenue aux nouveaux arrivants sur FantasPic !

- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.

--- L’équipe FantasPic ---
Forum général sur le langage C !

Modérateur : Jérémy

Optimiser des multiplications sur PIC16
Naheulf
Membre
Membre
Messages : 2
Enregistré en : janvier 2021

#21 Message par Naheulf » dim. 3 janv. 2021 21:59

Bonjour et bonne année !

Je ne connais ni le besoin en précision ni le besoin en vitesse du projet. Mais il y a encore deux optimisations possibles à apporter au calcul.

Optimisation 1 : Décalage de 16 bits
Cette optimisation peut améliorer la vitesse du calcul présenté dans le post précédent, sans perdre en précision, mais en devenant fort dépendant de la structure interne du micro-contrôleur.
Elle consiste à simplifier le calcul en ne lisant que les bits qui nous intéressent. Cela revient à trouver le nombre de milliers dans 123 456 en ne lisant que les milliers et en ignorant les centaines, les dizaines et les unités. Cela n’est possible que si le décalage voulu est un multiple de du décalage de 1 dans les adresses mémoire.
L’idée est de remplacer

Code : Tout sélectionner

mavar >> 16
par

Code : Tout sélectionner

((unsigned word *)((@mavar) + 1))
dit autrement cela consiste à lire uniquement le registre haut du long.

Optimisation 2 : Simplifier le calcul
Cette optimisation améliorera la vitesse de calcul présenté dans le post précédent au prix d’une perte de précision en nombre de chiffres significatifs. Elle n’est pas dépendante du matériel mais de l’amplitude connue des nombres entrant en jeu.
Si j’ai bien compris on a une valeur positive mesuré qui va de 0 à 1 000 000 que l’on doit multiplier par un facteur positif choisi parmi une liste de valeurs déjà connues à la compilation.
Le contrôleur supporte des calculs sur 32 bits. On a donc 32 bits pour stocker les bits intermédiaires.
La valeur mesurée va jusqu’à 1 000 000. Elle nécessite donc jusqu’à 20 bits pour être représentée.
Comme le produit de deux nombres utilise autant de chiffres que la somme des chiffres de chacun des deux facteurs, on en déduit qu’il « reste » 12 bits pour représenter l’autre facteur.
Prenons l’exemple du facteur 3,2568 utilisé dans les posts précédents dont on va chercher à récupérer les 12 premiers bits significatifs.
La partie entière (3) nécessite 2 bits pour son écriture. Cela laisse 10 bits pour représenter les décimales en binaire. Pour les récupérer, il faut décaler la virgule binaire de 10 chiffres. Cela revient à multiplier par 2^10 ce qui donne 3 334,9632. Pour garder un maximum de précision on arrondit à l’entier le plus proche soit 3335. Le calcul à effectuer devient (pour ce coefficient) :

Code : Tout sélectionner

affiche = (mesure * 3335) >> 10

Parlons maintenant de la perte de précision. La valeur mesurée est gardée entière et ne subit donc pas de perte de précision. En revanche, le coefficient est enregistré sous forme ne nombre à virgule flottante à 12 bits significatifs (ce qui est moins précis que les 23 bits d’un float). Il y a donc 12*Log 10(2) = 3,612 chiffres significatifs. Comme les morceaux de chiffres significatifs sont un peu obscures, on va faire le calcul autrement. Par construction on a un chiffre à 12 bits dont le premier est à « 1 ». L’erreur possible est alors de 1 / (2^12) = 0,024 %, ce qui revient à une erreur de plus ou mois 0,2 mm sur une mesure de 1 m.

Remarques :
paulfjujo a écrit :Source du message des qu'on utilise une multiplication ou division, on embarque dans le code toute la librairie Maths

Cela dépend du compilateur et des instructions disponibles dans le contrôleur. Je ne sais pas si c'est le cas ici (je n'ai pas cherché à savoir)

Toujours selon le microcontrôleur et les optimisations du compilateur, il peut être préférable (en termes de vitesse) de remplacer un code du type :

Code : Tout sélectionner

coeff = liste[choix];
affiche = mesure * coeff
par une structure du type :

Code : Tout sélectionner

switch(choix) {

   case 0  :  affiche = mesure * 1.4142; break; // premier coeff : racine(2)
   case 1  :  affiche = mesure * 3.1415; break; // second coeff : pi
   case 2  :  affiche = mesure * 3.2568; break; // troisième coeff
   // …
   default : affiche = mesure
}
Cela permet au compilateur de générer des instructions de multiplication optimisés pour les valeurs constantes définies dans le code ; À condition que le compilateur ne transforme pas les « case » en une looongue suite de « If » qui met trois plombes à s’exécuter, plombant les bénéfices de la manip.


Retourner vers « Langage C »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 50 invités