Floating point

Résolu
Messages postés
38
Date d'inscription
mardi 31 janvier 2006
Statut
Membre
Dernière intervention
4 avril 2008
-
Messages postés
4
Date d'inscription
mercredi 4 août 2004
Statut
Membre
Dernière intervention
5 janvier 2009
-
Dans une base de donnée utilisée pour un de mes programmes, j'ai des données qui ont comme type de champs la valeur reel simple. La base de donnée communique avec le programme via Ado. Donc dans la base de donnée j'ai les valeurs 26.3. Mais a l'affichage dans le programme, la valeur de ce champs est de 26.299365489 ce qui en valeur arrondie me donne 26.3.

Mais le hic ce que je me sert de cette donnée pour en afficher d'autre. Mais comme le programme intercepte la valeur de 26.3 comme 26.299... les autres donnée ne sont donc pas affichée. De plus c'est valeur doit etre de type numérique et non chaine de caractère parce que j'utilise le tri numérique pour ordonnancer ces données...

Le pire c'est quand je fais un query sur ma table du style select * from clc where (cas = 26.3), le query me trouve l'enregistrement.

Quelqu'un saurait me dire pourquoi la basse de donnée me donne la valeur de 26.3 alors que le programme affiche la valeur de 26.299...

Merci
Jerome

10 réponses

Messages postés
814
Date d'inscription
vendredi 3 novembre 2000
Statut
Membre
Dernière intervention
30 juillet 2009
3
Salut,

Cela vient de la manière dont est stocké la valeur en mémoire (du PC).

Pour faire dans le simplifié, Les nombres flotant sont stocké sous la forme "scientifique" cad 'base' x 10~'Puissance' (+signe)

