Forum Programmation.c Addition de flottants

Posté par  .
Étiquettes : aucune
0
6
fév.
2009
Bonjour,

Je recherche à faire l'addition de deux flottants.
Je cherche à ne faire un code du style :

float a=-1.3, b=2.4, c;
c=a+b;


En fait j'aimerais avoir l'algorithme (je ne le trouve nul part) avec les opérations à réaliser sur le bit de signe, sur les bits d'exposant et de mantisse.

Merci !
  • # linuxmag de fevrier

    Posté par  . Évalué à 2.

    il y a un article sur le probleme des nombres reels
    (avec l'explication des decalages de bits, et des explications que tu cherches)

    sinon il faut chercher des cours qui expliquent :
    - comment ecrire les entiers (positifs et negatifs)
    - comment ecrire les reels (nombre à virgule)
    - les operations mathematiques bit à bit (addition/soustraction/multi/division)

    puis il faut combiner les 3

    en effet l'operation

    A=-1.3
    B=2.4
    C=A+B

    revient à additionner des entiers d'une part ( -1 +2 ), et des reels d'autres parts (-0.3 + 0.4)
    puis d'additionner le resultat des 2
  • # il dit qu'il comprend pas

    Posté par  . Évalué à 3.

    Bonjour,

    je ne suis pas sur de bien saisir. Sur la plupart des processeurs, "l'algorithme" en question n'est pas réalisé au niveau du langage, mais par le processeur.
    Dans le cas enoncé, le compilo va se contenter de generer les opcodes floating point, et ce sera au processeur de se debrouiller pour faire l'addition des flottants.
    A part dans certains domaines particuliers, ce n'est pas au programmeur de s'occuper de gerer le bit de signe, l'exposant, et tout.
    Pour avoir l'algo, je pense qu'il vaut mieux regarder directement le standard :
    http://en.wikipedia.org/wiki/IEEE_754
    • [^] # Re: il dit qu'il comprend pas

      Posté par  . Évalué à 3.

      Je precise :
      si le but est de faire des additions de flottants sans flottants, il faut peut etre regarder du coté "fixed point arithmetic".
  • # Une implémentation

    Posté par  . Évalué à 2.

    Bonjour,

    Je m'étais amusé à coder ça il y à quelque temps. En fait j'ai commencé par la multiplication de short pour dériver sur la division puis les additions, division et multiplication flottantes. Tout ça juste avec des additions et des operations logique.

    Le code, pas franchement très propre, est ici http://snipt.org/tgk . L'addition flottante est dans fadd().

    L'idée c'est que chaque nombre est codé en 'mantisse*2^exposant'. Pour pouvoir additionner il faut donc que les deux exposant soit égaux, on multiplie donc l'exposant d'un des nombre pour obtenir le même exposant puis le résultat devient (mantisse1+mantisse2)*2^exposant.

    Ce code n'a évidemment aucun intérêt pratique en C mais il permet d'évaluer les algorithmes qui permettent de ré-implémenté ces opérations sur des petits microcontrolleurs (qui n'ont parfois même pas de multiplication hard), ou en hard justement (vhdl&co...)
    • [^] # Re: Une implémentation

      Posté par  . Évalué à 1.

      Merci c'était exactement ce que je cherchais.
      Je n'ai plus qu'à l'adapter à mon code :)
    • [^] # Re: Une implémentation

      Posté par  . Évalué à 1.

      Bonjour,

      J'aimerais mettre l'opérateur ternaire sous une forme "normale", mais je ne vois pas comment :

      res = (sr?(1<<31):0) | er | (((unsigned int)mr&0x7FFF)<<8);

      j'ai réussi à faire :

      res = (sr?(1<<31):0);
      res=res|er;
      res=res|(((unsigned long int)mr&0x7FFFF)<<8);


      Autre question, je dois avoir une mantisse en unsigned long int
      Je la récupère correctement, mais j'obtiens des résultats incorrects, voila mon code :

      void separeFloat (float x, char *sig, char *exp, unsigned long int *mant);

      float fadd(float a, float b) {
      char signe1, signe2, signeRes;
      unsigned long int mantisse1, mantisse2, mantisseRes;
      unsigned long int buf;
      char exposant1, exposant2, exposantRes;
      unsigned int res;

      separeFloat(a, &signe1, &exposant1, &mantisse1);
      separeFloat(b, &signe2, &exposant2, &mantisse2);
      //computation
      //Alignment
      if (exposant1>exposant2) {
      exposantRes = exposant1;
      while (exposant1>exposant2) {
      mantisse2>>=1;
      exposant2++;
      }
      } else {
      exposantRes = exposant2;
      while (exposant2>exposant1) {
      mantisse1>>=1;
      exposant1++;
      }
      }
      buf = (unsigned long int)mantisse1 + (unsigned long int)mantisse2;
      //Rescale
      while (buf>0xFFFFFFFF) {
      buf>>=1;
      exposantRes++;
      }
      mantisseRes = buf;
      // The sign is ignored (for the moment)
      signeRes = signe1;

      exposantRes<<=23;

      //RePack
      res = (signeRes?(1<<31):0);
      res=res|exposantRes;
      res=res|(((unsigned long int)mantisseRes&0x7FFFFFFF)<<8);


      return *((float*)&res);

      }

      Je ne vois pas où je me trompe, car je trouve :

      2.3 + -3.2 = 36893488147419103232.000000 -> gloups
      • [^] # Re: Une implémentation

        Posté par  . Évalué à 1.

        L'opérateur ternaire peut se remplacer par (en version longue ...) :
        if (sr!=0) {
        res = 0x80000000;
        } else {
        res = 0;
        }

        Sinon pour le résultat étrange ... je vois au moins 2 choses :
        si les mantisses sont alignés à droite, le réalignement après l'addition devrais être quelque chose comme "while(buf>0x0EFFFFFF)" (il faut que la mantisse résultante soit dans les 23Bits de poid faibles).
        Ensuite ces 23bits doivent être recopier dans les 23bits de poids faible du flottant, pour ça une ligne comme :
        res=res|(mantisseRes&0x0EFFFFFF);
        parais plus adapté.

        Enfin ce code ne gère pas les soustractions, donc dans le meilleur des cas tu obtiendra 5.5 (voir -5.5 si tu inverse a et b) :-).
  • # Optimisation

    Posté par  . Évalué à 4.

    Encore un qui va pondre une optimisation plus lente et plus grosse que le code d'origine.
    Sans parler de la lisibilité/maintenabilité :-)

    Plus sérieusement, et par curiosité, quel est le but de la manoeuvre ?
    • [^] # Re: Optimisation

      Posté par  . Évalué à 3.

      Perso j'ai pondu ce code principalement pour le fun (d'où la lisibilité ;). Pour voir s'il était possible de reforger un flottant compréhensible par le processeur (ça marche et rien que pour voir printf afficher que 21.5+20.5=42, avec l'addition faite à la main, ça vaut le coup :).

      Après, comme je l'ai déjà dit, en soit c'est totalement inutile, mais ça permet d'éprouver les algo dans un langage facile à coder et à déboguer (le C) pour les réimplémenter dans des langages un peu moins sympa a déboguer (comme en ASM pour microcontrolleur PIC16, ou en vhdl pour une implémentation hard).
      • [^] # Re: Optimisation

        Posté par  . Évalué à 2.

        j'ai pondu ce code principalement pour le fun
        Argument totalement recevable :-)
        J'avais étudié cela avec mon premier bouquin sur l'assembleur pour 80386 (ça ne s'appelait pas encore i386). Ca m'avait gravement barbé. Comme je n'ai jamais eu besoin d'utiliser des flottants (jamais, je cherche, mais jamais), ni en assembleur ni en quoi que ce soit (ah si, dans un tableur. Aucun rapport) alors ça reste pour moi un domaine que je garde bien a chaud au fond d'une boîte fermée à clef, mise dans un coffre placé dans un placard perdu dans un immeuble d'une ville anonyme au point que je ne connais même pas son nom. Ouf.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.