Practical guidelines for writing correct and efficient MtxVec code.
1. Always use try/finally with CreateIt/FreeIt:
TVec a = null, b = null;
TMtxVec.CreateIt(out a, out b);
try {
// ... use a, b ...
} finally {
TMtxVec.FreeIt(ref a, ref b); // always executes, even on exception
}
Never skip the try/finally — an exception will leak pool objects.
2. Mixing Vector and TVec in the same code:
var v = new Vector(); // automatic lifetime
v.Size(100); // v manages itself
TVec t = null;
TMtxVec.CreateIt(out t);
try {
t.Size(100);
t.Sin((TVec)v); // cast Vector to TVec for method parameter
} finally {
TMtxVec.FreeIt(ref t);
}
3. Avoid element-by-element loops:
// BAD — slow, not vectorized
for (int i = 0; i < a.Length; i++)
a.Values1D[i] = Math.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);
} catch (EMtxVecException e) {
Console.WriteLine("LUSolve failed: " + e.Message);
}
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.