Using Exentia
Include the unit Exentia.pas in your project,
then create instances of the TFVector class using
class function BuildVector(const ALength : integer) : TFVector;
Never create instances using constructors
(i.e. MyVector := TSSEVector.Create(MySize);)
as it would force the usage of a specific instruction set!
You can clone an existing vector by using:
class function CopyVector(const V : TFVector) : TFVector;
You can read and write single data elements
using the Data property (being the default property, you can also use the
simpler MyDataValue := MyVector[index]
syntax).
Each vector allocates the memory required
to hold ALength 32-bit floating point values on 16-bytes boundaries so
that memory access is optimal.
Please note that ALength must be a
multiple of 4, otherwise it will be rounded up during vector construction.
Here is the definition of the TFVector
class:
type
TFVector = class(TObject)
private
AlignedArray : PSingleArray;
AllocatedArray : pointer;
NumElements : integer;
function GetDataElement(index : integer) : single;
procedure SetDataElement(index : integer; const
value : single);
public
property DataArray : PSingleArray read AlignedArray;
property Data[index : integer] : single read
GetDataElement write SetDataElement; default;
constructor Create(const ALength : integer);
constructor Copy(const V : TFVector); // Self
= V
destructor Destroy;override;
class function BuildVector(const ALength : integer)
: TFVector;
class function CopyVector(const V : TFVector)
: TFVector;
class function isSSE : boolean;
class function is3DNow : boolean;
procedure SetLength(const ALength : integer);
procedure ImportArray(const Source : PSingleArray;
const Length : integer = 0);
procedure ExportArray(Destination : PSingleArray;
const Length : integer = 0);
procedure ClearArray; // Self = 0
procedure SetArray(value : single); //
Self[i] = value
// basic operations
procedure Add(V : TFVector); virtual; abstract;
// Self = Self + V
procedure Sub(V : TFVector); virtual; abstract;
// Self = Self - V
procedure Mul(V : TFVector); virtual; abstract;
// Self = Self * V
procedure Divide(V : TFVector); virtual; abstract;
// Self = Self / V
procedure Sqrt(V : TFVector); virtual; abstract;
// Self = Sqrt(V)
procedure Reciprocal(V : TFVector); virtual;
abstract; // Self = 1 / V
procedure RecSqrt(V : TFVector); virtual; abstract;
// Self = 1 / Sqrt(V)
procedure Max(V : TFVector); virtual; abstract;
// Self = Max(Self, V)
procedure Min(V : TFVector); virtual; abstract;
// Self = Min(Self, V)
procedure LogicalAnd(V : TFVector); virtual;
abstract; // Self = Self and V
procedure LogicalOr(V : TFVector); virtual;
abstract; // Self = Self or V
procedure LogicalXor(V : TFVector); virtual;
abstract; // Self = Self xor V
procedure CmpGreater(V : TFVector); virtual;
abstract; // Self = Self > V
procedure CmpLower(V : TFVector); virtual; abstract;
// Self = Self < V
procedure CmpEqual(V : TFVector); virtual; abstract;
// Self = Self == V
procedure CmpGreaterEqual(V : TFVector); virtual;
abstract; // Self = Self >= V
procedure CmpLowerEqual(V : TFVector); virtual;
abstract; // Self = Self <= V
// complex operations
procedure AddSquare(V : TFVector); virtual;
abstract; // Self = Self + V^2
function InnerSum : single; virtual; abstract;
// result = Sum(Self[i])
function InnerSumAbs : single; virtual; abstract;
// result = Sum(abs(Self[i]))
function DotProduct(V : TFVector) : single;
virtual; abstract; // result = Sum(Self[i] * V[i])
function MaxValue : single; virtual; abstract;
// result = Max(Self[i])
function MaxAbsValue : single; virtual; abstract;
// result = Max(abs(Self[i]))
function IndexMaxValue : integer; virtual; abstract;
// result = index of Max(Self)
function MinValue : single; virtual; abstract;
// result = Min(Self[i])
function MinAbsValue : single; virtual; abstract;
// result = Min(abs(Self[i]))
function IndexMinValue : integer; virtual; abstract;
// result = index of Min(Self)
function Mean : single; virtual; abstract;
// result = Sum(Self[i]) / NumElements
procedure Scale(value : single); virtual; abstract;
// Self = value * Self
end;
TFVector defines an abstract interface
which is implemented in the derived classes: TX87Vector, TSSEVector and
T3DNowVector. When creating a vector, the BuildVector class function checks
the instruction sets supported by the current CPU and creates the top-performing
instance, i.e.
-
TSSEVector on Intel Pentium III and Celeron
II processors
-
T3DNowVector on AMD K6-2, K6-III, Athlon and
Duron processors
-
TX87Vector on older processors
The derived classes implement all abstract
methods.
Update! The new
Exentia64 extensions lets you use both x87 and Intel SSE2 instructions to
process 64-bit floating point data vectors. Just include the Exentia64 unit, and
use the TFVector64 object as base class, and you're ready to reap the benefits
of the Pentium 4 processor! Many thanks to Tom Womack and Chris Rorden for
coding and testing these extensions!
Update! The new
SIMD extensions lets you use Exentia SSE code with previously unsupported
Delphi release (5 and below)! Click here
to download the SIMD DLL and the import class. Many thanks to Uwe Rossek
for designing and coding it!
Click here
for the current status of this library.
