Compare mirror results by bit pattern and say what that proves
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>
This commit is contained in:
parent
9407da0461
commit
08e213dd7c
2 changed files with 13 additions and 5 deletions
|
|
@ -85,6 +85,11 @@ The HLSL side is checked too: `tools/get-dxc.ps1` fetches Microsoft's
|
|||
DirectXShaderCompiler, and
|
||||
`dxc -T lib_6_3 -HV 2021 shaders/CultMath.hlsl` must compile cleanly.
|
||||
|
||||
The mirror test compares bit patterns (any NaN equals any NaN; -0 differs from
|
||||
0). It proves the text of `CultMath.hlsl` 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 bit for bit on hardware.
|
||||
|
||||
Where HLSL is silent, CultMath keeps its own decisions and does not defer to
|
||||
Unity.Mathematics: `normalize` is safe (divides by `max(length, 1e-20)`),
|
||||
`hash` returns float, and `Random` is CultMath's own xorshift32. Engine-shaped
|
||||
|
|
|
|||
|
|
@ -37,10 +37,12 @@ public sealed class HlslSourceCompatibilityTests
|
|||
private static readonly float[] Specials = { 0.0f, -0.0f, 1.0f, -1.0f, 0.5f, -2.75f, 3.0f, 1.0e-7f, 1.0e4f, -1.0e4f, 1.0e7f, float.NaN };
|
||||
|
||||
/// <summary>
|
||||
/// Every mirror function with a C# math counterpart returns the same bits (NaN equal to NaN, -0 equal
|
||||
/// to 0) over random inputs, every special value in every argument (ties, zeros, negatives, NaN,
|
||||
/// large values, integer lattice points), special pairs, and vectors whose first two components tie
|
||||
/// (x0.x == x0.y in snoise). Equality is exact: both sides are float32 C# over the same intrinsics.
|
||||
/// Every mirror function with a C# math counterpart returns the same bits (any NaN equals any NaN;
|
||||
/// -0 differs from 0) over random inputs, every special value in every argument (ties, zeros,
|
||||
/// negatives, NaN, large values, integer lattice points), special pairs, and vectors whose first two
|
||||
/// components tie (x0.x == x0.y in snoise). This proves the text of CultMath.hlsl computes the same
|
||||
/// float32 results as C# math on the CPU. It does not prove GPU agreement: driver sin precision alone
|
||||
/// makes cultmath_hash and value noise differ bit for bit on hardware.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void EveryMirrorFunctionMatchesCSharpMath()
|
||||
|
|
@ -78,7 +80,8 @@ public sealed class HlslSourceCompatibilityTests
|
|||
: Activator.CreateInstance(t, Enumerable.Range(0, Components(t)).Select(_ => (object)input(slot++)).ToArray())!).ToArray();
|
||||
var expected = Floats(counterpart.Invoke(null, args)!);
|
||||
var actual = Floats(mirror.Invoke(shader, args)!);
|
||||
if (!expected.SequenceEqual(actual))
|
||||
if (expected.Length != actual.Length || expected.Zip(actual).Any(p => !(float.IsNaN(p.First) && float.IsNaN(p.Second))
|
||||
&& BitConverter.SingleToInt32Bits(p.First) != BitConverter.SingleToInt32Bits(p.Second)))
|
||||
{
|
||||
mismatches.Add($"{mirror.Name}({string.Join(", ", args.Select(a => string.Join(" ", Floats(a))))}): C# {string.Join(" ", expected)}, mirror {string.Join(" ", actual)}");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue