Мы сталкиваемся с проблемой двойного сравнения типа данных:
if(p > pmax) then
begin
Showmessage('');
end
Если оба значения равны 100 (p = 100 и pmax = 100), то он также входит в предложение if.
Мы сталкиваемся с проблемой двойного сравнения типа данных:
if(p > pmax) then
begin
Showmessage('');
end
Если оба значения равны 100 (p = 100 и pmax = 100), то он также входит в предложение if.
Есть несколько проблем с сравнением парных разрядов. Одна из проблем заключается в том, что то, что вы видите, не совсем то, что вы получаете из-за округления. Вы можете иметь 99.999999996423 и 100.00000000001632, которые округлены до 100, но они не равны.
Решение заключается в использовании поля, так что если разница двух парных чисел лежит в пределах поля, вы принимаете их равными.
Вы можете создать функцию IsEqual с использованием поля в качестве необязательного параметра:
function IsEqual(const ANumber1, ANumber2: Double; const AMargin: Double = cMargin): Boolean;
begin
Result := Abs(ANumber1-ANumber2) <= AMargin;
end;
Модуль 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, - это когда производительность имеет решающее значение, и вы хотите избежать накладных расходов на то, чтобы эпсилон многократно вычислялся.