begin process at 2010 02 10 12:53:41
  Trouver un code source :
 
dans
 
Accueil > Forum > 

Delphi

 > 

Algorithme

 > 

Maths

 > 

Soucis avec les comparaisons de nombres réels


Derniers messages déposésPoser une question dans le forum ou lancer une discussion

Soucis avec les comparaisons de nombres réels

dimanche 7 décembre 2008 à 17:31:14 | Soucis avec les comparaisons de nombres réels

John Dogget

Salut à tous.

J'ecris une fonction qui transforme un nombre decimal en fraction non réduite (pour l'instant).
la technique est très simple, je multplie le nombre par 10,100,1000,x jusqu'à ce que la valeur après la virgule du produit soit nul.

Voici donc mon code :

function DecimalToFraction(NombreDecimal:extended):TFraction;
var
  Fraction:TFraction;
  Multiplicateur:int64;
  DecimalTemporaire:extended;
begin
  Multiplicateur:=1;
  DecimalTemporaire:=NombreDecimal;
  while Frac(DecimalTemporaire)<>0 do
  begin
    Multiplicateur:=Multiplicateur*10;
    DecimalTemporaire:=NombreDecimal*Multiplicateur;
  end;
  Fraction.Numerateur:=Trunc(DecimalTemporaire);
  Fraction.Denominateur:=Multiplicateur;
  Result:=Fraction;
end;

Ca marche très bien pour certaines valeurs, pour d'autres delphi me fait n'importe quoi

Exemple avec le nombre decimal 1.4615.

Le calcul se passe bien jusqu'au 4° passage dans la boucle, au dela Frac(DecimalTemporaire) me sors des valeurs bizarres.
A ce stade  on a normalement 1.4615*10000=14615, et donc Frac(14615) devrait être nul en toute logique, c'est pas le cas apparement puisque delphi me dit que Frac(14615) est egal à ... 8.881[...]e-16

J'ai cru comprendre que c'etait une chose normale, que ça venait de la représentation des nombres réels ...
Sauf que dans mon cas, c'est très genant, en plus d'être archi faux mathematiquement.
dimanche 7 décembre 2008 à 18:08:40 | Re : Soucis avec les comparaisons de nombres réels

Francky23012301

Membre Club
Salut,

Ce code fonctionne nickel chez moi :

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TFraction=Record
    Numerateur:Extended;
    Denominateur:Extended;
  End;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

Function Retourne_Fraction(NombreDecimal:extended):TFraction;
Begin
  Result.Denominateur:=1;
  Result.Numerateur:=NombreDecimal;
  While Frac(Result.Numerateur)<>0 Do
   Begin
     Result.Denominateur:=Result.Denominateur*10;
     Result.Numerateur:=Result.Numerateur*10;
   End;
End;

procedure TForm1.Button1Click(Sender: TObject);
Var
  Fraction:TFraction;
begin
  Fraction:=Retourne_Fraction(1.4615);
  Showmessage(FloatToStr(Fraction.Numerateur));
  Showmessage(FloatToStr(Fraction.Denominateur));
end;
dimanche 7 décembre 2008 à 18:46:28 | Re : Soucis avec les comparaisons de nombres réels

John Dogget

Hmm, tu as essayé avec d'autres valeurs qu'avec 1.4615 ?

Perso, je l'ai trouvé en utilisant une fonction test pour voir si le bug etait reproductible, une simple generation de nombre réels aleatoires avec une boucle sur la fonction qui calcul la fraction.

Dans mon cas ça aboutissait vite fait à un plantage de la fonction

Et aussi, le type TFraction que j'utilise est avec des int64, pas des extended comme tu le fait, tu penses que le problème vient de là ?

Tiens pis j'ai une autre question
Dans ta fonction tu travail directement avec le résultat de celle-ci, alors que moi je crée une variable de travail pour ça.
C'est une habitude ou bien ta soution est preferable à la mienne (rapidité, efficacité toussa)

Merci de ta réponse
dimanche 7 décembre 2008 à 19:06:58 | Re : Soucis avec les comparaisons de nombres réels

Francky23012301

Membre Club
J'ai essayé avec d'autres nombres et pas de plantages en vue

