Comment comparer le double en Delphes?

Nous sommes confrontés à un problème avec la double comparaison de type de données:

if(p > pmax) then
begin
  Showmessage('');
end

Si les deux valeurs sont 100 (P=100 et pmax = 100), alors aussi il va à l'intérieur de la clause if.

27
demandé sur Toon Krijthe 2011-05-24 09:35:58

2 réponses

Il y a plusieurs problèmes avec la comparaison des Doubles. Un des problèmes est que ce que vous voyez n'est pas exactement ce que vous obtenez en raison de l'arrondissement. Vous pouvez avoir 99.999999996423 et 100.00000000001632, qui sont tous deux arrondis à 100, mais ils ne sont pas égaux.

La solution est d'utiliser une marge de sorte que, si la différence des deux Doubles se trouve dans la marge, vous les acceptez comme égaux.

Vous pouvez créer une fonction IsEqual en utilisant la marge comme paramètre facultatif:

function IsEqual(const ANumber1, ANumber2: Double; const AMargin: Double = cMargin): Boolean;
begin
  Result := Abs(ANumber1-ANumber2) <= AMargin;
end;
12
répondu Toon Krijthe 2017-06-13 16:45:37

Le Calcul.l'Unité pas comprend des fonctions telles que SameValue(), IsZero(), CompareValue() qui gèrent les comparaisons de type flottant et l'égalité.

const
  EPSILON = 0.0000001;
begin    
  if CompareValue(p, pMax, EPSILON) = GreaterThanValue then
    ShowMessage('p greater than pMax');

La constante GreaterThanValue est définie dans les Types.pas

Si vous comparez de très grandes valeurs , Vous ne devez pas utiliser de constante pour epsilon, mais votre valeur epsilon doit être calculée en fonction des valeurs que vous comparez.

var
  epsilon: double;
begin    
  epsilon := Max(Min(Abs(p), Abs(pMax)) * 0.000001, 0.000001);
  if CompareValue(p, pMax, epsilon) = GreaterThanValue then
    ShowMessage('p greater than pMax');

Notez que si vous utilisez CompareValue(a, b, 0) ou dans XE2 et, plus tard, CompareValue(a, b), Delphi remplira automatiquement un bon epsilon pour vous.

De Delphes Math unité:

function SameValue(const A, B: Extended; Epsilon: Extended): Boolean;
begin
  if Epsilon = 0 then
    Epsilon := Max(Min(Abs(A), Abs(B)) * ExtendedResolution, ExtendedResolution);
  if A > B then
    Result := (A - B) <= Epsilon
  else
    Result := (B - A) <= Epsilon;
end;

À partir de Delphi XE2 , Il y a maintenant des surcharges pour toutes ces fonctions qui ne nécessitent pas de paramètre epsilon et en calculent un pour vous (similaire au passage d'une valeur 0 pour epsilon). Pour plus de clarté du code, je recommande d'appeler ces fonctions plus simples et de laisser Delphi gérer l'epsilon.

La seule raison de ne pas utiliser les surcharges sans paramètres epsilon serait lorsque la performance est crucial et vous voulez éviter les frais généraux d'avoir l'epsilon calculé à plusieurs reprises.

57
répondu LachlanG 2018-06-29 14:54:30