Подтвердить что ты не робот

Как сравнить double в delphi?

Мы сталкиваемся с проблемой двойного сравнения типа данных:

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

Если оба значения равны 100 (p = 100 и pmax = 100), то он также входит в предложение if.

4b9b3361

Ответ 1

Есть несколько проблем с сравнением парных разрядов. Одна из проблем заключается в том, что то, что вы видите, не совсем то, что вы получаете из-за округления. Вы можете иметь 99.999999996423 и 100.00000000001632, которые округлены до 100, но они не равны.

Решение заключается в использовании поля, так что если разница двух парных чисел лежит в пределах поля, вы принимаете их равными.

Вы можете создать функцию IsEqual с использованием поля в качестве необязательного параметра:

function IsEqual(const ANumber1, ANumber2: Double; const AMargin: Double = cMargin): Boolean;
begin
  Result := Abs(ANumber1-ANumber2) <= AMargin;
end;

Ответ 2

Модуль Math.pas включает в себя такие функции, как SameValue(), IsZero(), CompareValue() которые обрабатывают сравнение и равенство плавающего типа.

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

Константа GreaterThanValue определяется в Type.pas

Если вы сравниваете очень большие значения, вы не должны использовать константу для epsilon, вместо этого значение epsilon должно рассчитываться на основе сравниваемых значений.

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');

Обратите внимание: если вы используете CompareValue(a, b, 0) или в XE2 и более поздних CompareValue(a, b), Delphi автоматически заполнит вам хороший эпсилон.

Из блока Math Дельфы:

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;

Начиная с Delphi XE2 теперь есть перегрузки для всех этих функций, которые не требуют параметра epsilon и вместо этого вычисляют один для вас (аналогично передаче значения 0 для epsilon). Для ясности кода я бы рекомендовал назвать эти более простые функции и позволить Delphi обрабатывать epsilon.

Единственная причина, по которой не использовать перегрузки без параметров epsilon, - это когда производительность имеет решающее значение, и вы хотите избежать накладных расходов на то, чтобы эпсилон многократно вычислялся.