OneMath has Vector2/3/4, Matrix3x3/4x4 and Quaternion types in float (F) and double (D), with the operations you expect and the same results on every machine. The program below takes a ship’s heading, turns it with a quaternion, blends two orientations and moves a point into world space.
dotnet new console -o VectorMath && cd VectorMath dotnet add package RecursiveAI.OneMath --version 1.0.0
Put this in Program.cs and run dotnet run:
using RecursiveAI.OneMath; var forward = new Vector3F(0, 0, 1); var toTarget = new Vector3F(3, 0, 4); // Vectors: length, normalize, dot and cross products, distance. Vector3F dir = toTarget.Normalized(); Console.WriteLine($"length {toTarget.Length()}, direction {dir}"); Console.WriteLine($"dot {Vector3F.Dot(forward, dir)}"); Console.WriteLine($"cross {Vector3F.Cross(forward, dir)}"); Console.WriteLine($"distance {Vector3F.Distance(Vector3F.Zero, toTarget)}"); // Quaternions: turn 90 degrees about the up axis (counterclockwise seen from above). QuaternionF turn = QuaternionF.CreateFromAxisAngle(Vector3F.UnitY, MathF.PI / 2); Console.WriteLine($"forward turned: {turn.Rotate(forward)}"); // Blend two orientations: halfway along the shortest arc. QuaternionF half = QuaternionF.Slerp(QuaternionF.Identity, turn, 0.5f); Console.WriteLine($"halfway: {half.Rotate(forward)}"); // Combine rotations: a * b applies b first, then a. QuaternionF twice = turn * turn; Console.WriteLine($"turned twice: {twice.Rotate(forward)}"); // Matrices: rotate, then move 10 along x. Column vectors, so read right to left. Matrix4x4F world = Matrix4x4F.CreateTranslation(new Vector3F(10, 0, 0)) * Matrix4x4F.CreateFromQuaternion(turn); Console.WriteLine($"local (0, 0, 1) in world: {world.TransformPoint(forward)}");
length 5, direction (0.6, 0, 0.8) dot 0.8 cross (0, 0.6, 0) distance 5 forward turned: (0.99999994, 0, 5.9604645E-08) halfway: (0.70710695, 0, 0.7071067) turned twice: (0, 0, -0.99999976) local (0, 0, 1) in world: (11, 0, 5.9604645E-08)
0.99999994 and 5.9604645E-08 instead of 1 and 0 are float rounding: π/2 isn’t exact in a float, and neither are its sine and cosine. What OneMath promises is that every machine prints these same values.
The types
- Vectors:
Vector2F,Vector3F,Vector4Fand theirDforms, with+ - *,Dot,Cross,Length,Normalized,Distance,Lerp,Min,MaxandAbs. - Quaternions:
CreateFromAxisAngle(the axis must be a unit vector),Rotate,Slerp,NLerp,Conjugated,Normalizedand the Hamilton producta * b. - Matrices:
Matrix2x2,Matrix3x3,Matrix4x4, withCreateTranslation,CreateRotationX/Y/Z,CreateFromQuaternion,TransformPointandTransformVector; alsoAffine3,RigidTransformandBounds2/3. ToSystemNumerics()andFromSystemNumerics()convert to and from System.Numerics, for handing results to a renderer.
Limits
- Column vectors.
A * BappliesBfirst, the opposite of System.Numerics and MonoGame. Moving existing code: Port System.Numerics code to OneMath. - Exact equality is exact.
==compares bits; use a tolerance when comparing results that went through different operations.
Why the results match across machines, and how to check it: Deterministic floating-point math in C#.