The mirror compiles under using static CultMath.math, so it proves composition,
not intrinsic rules; HlslSemanticsTests alone pins those. design.md also states
where FMin/FMax/Saturate turn NaN or infinity into numbers and tells callers to
check isnan first.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
dxc lowers double min/max to dx.op.binary.f64 opcodes 36/35 (FMin/FMax),
the same operations as float, so Math.Min/Math.Max (NaN-propagating) was the
wrong rule. Double min/max now use the float formulas, with NaN and signed-zero
assertions beside the float ones. Tracked Unity DLL rebuilt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
SequenceEqual on floats treats -0 as 0. The mirror test now compares
SingleToInt32Bits, with any NaN equal to any NaN. Its summary and
design.md now say the test proves CultMath.hlsl's text computes the same
float32 results as C# math on the CPU, not that a GPU agrees: driver sin
precision alone makes cultmath_hash and value noise differ on hardware.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
dxc lowers float min/max/clamp to dx.op FMin/FMax (36/35) and saturate to
dx.op Saturate (7). DXIL.rst defines them: FMin(a, b) is a < b ? a : b,
FMax(a, b) is a >= b ? a : b, a NaN operand returns the other, and
Saturate is FMin(1, FMax(0, x)). C# used MathF.Min/Max, which pass NaN
through and order signed zeros, so saturate(NaN) was NaN instead of 0.
Every float overload now follows the spec, normalize uses the same max as
its mirror, and the mirror's saturate spells Saturate's operand order
(which maps -0 to +0, where clamp(x, 0, 1) keeps -0). Non-NaN results
change only in the sign of a zero. design.md records the rules and that
dxc marks float math fast, so GPU NaN results are not guaranteed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Only cultmath_snoise was compared, at four inputs, so a flipped cultmath_step,
a changed hash constant, and a snoise2 tie change all passed. The mirror is
now discovered by reflection: every cultmath_* overload with a math
counterpart (26 functions) runs over 104 deterministic cases - each special
value in every argument (0, -0, +-1, ties, 1e-7, +-1e4, 1e7, NaN), special
pairs, seeded randoms, and vectors with x == y (snoise's x0.x == x0.y) - and
must match exactly. Both sides are float32 C# over the same intrinsics, so no
tolerance. A cultmath_* function with no counterpart must be named in
MirrorOnly. The four-input snoise theory is gone.
Mutations: flipped step args fail (349 mismatches); hash constants changed
by more than one float32 ulp fail (43758.55: 467, 127.2: 289, 74.8: 97).
43758.5453 -> .5454 is the same float32 and cannot fail. snoise2 x0.x > x0.y
-> >= is invisible: over 1,829,415 exact ties the result is bit-identical,
because the off-simplex corner's kernel is <= 0 on the shared edge.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
dxc 1.9.0.5402 (dxc_2026_07_29, lib_6_3, -HV 2021, -Od) lowers step(e, x) to
fcmp olt x, e; select 0 : 1, so NaN on either side gives 1. The previous
x >= e ? 1 : 0 rule came from prose, not the compiler. math.step and
cultmath_step now use x < e ? 0 : 1 for every overload; the mirror's
cultmath_step compiles to the same fcmp/select as the intrinsic. Unity shader
copy synced; DLL rebuilt and byte-checked by build-unity-package.ps1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
HlslSourceCompatibilityTests now reads shaders/CultMath.hlsl, applies only
the documented transformations (drop include guards, drop Texture2D/
SamplerState functions, file-scope static const -> const, f literal
suffixes, wrap in a class), and compiles it with Roslyn against CultMath.
Any compile error fails the test (probed with an undeclared call). The
compiled cultmath_snoise(float3/float2) also matches math.snoise.
dxc -T lib_6_3 -HV 2021 rejected the mirror: cultmath_snoise(float2) called
the undeclared cultmath_simplex_mod289/permute. Renamed to the declared
cultmath_snoise_* helpers. Vector const locals became plain locals (C# const
is primitives only), and cultmath_step uses value >= edge like HLSL step and
the C# mirror. dxc 1.9.0.5402 now compiles the file cleanly. The Unity
package's Shaders copy is synced.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tools/generate-swizzles.ps1 writes the checked-in src/CultMath/Swizzles.g.cs
as partial structs plus a partial math: for float2/3/4, int2/3/4 and bool2/3/4
every swizzle of length 2-4 including repeats, in xyzw and rgba naming, with
setters only on non-repeating masks, plus single-component r/g/b/a. double2/3
get lengths 2-3 (there is no double4). Every HLSL mixed constructor
(float4(float2, float2), float4(float, float2, float), copy forms, ...) exists
as a struct constructor and, for float/int/bool, a math function. The
hand-written swizzles and mixed constructors it supersedes are deleted.
Matrices store private rows and return ref float2/float3 from the row
indexer ([UnscopedRef], polyfilled for netstandard2.1), so m[1][2] = s
compiles as in HLSL; _mRC are get/set properties over the rows. Equality and
hashing stay value-based.
Intrinsics follow HLSL: sign returns int/intN and yields 0 for NaN; step is
x >= y ? 1 : 0 so NaN yields 0; any/all accept float and int vectors;
min/max/abs on int vectors return int vectors, and abs(int) returns int.
Strips the UTF-8 BOMs this branch added to math.cs, CultMath.csproj and
HlslSemanticsTests.cs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
HLSL is now CultMath's semantic authority where it defines one.
- float2/3/4, int2, double2/3, bool2 and quaternion are plain structs with
public mutable fields instead of record structs. Indexers and swizzles
(float2.yx; float3 xy xz yx yz zy xyz xzy yzx zyx; float4 xy xyz xyw yzx)
have setters.
- ==, !=, <, >, <=, >= are component-wise and return bool2/3/4. Equals and
GetHashCode stay value-based so vectors remain dictionary keys.
quaternion is not an HLSL type and keeps a bool ==.
- Scalar/vector arithmetic and comparisons get explicit overloads on both
sides instead of leaning on implicit splat.
- New types: bool3, bool4, int3, int4, float2x2, float3x3 (row-major like
HLSL, _mRC fields, Rotate / RotateX/Y/Z / Euler with math.RotationOrder).
- New intrinsics: mul (matrix-vector both sides, matrix-matrix), any, all,
select (HLSL argument order), log, vector pow/sqrt/sin/cos/acos/atan2,
double min/max, int3/int4/bool3/bool4/float2x2/float3x3 constructor
functions.
- simplex_noise is renamed snoise and gains the Ashima 3D variant; the HLSL
mirror follows as cultmath_snoise(float2/float3).
- Random gains NextFloat3() and NextFloat3(float3 max) on the same draw order.
Tests pin snoise(float3), float3x3.Euler and float2x2.Rotate to
Unity.Mathematics reference values, and an HLSL-shaped source block compiles
under using static CultMath.math.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>