La base est stocké avec un nombre finit de bit (disons 15 pour l'exemple).

Donc quand tu écrit 26.3, il vas arrondire la base (263) au nombre le plus pres d'une puissance de 2 (1 à 2^15-1).

Après quand tu "relit" la valeur, il te retourne toute la précision qu'il a (26299...). Même celle que tu ne lui a pas donné.

C'est pour ça qu'il ne FAUT JAMAIS FAIRE DE TEST D'EGALITE AVEC DES FLOTANT !!!!

C'est aussi pour ça que tu peut additionner 1e-10 à une var floatant qui vaut 10e40 pendant toute une journée sans que la var ne change de valeur.

fait un test genre :

(cas < Limit + Epsilon) and (cas > limit - Epsilon)

avec un Epsilon qui vaut genre 0.002. (enfin, ça dépend de bcp de choses)

Chaque fois que possible, évite les type flotant, remplace les par des integer avec une ponderation (facteur).


"De plus c'est valeur doit etre de type numérique et non chaine de caractère parce que j'utilise le tri numérique pour ordonnancer ces données..."

je connais pas les détail de ton cas, mais il y a surement un moyen de le lire directement en floatant.

bon code,
Messages postés
4202
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
13 juin 2020
38
utilise la virgule fixe.

26.3 = 2630/100 << depend de l'interval Min..Max des chiffres et de la precision voulue 1..n decimales

stockage en entiers : round(Float*100)

si je joue dans l'interval : 0..1000 avec precision maxi de 3 decimale, je multiplie par 1000
Fin := round(F*1000);
Fout := Fin/1000;

le tri de chaine en valeur flottante risque de faire n'importe quoi ...

en tout cas on index pas des valeurs avec des flottant justement a cause de ça.

champs ID : int / unique / auto increment / non null
champs Valeur : float / null

<hr size="2" width="100%" />Croc (click me)
Messages postés
38
Date d'inscription
mardi 31 janvier 2006
Statut
Membre
Dernière intervention
4 avril 2008

Ah oui une chose importante peut etre, la valeur de 26.3 dals la base de donnée est recupérée avec le composant DBEdit. C'est peut etre ca le probleme... Je check et vous tiens au courant...

Si quelqu'un, trouve avant moi, merci de poster vos commentaires...

Jerome
Messages postés
38
Date d'inscription
mardi 31 janvier 2006
Statut
Membre
Dernière intervention
4 avril 2008

Y pas une solution pour lire le nombre comme il est tape dans la base de donnée??
Messages postés
814
Date d'inscription
vendredi 3 novembre 2000
Statut
Membre
Dernière intervention
30 juillet 2009
3
oui, il faut utiliser un champ string pas floatant.

ou si t'as toujours la même précision lors de la saisie, fait une routine de formatage.
Messages postés
38
Date d'inscription
mardi 31 janvier 2006
Statut
Membre
Dernière intervention
4 avril 2008

Avec une chaine string, tu sais faire un tri numerique sur les donnees??
Messages postés
814
Date d'inscription
vendredi 3 novembre 2000
Statut
Membre
Dernière intervention
30 juillet 2009
3
au pire des pire, fait un champs en flotant que tu utilise pour le tri et un en string pour avoir ta "saisie". (très moche)

Mais j'éviterais si j'étais toi, y a surement un moyen de résoudre ton problème en changeant deux-trois trucs dans ton system.

De toute façon, tu peux marquer 'dommage' pour faire un test d'égalité (unique) avec un flotant.
Messages postés
38
Date d'inscription
mardi 31 janvier 2006
Statut
Membre
Dernière intervention
4 avril 2008

oui c'est vrai que c'est moche comme solution. J'ai fait changer le fusil d'epaule de loa sncb qui a abandonner le projet de mettre un cas intermedaire. Ex: 26 26BIS et 27 (si je les mettais en chaine de caractere) j'aurais pas eu cet ordre la. Maintenant la solution etait de garder le champs numerique mais de mettre 26 26,1 et 27 dans la base de donnée. Mais le projet a ete abandonné. Merci pour ton explication Loda j'avais pas capté cela comme ca mais c'est vrai que les float c'est de la M....

Jerome
Messages postés
814
Date d'inscription
vendredi 3 novembre 2000
Statut
Membre
Dernière intervention
30 juillet 2009
3
de rien.

si j'ai bien compris, tu utilise la partie fractionnaire de ton float pour distinguer des cas?!

pourquoi tu n'utilise pas un champs supplémentaire ? cela te permeterait de faire ton trie facilement.

(les float c'est fait pour manipuler des valeurs floattant. faut pas s'en servire pour autre choses.)

bon code,
Messages postés
4
Date d'inscription
mercredi 4 août 2004
Statut
Membre
Dernière intervention
5 janvier 2009

procedure TForm1.Button1Click(Sender: TObject);
var a,b,c,d,e,f,n,o,k: string;
    i,j,g,m,x,y,v: integer;
    tr: boolean;
begin
j := 0;
k := '';
tr := false;while (j <length(edit1.Text)) and (tr false) do
   begin
     k := edit1.Text[j];
     if k = '.' then
       begin
        tr := true;
        v := j;
       end;
     j := j + 1;
   end;
if tr = true then
begin if (length(edit1.Text) - v 1) or (length(edit1.Text) - v 2)  then
  edit2.text := edit1.Text
else
begin
i := 1;
m := 0;
c := '';
b := '';
while i <= length(edit1.Text) do
  begin
     c := edit1.Text[i];
     b := b + c;
      if c = '.' then
        begin
          a := b;
          m := i;
        end;
     i := i + 1;
  end;
d := edit1.Text[m + 1];
e := edit1.Text[m + 2];
f := edit1.Text[m + 3];
n := d + e;
if StrToInt(f) >= 5 then
  begin
    g := StrToInt(n) + 1;
    n := IntToStr(g);
    if g = 100 then
        begin
          o := '';
          for x := 1 to m - 1 do o := o + a[x];
          y := StrToInt(o) + 1;
          edit2.Text := IntToStr(y);
        end
       else
           edit2.Text := a + n;
  end
     else
       begin
         edit2.Text := a + n;
       end;
end;
end
  else
    edit2.text := edit1.Text;
end;

The joy of the life is to do a work that nobody made and that nobody it imagined