Pour le type utilisé j'ai pris un extended car c'est le type utilisé pour NombreDecimal. Il est pas impossible que ton probleme vient de cela.

Pour le Result que j'utilise : Ca évite d'utiliser une autre variable donc c'est un gain de performance. Cette technique est à bannir dans certains le cas de traitements lourds, ce qui n'est pas le cas ici .

Bon coding John
dimanche 7 décembre 2008 à 20:56:29 | Re : Soucis avec les comparaisons de nombres réels

John Dogget

Haha !!

J'ai reproduit le bug avec ton code Francky
Avec la valeur que j'avais donné avant, mais aussi avec pleins d'autres : 4.2295, 3.8265 etc etc

Pour moi, il y a bel et bien un soucis avec la fonction Frac.
Par curiosité, tu utilises quelle version de delphi ?
dimanche 7 décembre 2008 à 21:31:32 | Re : Soucis avec les comparaisons de nombres réels

Francky23012301

Membre Club
Je viens de tester tes 3 valeurs : je n'ai aucune erreur .
J'ai Delphi6 personnel : je pense pas que cela soit un beug de la fonction Frac.

Peux tu faire un copier coller exact de tout ton code stp que je teste avec ma version : merci .
dimanche 7 décembre 2008 à 21:45:14 | Re : Soucis avec les comparaisons de nombres réels

John Dogget

Oki.

Bon alors une form avec un memo et un bouton, qui va tester la fonction de calcul des fractions.

Son code :

procedure TForm1.Button1Click(Sender: TObject);
var
  Compteur:byte;
  ReelAleatoire:extended;
  Fraction:TFraction;
begin
  Memo1.Clear;
  ReelAleatoire:=1.225;
  for Compteur:=0 to 20 do
  begin
    Memo1.Lines.Add('Calcul de la fraction correspondant à '+FloatToStr(ReelAleatoire));
    Fraction:=DecimalToFraction(ReelAleatoire);
    Memo1.Lines.Add('   '+FloatToStr(Fraction.Numerateur)+'/'+FloatToStr(Fraction.Denominateur));
    ReelAleatoire:=ReelAleatoire+0.2365;
  end;
end;

Ensuite une unité à part pour toutes les fonctions de calcul

unit Fractions;

interface

uses Dialogs, Math, SysUtils;

type TFraction=record
  Numerateur:extended;
  Denominateur:extended;
end;

type TNombreDecompose=array of int64;

function DecimalToFraction(NombreDecimal:extended):TFraction;

implementation

Function DecimalToFraction(NombreDecimal:extended):TFraction;
begin
  Result.Numerateur:=NombreDecimal;
  Result.Denominateur:=1;
  While Frac(Result.Numerateur)<>0 Do
   Begin
     Result.Denominateur:=Result.Denominateur*10;
     Result.Numerateur:=Result.Numerateur*10;
     ShowMessage(FloatToStr(Result.Numerateur)+#13+
                 FloatToStr(Result.Denominateur)+#13+
                 FloatToStr(Frac(Result.Numerateur)));
   End;
end;

end.
dimanche 7 décembre 2008 à 23:20:05 | Re : Soucis avec les comparaisons de nombres réels

Francky23012301

Membre Club
Aucun problème pour ma part sauf au niveau du formatage du résultat qui laisse à désirer à partir d'une certaine valeur (Mais ce n'est pas pour l'instant le probleme).

T'es sur que tu as pas autre chose dans ton code qui serait à l'origine du problème ? Ca me surprend que Borland est changé la fonction Frac. Au pire tu as qu'a la recoder toi meme : c'est pas bien dur  à faire et comme ca tu es sur de plus te prendre la tete si tu viens un jour à changer de version de Delphi.

Allez t'énerve pas : tout probleme est formateur
dimanche 7 décembre 2008 à 23:56:52 | Re : Soucis avec les comparaisons de nombres réels

John Dogget

Ben c'est quand même bizarre qu'avec le même code, on n'arrive pas à la même chose.
Chez moi on voit clairement que la multiplication par dix se poursuit plus que necéssaire, et ce à cause de la fonction Frac puisque c'est elle qui contrôle "la manoeuvre".
Pour une raison que j'ignore Frac(un nombre au hasard)=0.00000000000000000000000000000000XYZ dans certains cas, et donc il ne donne pas 0 comme il devrait le faire

