使用浮点数时,永远不要执行精确比较;始终使用小Epsilon
值,如The Floating-Point Guide - What Every Programmer Should Know中所述。
注意:我特意在绝对意义上陈述这一点。当然也有例外,但实际上这些通常是例外的。当然,您可能处于您的问题领域非常特殊的情况,并且需要进行精确比较。在我维护的绝大多数代码中,情况并非如此。
该Math
单元(它与 Delphi 一起使用了很长时间)包含以下Epsilon
为您处理值的函数。
当您将Epsilon
零值(即0.0
)或根本没有值传递给下面的函数时,它们将使用这些常量估计一个合理的值。
笔记:
您要使用的适当值Epsilon
取决于您使用的计算:有时不准确会累积到比这些常数大得多的值。
const
FuzzFactor = 1000;
SingleResolution = 1E-7 * FuzzFactor;
DoubleResolution = 1E-15 * FuzzFactor;
{$IFDEF EXTENDEDIS10BYTES}
ExtendedResolution = 1E-19 * FuzzFactor;
{$ELSE EXTENDEDIS10BYTES}
ExtendedResolution = DoubleResolution;
{$ENDIF EXTENDEDIS10BYTES}
功能:
function CompareValue(const A, B: Extended; Epsilon: Extended = 0): TValueRelationship; overload;
function CompareValue(const A, B: Double; Epsilon: Double = 0): TValueRelationship; overload;
function CompareValue(const A, B: Single; Epsilon: Single = 0): TValueRelationship; overload;
function SameValue(const A, B: Extended; Epsilon: Extended = 0): Boolean; overload;
function SameValue(const A, B: Double; Epsilon: Double = 0): Boolean; overload;
function SameValue(const A, B: Single; Epsilon: Single = 0): Boolean; overload;
function IsZero(const A: Extended; Epsilon: Extended = 0): Boolean; overload;
function IsZero(const A: Double; Epsilon: Double = 0): Boolean; overload;
function IsZero(const A: Single; Epsilon: Single = 0): Boolean; overload;