I was doing a solution for this question with respect to underlying hardware and platform.
Due Delphi's code generator specifics, it produces 80x87 instructions for IA32 platform and SSE instructions for AMD64 platform, thus having generic Real
type defined as Extended
or Double
depending on the target.
The algorithm specifics requires some attention to be paid to the base type, because machine epsilon differs for Double
and Extended
types. The only thing I figured out is branching on the size of function argument:
type
Real = Extended{|Double|Single};
function SqrtHeron(a: Real): Real;
var
x0: Real;
x1: Real;
const
FuzzFactor = 1000;
{$IF SizeOf(a) = SizeOf(Extended)}
Epsilon = 1E-19 * FuzzFactor;
{$ELSE}{$IF SizeOf(a) = SizeOf(Double)}
Epsilon = 1E-15 * FuzzFactor;
{$ELSE}{$IF SizeOf(a) = SizeOf(Single)}
Epsilon = 1E-7 * FuzzFactor;
{$IFEND}{$IFEND}{$IFEND}
var
n: Integer;
begin
{ ... }
How can I implement this branching in the better way? And I definitely want to avoid deceptively pretending Double
machine epsilon for Extended
machine epsilon (citing a clumsy patch to Math.pas
):
const
FuzzFactor = 1000;
SingleResolution = 1E-7 * FuzzFactor;
DoubleResolution = 1E-15 * FuzzFactor;
{$IFDEF CPUX64}
ExtendedResolution = DoubleResolution;
{$ELSE !CPUX64}
ExtendedResolution = 1E-19 * FuzzFactor;
{$ENDIF}
First, your {$IF}
statements can be cleaned up using {$ELSEIF}
instead of {$ELSE}{$IF}
.
Second, Extended
and Double
are the same thing on Win64, unless you enable {$EXTENDEDCOMPATIBILITY ON}
, so your first {$IF}
would end up using the wrong value. Try swapping them to account for that. I would even go as far as checking for SizeOf(Single)
first, moving up in increasing byte size rather than down in decreasing size:
const
FuzzFactor = 1000;
{$IF SizeOf(Real) = SizeOf(Single)}
Epsilon = 1E-7 * FuzzFactor;
{$ELSEIF SizeOf(Real) = SizeOf(Double)}
Epsilon = 1E-15 * FuzzFactor;
{$ELSEIF (SizeOf(Extended) > SizeOf(Double)) and (SizeOf(Real) = SizeOf(Extended))}
Epsilon = 1E-19 * FuzzFactor;
{$IFEND}
If you need 80-bit precision on Win64, use TExtended80Rec
or TExtendedHelper
instead.