Par ailleurs, j'ai trouvé ceci : http://delphi.developpez.com/faq/?page=typenombre#comprarerreels
En gros ca explique que les comparaisons entre réels peuvent parfois mal tourner.

Je pense que je vais laisser tomber le côté mathematique de la chose, pour chercher une solution avec les chaines de caracteres
- on cherche le point de séparation decimal/entier
- on cherche la longueur de la partie arrière de la chaine (après la virgule donc)
- on calcul le denominateur avec (10 puissance longueur de la chaine)
- on efface le point de séparation dans la chaine de depart et on a le numerateur

C'est plus compliqué que la méthode mathematique, mais au moins ça marche ...
Tout ça pour mettre à jour une source que j'avais deposé ici il y aquelques temps, et la débarrasser de ses bugs

lundi 8 décembre 2008 à 06:06:19 | Re : Soucis avec les comparaisons de nombres réels

Jean_Jean

Ta fonction John fonctionne chez moi aussi!
Je n'ai jamais eu de probème avec frac à la condition de bien savoir ce que l'on prend de l'extended qui pose toujours des problèmes de limite. Mais dans ton cas tu ne retraites pas le calcul à partir de la partie fractionnaire résultante précédente, donc il ne devrait pas y avoir d'erreur. Peut-être est-ce un bug local ou ton processeur!?
Pour la valeur 1.00000000000000000001 qui comprend 21 chiffres significatifs, le résultat est 0 car le 1 est dans lanature à la 21ème place.
Tiens nous au courant!
Cordialement
Jean_Jean

1 2

Cette discussion est classée dans : nombres, fraction, multiplicateur, frac, decimaltemporaire


Répondre à ce message

Sujets en rapport avec ce message

Fraction [ par Faust ] Existe-t-il une routine ou un procédé qui permettrai de convertir un Real en Fraction ex: 0,5>>1/2J'ai cru trouver la solution en découvrant la foncti Converti Hexa en decimal [ par nekinox ] Voila j'ai ce probleme quand je veux lire un fichier reg il faudrais que je convertisse les nombres hexadecimal en nombres entier.Si vous avez une sol Dire le nombres d'items dans un ComboBox [ par MAsterC ] Comment fait-ton pour afficher le nombre d'items d'un TComboBox dans un TLabel et déterminer le rang d'un Item sélectionné dans le TComboBox dans un a convertir des lettres en nombres [ par cricri_b34 ] j'aimerais transformer un chaine de caractère en un valeur numérique; ex.: adlfas;ldfjasldfj en nimporte quel valeur numérique ex.: 2342342342242quel MULTIPLICATION DE NOMBRES [ par guy jeuniaux ] Quelqu'un pourait il me dire la conversion à faire pour multiplier :1,2*100=120en sachant que 1,2 est saisi dans un Edit.j'essaie :n1:=strtofloat(edit TmaskEdit et caractères A à Z et nombres [ par furax13 ] bonjour,j'aimerai signaler à un TmaskEdit que seuls les caractères de a à z (minuscule et majuscule) sont autorisés ainsi que les chiffres (0à9)De plu Multiplication de grands nombres... [ par greg505 ] Bonsoir a tous Dans le but de creer prog simple utilisant le principe du RSA... J'ai besoin de multiplier de grand nombres et d'afficher les resulta Affichage des nombres apres le vergule ds dbedit? [ par dahman ] G un dbedit lie a un champ d une table le nombre affiché contient plusieurs chiffres apres le vergule j ai pas trouve ou je peux limité l affichage a Opérations avec des nombres dans des TEdit [ par ced55957 ] bonjour voila je voudrais soustraire le nombre contenue dans un edit (edit1) avec le nombre contenue dans un autre edit (edit2), puis diviser le resu codes delphi [ par talibikeba ] bonjour ,je suis etudiant debutant en delphi s,il vous plais j'ai bésoin d'un programme en delphi qui permet de choisir 7 nombres dans un tableau deja


Nos sponsors


Sondage...

CalendriCode

Février 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,655 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales