Recursive AI

Getting started with OneMath

All onemath docs

Install OneMath for .NET 10 and use its correctly rounded functions, vectors and matrices, exact predicates and fixed-point bridge, with results that are the same bits on every platform.

Install

OneMath targets net10.0, so you need the .NET 10 SDK. This guide uses 1.0.0.

Terminal
dotnet new console -o OneMathStart
cd OneMathStart
dotnet add package RecursiveAI.OneMath --version 1.0.0

The package has no dependency beyond the .NET base class library and works under NativeAOT, trimming and browser WebAssembly.

A first program

C#
using RecursiveAI.OneMath;
using RecursiveAI.OneMath.Predicates;
 
// Elementary functions: correctly rounded, the same bits everywhere.
double s = Math64.Sin(1e300);
float e = Math32.Exp(1.5f);
Console.WriteLine($"Math64.Sin(1e300) = {s:R}  bits {BitConverter.DoubleToInt64Bits(s):X16}");
Console.WriteLine($"Math32.Exp(1.5f)  = {e:R}");
 
// Vectors, quaternions and matrices, in float (F) and double (D).
var q = QuaternionD.CreateFromAxisAngle(new Vector3D(0, 1, 0), Math.PI / 2);
Matrix4x4D m = Matrix4x4D.CreateFromQuaternion(q) * Matrix4x4D.CreateTranslation(new Vector3D(10, 0, 0));
Vector3D p = m.TransformPoint(new Vector3D(1, 0, 0));
Console.WriteLine($"Rotated and moved: {p}");
 
// Exact predicates: the sign of the exact determinant.
int side = ExactPredicates.Orient2D(0, 0, 1, 0, 0.5, 1e-10);
Console.WriteLine($"Orient2D: {side} (+1 left, -1 right, 0 on the line)");
 
// The Q31.32 fixed-point bridge.
long raw = FixedBridge.FromDouble(1.5);
Console.WriteLine($"FixedBridge.FromDouble(1.5) = {raw} = 0x{raw:X}, back: {FixedBridge.ToDouble(raw)}");
Text
Math64.Sin(1e300) = -0.8178819121159085  bits BFEA2C16B010E385
Math32.Exp(1.5f)  = 4.481689
Rotated and moved: (2.4424906541753444E-15, 0, -11)
Orient2D: 1 (+1 left, -1 right, 0 on the line)
FixedBridge.FromDouble(1.5) = 6442450944 = 0x180000000, back: 1.5

What each part is:

  • Math64 and Math32 have sin, cos, tan, sincos, asin, acos, atan, atan2, exp, exp2, expm1, log, log2, log10, log1p, pow, cbrt, hypot, sinh, cosh and tanh for double and float. Each is correctly rounded: the result is the representable number nearest to the exact value, even for an argument like 10^300. See elementary functions.
  • The types are Vector2/3/4, Matrix2x2/3x3/4x4, Quaternion, Affine3, RigidTransform and Bounds2/3, each with an F (float) and a D (double) form. Matrices use column vectors: R * T applies T first. That is the opposite of System.Numerics; see Port from System.Numerics.
  • ExactPredicates (namespace RecursiveAI.OneMath.Predicates) returns the sign of the exact determinant, never a rounding accident: see Exact geometric predicates.
  • FixedBridge converts between Q31.32 fixed-point raw values and double, exactly within ±2^21: see The fixed-point bridge.

The rotated point shows double rounding at work: 2.44E-15 is the cosine of a rounded π/2, not zero. What OneMath promises is that it is the same 2.44E-15 everywhere.

The determinism promise

A result depends only on its inputs, not on the OS, the CPU and its SIMD or fused multiply-add support, the runtime version, the JIT tier, NativeAOT or WebAssembly, or the thread count. OneMath never calls Math.Sin and friends and never uses fused multiply-add.

It also holds across versions: no 1.x release changes the result of any existing function, type or predicate. A deterministic host can update within 1.x without breaking replays, saved games or lockstep peers. Check that two machines agree shows how to test it on your own targets.

Next