MathAssertions 0.4.1
Prefix ReservedSee the version list below for details.
dotnet add package MathAssertions --version 0.4.1
NuGet\Install-Package MathAssertions -Version 0.4.1
<PackageReference Include="MathAssertions" Version="0.4.1" />
<PackageVersion Include="MathAssertions" Version="0.4.1" />
<PackageReference Include="MathAssertions" />
paket add MathAssertions --version 0.4.1
#r "nuget: MathAssertions, 0.4.1"
#:package MathAssertions@0.4.1
#addin nuget:?package=MathAssertions&version=0.4.1
#tool nuget:?package=MathAssertions&version=0.4.1
MathAssertions
Scope: Test projects only. Not intended for production code.
Framework-agnostic core of the MathAssertions package family. Math assertion helpers for .NET tests, spanning tolerance comparisons, sequences, statistics, linear algebra, number theory, and 3D geometry. Test-framework-specific entry points ship in adapter packages (currently MathAssertions.TUnit for TUnit).
Most users want
MathAssertions.TUnit, not this package directly. This package ships the framework-agnostic helper classes (MathTolerance,Sequences,Statistics,LinearAlgebra,NumberTheory, plus theGeometry3Dnamespace); the adapter package adds the fluentAssert.That(value).Method(...)entry points your test framework expects.
What's in this package
Pure, NaN-aware, infinity-aware mathematical-assertion helpers. Six static classes plus the Geometry3D namespace cover ~85 methods:
MathTolerance: scalarIsApproximatelyEqualfordouble/floatplus theSystem.Numericscompounds (Vector2/Vector3/Vector4,QuaternionwithIsRotationallyEquivalentand (v0.2.0+)HasAxisAngleApproximately,Matrix4x4,PlanewithIsGeometricallyEquivalent,Complex), span / tensor overloads (ReadOnlySpan<double>/<float>, genericReadOnlyTensorSpan<T>), ULP-distance equality (IsCloseInUlps), combined relative+absolute tolerance, finiteness/probability/percentage predicates,HasRoundtripIdentityfor invertible-transformation checks, and (v0.4.0+) the pose primitivesRotationAngleDegrees,PositionDistance, andIsPoseApproximatelyEqual.- (v0.2.0+) Adapter packages such as
MathAssertions.TUnituse an internal per-component / per-cell / first-failing-element failure-message renderer so every compoundIsApproximatelyEqualTofailure shows the diverging axis and its delta. The renderer is reachable across the assembly boundary via[InternalsVisibleTo]; consumers do not interact with it directly. Sequences: monotonicity (strict + non-strict), boundedness, arithmetic and geometric progressions,ConvergesTo, single-stepIsCauchyConvergent, generic length predicates overReadOnlySpan<T>.Statistics: Welford'sMeanAndVariance,HasMean/Variance/StdDev/Sum/Median/PercentileApproximately,IsWithinSigmasOfMean,AreAllWithinSigmasOfMean. Median and percentile use overflow-safe forms.LinearAlgebra:Matrix4x4invariants (IsSymmetric,IsOrthogonal,IsIdentity,HasDeterminantApproximately,HasTraceApproximately,IsInvertible) plusVector3pair properties (AreOrthogonal,AreParallel,AreLinearlyIndependent).NumberTheory: exact integer predicates overlong:IsDivisibleBy,IsPrime,AreCoprime,GreatestCommonDivisor,LeastCommonMultiple,IsPowerOf,IsPerfectSquare,IsCongruent. Overflow-safe andlong.MinValue-aware.Geometry3D: eight primitiverecord structtypes (Sphere,AxisAlignedBox,OrientedBox,Ray3D,LineSegment3D,Triangle3D,Capsule,Cylinder) and five static classes:Properties(degeneracy, collinearity, coplanarity),Containment(point/box/sphere/OBB/convex hull),Distance(point-to-plane/segment/triangle),Intersection(sphere-sphere, AABB-AABB, ray-plane/sphere/triangle/AABB with citations to Real-Time Rendering §§22.6, 22.7, 22.8),Pointcloud(boundedness, centroid, on-plane / on-sphere). Algorithm citations preserved per Real-Time Collision Detection and Real-Time Rendering.
All tolerance- and sigma-taking methods validate the bound up front; invalid input throws ArgumentOutOfRangeException even on early-return paths.
Test-framework adapters
| Package | Test framework | Status |
|---|---|---|
MathAssertions.TUnit |
TUnit | Available now |
MathAssertions.NUnit |
NUnit | Possible if there is demand |
MathAssertions.xUnit |
xUnit | Possible if there is demand |
MathAssertions.MSTest |
MSTest | Possible if there is demand |
If you'd find a non-TUnit adapter useful, open a feature request. Adapters are not built proactively.
When to install this package directly
Only when authoring a non-TUnit adapter for the assertion family, or when calling MathTolerance from a [GenerateAssertion] extension on a private type. For any TUnit testing use case, install MathAssertions.TUnit.
Installation
dotnet add package MathAssertions.TUnit
MathAssertions comes transitively. You don't need to install it directly unless you're building your own adapter package.
Stability
The public surface above is semver-bound. Breaking changes require a major version bump. The exact text of any future failure-message rendering produced inside MathTolerance is not stable and may gain extra detail or change formatting in any release.
Repository
github.com/JohnVerheij/MathAssertions.TUnit for the full README, design notes, and roadmap.
License
MIT. Copyright (c) 2026 John Verheij.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- System.Numerics.Tensors (>= 10.0.8)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on MathAssertions:
| Package | Downloads |
|---|---|
|
MathAssertions.TUnit
TUnit-native math assertions for .NET tests. Fluent .Method(...) entry points (generated via TUnit's [GenerateAssertion]) covering tolerance comparisons (scalar, vector, quaternion, matrix, plane, complex, double[]/float[]), sequences, statistics, Vector3 linear algebra, long-integer number theory, and the Geometry3D primitive surface (containment, distance, intersection, pointcloud aggregates). Extensible: consumers add tolerance assertions for their own domain types via [GenerateAssertion] extensions calling MathTolerance helpers. AOT-compatible, trimmable, no reflection. |
GitHub repositories
This package is not used by any popular GitHub repositories.
View the rendered release notes: https://github.com/JohnVerheij/MathAssertions.TUnit/releases/tag/v0.4.1
Bug-fix release. No public API signature change.
### Fixed
- **`IsPoseApproximatelyEqualTo`** (and the `Matrix4x4` overload `IsRigidTransformApproximatelyEqualTo`, and the underlying `MathTolerance.RotationAngleDegrees`) reported a non-zero rotation angle for a pose compared with itself, failing on identical inputs. The geodesic angle was computed as `2 * acos(|dot|)`, and `acos` has infinite slope at `dot = 1`, so the residual float error of normalizing a non-unit quaternion (any quaternion whose magnitude is not exactly 1) was amplified into a spurious angle large enough to exceed a tight rotation tolerance. The metric is now the numerically-stable `theta = 2 * atan2(||imag(q1 * conj(q2))||, |real(q1 * conj(q2))|)`, which is well-conditioned across the whole 0-180 degree range, and both quaternions are normalized in double precision before measuring (a quaternion and any positive scalar multiple are the same rotation), so a quaternion compared with itself now measures exactly zero.
- **`IsPoseApproximatelyEqual`** now handles a degenerate, non-normalizable orientation (squared magnitude underflows to zero, e.g. `default(Quaternion)` = `(0, 0, 0, 0)`), which has no defined geodesic angle. The orientation half falls back to a componentwise comparison against a tight fixed tolerance, independent of the caller's rotation tolerance: the rotation tolerance is a degrees value, and reusing it would be far too permissive (a tolerance of 1 or more would accept a zero quaternion as equal to a real rotation, whose nearest component delta is at most 1). So a default-pose round-trip (`(0,0,0,0)` vs `(0,0,0,0)`) passes, while `(0,0,0,0)` compared with a real rotation fails regardless of the angular tolerance, with the combined diagnostic naming the rotation half.