Each routine's fixtures test calls runFixtures with 100 random inputs,
comparing the GPU result against the CPU stdlib reference using a
routine-specific error metric and threshold.
Input Generation
buildArb constructs a fast-check arbitrary that produces a complete args
object for one test run. Scalar params (n, incx, incy, alpha, c,
s) are generated first; vectors x and y are then sized to exactly
(n-1)*inc+1 elements so their length is always consistent with the
generated n and stride.
FTZ — Flush to Zero
WGSL may flush subnormals to zero: "To flush to zero is to replace a
subnormal value for a floating point type with a zero value of that type."
(WGSL §15.7.2)
Filtering generated values for subnormals is not enough — the product of two
small-but-normal values can itself land in the subnormal range (e.g.
F32_MIN_NORMAL * 5.96e-8 ≈ 7e-46). floatArb uses 1e-3 as the minimum
non-zero magnitude, ensuring any pairwise product stays well above
F32_MIN_NORMAL (1e-3 × 1e-3 = 1e-6 >> 1.175e-38).
Error Metrics and Thresholds
runFixtures accepts an errorMetric function and a threshold. Each run
passes if errorMetric(gpuResult, refResult, args) <= threshold. Despite
the name, it isn't always a ULP count — it's maxUlp/ulpDiff for exact
and reduction routines, but forwardFactor/backwardResidualFactor for
everything else (see tests/index.mjs for the full per-routine table).
Property-based fixture runner using fast-check.
Each routine's fixtures test calls
runFixtureswith 100 random inputs, comparing the GPU result against the CPU stdlib reference using a routine-specific error metric and threshold.Input Generation
buildArbconstructs a fast-check arbitrary that produces a complete args object for one test run. Scalar params (n,incx,incy,alpha,c,s) are generated first; vectorsxandyare then sized to exactly(n-1)*inc+1elements so their length is always consistent with the generatednand stride.FTZ — Flush to Zero
WGSL may flush subnormals to zero: "To flush to zero is to replace a subnormal value for a floating point type with a zero value of that type." (WGSL §15.7.2)
Filtering generated values for subnormals is not enough — the product of two small-but-normal values can itself land in the subnormal range (e.g.
F32_MIN_NORMAL * 5.96e-8 ≈ 7e-46).floatArbuses1e-3as the minimum non-zero magnitude, ensuring any pairwise product stays well aboveF32_MIN_NORMAL(1e-3 × 1e-3 = 1e-6 >> 1.175e-38).Error Metrics and Thresholds
runFixturesaccepts anerrorMetricfunction and athreshold. Each run passes iferrorMetric(gpuResult, refResult, args) <= threshold. Despite the name, it isn't always a ULP count — it'smaxUlp/ulpDifffor exact and reduction routines, butforwardFactor/backwardResidualFactorfor everything else (seetests/index.mjsfor the full per-routine table).