Practical guidelines for writing correct and efficient MtxVec code.
1. Always use try/finally with CreateIt/FreeIt:
CreateIt(a, b);
try
// ... use a, b ...
finally
FreeIt(a, b); // always executes, even on exception
end;
Never skip the try/finally — an exception will leak pool objects.
2. Mixing Vector and TVec in the same code:
var v: Vector; // automatic lifetime
t: TVec; // needs CreateIt/FreeIt
begin
v.Size(100); // v manages itself
CreateIt(t);
try
t.Size(100);
t.Sin(v); // OK: Vector auto-converts to TVec parameter
finally
FreeIt(t);
end;
end;
3. Avoid element-by-element loops:
// BAD — slow, not vectorized
for i := 0 to a.Length - 1 do
a.Values1D[i] := Sin(a.Values1D[i]);
// GOOD — vectorized, SIMD, potentially multithreaded
a.Sin;
The vectorized form is 10-100x faster depending on array size and operation.
4. Use compound operations when formula matches:
// BAD — 3 passes through memory, 2 temporaries
c.Mul(a, b);
c.Add(d);
// GOOD — 1 pass, no temporaries
c.MulAndAdd(a, b, d); // c = a * b + d
5. Handle exceptions — they signal contract violations only:
An exception is raised only when a genuine violation of an operation's contract occurs. Exceptions are never used to report normal processing results:
Size(0)is legal — an empty vector or matrix is a valid state, not an error.NANandINFare valid floating-point values — they propagate through computations normally and raise nothing.
| Class | Raised when |
|---|---|
EMtxVecException | base class of all MtxVec exceptions |
EMtxVecRangeError | an index or length falls outside the valid range |
EMtxVecInvalidArgument | a parameter violates the method's contract |
EOutOfMemory | allocation failure |
EMtxVecRangeError and EMtxVecInvalidArgument both descend from EMtxVecException, so catching the base class handles either.
// LUSolve's contract requires a full-rank matrix
try
m.LUSolve(b, x);
except
on E: EMtxVecException do
ShowMessage('LUSolve failed: ' + E.Message);
end;
6. Sizing is automatic:
You never need to call Size() before writing to a vector or matrix — every operation that writes a result calls Size() on the destination implicitly, matching it to its inputs.