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

28

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

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

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

  • 0
    я не думаю, что это петля.
  • 0
    @Simon: есть немецкий сайт if-schleife.de . Гугл переводчик делает There are no if-loops, but only if statements! этого
Теги:
types

2 ответа

12
Лучший ответ

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

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

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

function IsEqual(const ANumber1, ANumber2: Double; const AMargin: Double = cMargin): Boolean;
begin
  Result := Abs(ANumber1-ANumber2) <= AMargin;
end;
  • 10
    Обратите внимание, что ваше правильное решение уже доступно в Math.pas как SameValue.
55

Модуль 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, - это когда производительность имеет решающее значение, и вы хотите избежать накладных расходов на то, чтобы эпсилон многократно вычислялся.

  • 0
    Большое спасибо .. выглядит это работает .. вчера я пробовал это, но я не знаю о Types.pas ..
  • 0
    -100 для использования фиксированного значения epsilon, вместо этого я отредактировал ответ, чтобы исправить проблему.
Показать ещё 7 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню