diff --git a/packages/cultmath/README.md b/packages/cultmath/README.md index 381b194a..b144c56d 100644 --- a/packages/cultmath/README.md +++ b/packages/cultmath/README.md @@ -29,7 +29,8 @@ shader semantics. `cross`, `length`, `distance`, `normalize`, `reflect`, `csum`, `erf`, `erfinv` (scalar only), exponential `decay`/`damp`, intercept/segment helpers (`distance_to_segment` in 2D and 3D, with and without `out closest`, and `segment_closest`), Catmull-Rom, Bezier curves, and - deterministic value-noise primitives + deterministic value-noise primitives, and `fbm(p)` / `fbm(p, octaves, lacunarity, gain)`, the value-only octave sum + of `snoise` (`cultmath_fbm` in HLSL and GLSL) - Site cells: `power_cells` and `multiplicative_cells` return the two nearest sites of a point as `CultSiteCells`, `soft_gabriel_gate` gates a pair of sites by the empty-disc margin. Each is a loop over the shader steps `cultmath_power_score` / `cultmath_multiplicative_score`, `cultmath_site_cells_empty`, `cultmath_site_cells_insert`, diff --git a/packages/cultmath/docs/design.md b/packages/cultmath/docs/design.md index 3b63f4d2..d9f06b5f 100644 --- a/packages/cultmath/docs/design.md +++ b/packages/cultmath/docs/design.md @@ -451,6 +451,26 @@ together, laid out as `float4(gradient.xyz, value.w)`, with no value-only twin nearly cancels. The total weight `W` is positive for every `pcg3d` input (the smallest found by hill-climbing is 0.056); `W = 0`, and a NaN output, needs adversarial jitter no hash yields. + Lipschitz bound of the `(cosine, sine)` field in `p` (one cell is 1 unit): the + largest singular value of its 2×3 Jacobian is at most + `max(10, 1.25 |side|) / (1 - normalization)` for `normalization` in `[0, 0.9]` and + `|side|` in `[0.25, 25]`. A scalar use of `cosine` or `sine` alone is bounded by the same number (its gradient norm is + one row of the Jacobian, never above the largest singular value). Method (`tools/phacelle-lipschitz`): + random `p` (a 64-unit cube), a uniformly random `side` direction and offset, the + exact gradient at each, 4 million samples per (normalization, |side|); then + hill-climbing from the 256 best samples over `p`, `side` direction and offset + (10 000 steps each); then value differences around the climbed argmax to confirm the + gradient is the field's slope (agreement within 3%). Random sampling alone + undershoots the climbed maximum by up to 4×, because the maxima sit at near-cancellation + points of the blend (`1/|I|`); quote the climbed number. The climbed sup is 0.016 to 0.88 of + the envelope over the sweep: tightest (within 1.15×) at `normalization` 0 and `|side| >= 8`, + and 1.5 to 60× loose at small `|side|` or large `normalization`, where the + envelope's constant 10 is the worst case over all `|side|`. The typical gradient (99.99th percentile of the + samples) is 2 to 5× below the sup, so a sphere trace steps safely at `distance / L` + and can step farther with the returned gradient. The bound is not a proof (a + search found it, not an argument) and it does not hold as `normalization` approaches 1: + the 1/|I| factor is unbounded there (sampled 1335 at `normalization` 1, `|side|` 2π, and + rising with the sample count). If the caller scales `p` by `f` the bound scales by `f`. Cells whose per-axis lower bound `Σ max(0, |local - g| - 0.5)²` is at least 2.25 lie outside the support and have weight exactly 0, so they are skipped, which changes no output bit. Cells whose bound sits just under 2.25 can still diff --git a/packages/cultmath/shaders/CultMath.glsl b/packages/cultmath/shaders/CultMath.glsl index 6ebf3f36..529ad6e8 100644 --- a/packages/cultmath/shaders/CultMath.glsl +++ b/packages/cultmath/shaders/CultMath.glsl @@ -342,6 +342,26 @@ vec4 cultmath_fbm_grad(vec3 p, int octaves, float lacunarity, float gain) return vec4(gradient, value); } +// Value-only octave sum of cultmath_snoise; see the C# math.fbm comment. The one-argument form is four octaves, +// lacunarity 2, gain 0.5. +float cultmath_fbm(vec3 p, int octaves, float lacunarity, float gain) +{ + octaves = clamp(octaves, 0, 16); + float amplitude = 1.0; + float frequency = 1.0; + float value = 0.0; + for (int i = 0; i < octaves; i++) + { + value += amplitude * cultmath_snoise(p * frequency); + frequency *= lacunarity; + amplitude *= gain; + } + + return value; +} + +float cultmath_fbm(vec3 value) { return cultmath_fbm(value, 4, 2.0, 0.5); } + // Ridged multifractal noise (Musgrave, Texturing and Modeling, ch. 16); see the C# math.ridged_grad // comment for the fold/sign derivation, the deliberate crease at n = 0, and why octaves is clamped. vec4 cultmath_ridged_grad(vec3 p, int octaves, float lacunarity, float gain) diff --git a/packages/cultmath/shaders/CultMath.hlsl b/packages/cultmath/shaders/CultMath.hlsl index d3eea396..fc9f7a70 100644 --- a/packages/cultmath/shaders/CultMath.hlsl +++ b/packages/cultmath/shaders/CultMath.hlsl @@ -342,6 +342,26 @@ float4 cultmath_fbm_grad(float3 p, int octaves, float lacunarity, float gain) return float4(gradient, value); } +// Value-only octave sum of cultmath_snoise; see the C# math.fbm comment. The one-argument form is four octaves, +// lacunarity 2, gain 0.5. +float cultmath_fbm(float3 p, int octaves, float lacunarity, float gain) +{ + octaves = clamp(octaves, 0, 16); + float amplitude = 1.0; + float frequency = 1.0; + float value = 0.0; + for (int i = 0; i < octaves; i++) + { + value += amplitude * cultmath_snoise(p * frequency); + frequency *= lacunarity; + amplitude *= gain; + } + + return value; +} + +float cultmath_fbm(float3 value) { return cultmath_fbm(value, 4, 2.0, 0.5); } + // Ridged multifractal noise (Musgrave, Texturing and Modeling, ch. 16); see the C# math.ridged_grad // comment for the fold/sign derivation, the deliberate crease at n = 0, and why octaves is clamped. float4 cultmath_ridged_grad(float3 p, int octaves, float lacunarity, float gain) diff --git a/packages/cultmath/src/CultMath/math.cs b/packages/cultmath/src/CultMath/math.cs index 0d22dc4c..a7c41f48 100644 --- a/packages/cultmath/src/CultMath/math.cs +++ b/packages/cultmath/src/CultMath/math.cs @@ -823,6 +823,29 @@ public static partial class math return new float4(gradient, value); } + // Value-only fractional Brownian motion: the octave sum of snoise, octave i at frequency lacunarity^i and + // amplitude gain^i. It is fbm_grad(p, octaves, lacunarity, gain).w without the gradient work (to float + // rounding: snoise and snoise_grad.w order their arithmetic differently), so a loop that only wants the height + // (a sphere trace) does not pay for the gradient. octaves clamps to [0, 16] as fbm_grad's does. The one-argument + // form is the stock four octaves, lacunarity 2, gain 1/2: its range is within +-1.875 times snoise's. + public static float fbm(float3 p, int octaves, float lacunarity, float gain) + { + octaves = clamp(octaves, 0, 16); + var amplitude = 1.0f; + var frequency = 1.0f; + var value = 0.0f; + for (var i = 0; i < octaves; i++) + { + value += amplitude * snoise(p * frequency); + frequency *= lacunarity; + amplitude *= gain; + } + + return value; + } + + public static float fbm(float3 value) => fbm(value, 4, 2.0f, 0.5f); + // Ridged multifractal noise (Musgrave, Texturing and Modeling, ch. 16; the operator's dune term, // 2026-09-25): each octave folds snoise_grad about zero, value = Sum a_i*(1 - |n_i|), gradient = // -Sum a_i*f_i*sign(n_i)*grad(n_i), the same per-octave frequency scaling as fbm_grad's chain diff --git a/packages/cultmath/tests/CultMath.Tests/FbmTests.cs b/packages/cultmath/tests/CultMath.Tests/FbmTests.cs new file mode 100644 index 00000000..89ca4dc9 --- /dev/null +++ b/packages/cultmath/tests/CultMath.Tests/FbmTests.cs @@ -0,0 +1,73 @@ +using System; +using CultMath; +using Xunit; + +namespace CultMath.Tests; + +public sealed class FbmTests +{ + private static float3 Point(System.Random r) => new(r.NextSingle() * 20.0f - 10.0f, r.NextSingle() * 20.0f - 10.0f, r.NextSingle() * 20.0f - 10.0f); + + [Fact] + public void OneOctaveIsSnoise() + { + var random = new System.Random(0xFB01); + for (var i = 0; i < 64; i++) + { + var p = Point(random); + Assert.Equal(math.snoise(p), math.fbm(p, 1, 1.0f + random.NextSingle() * 3.0f, 0.1f + random.NextSingle() * 0.8f)); + } + } + + [Fact] + public void ZeroOrNegativeOctavesSumNothing() + { + var p = new float3(0.3f, 1.7f, -2.2f); + Assert.Equal(0.0f, math.fbm(p, 0, 2.0f, 0.5f)); + Assert.Equal(0.0f, math.fbm(p, -5, 2.0f, 0.5f)); + } + + [Fact] + public void OctavesCompoundGainAndLacunarityIndependently() + { + // gain != lacunarity and neither is 1, so applying either once, or swapping them, changes the sum. + const float lacunarity = 2.3f; + const float gain = 0.4f; + var random = new System.Random(0xFB02); + for (var i = 0; i < 64; i++) + { + var p = Point(random); + var expected = math.snoise(p) + gain * math.snoise(p * lacunarity) + gain * gain * math.snoise(p * (lacunarity * lacunarity)); + Assert.Equal(expected, math.fbm(p, 3, lacunarity, gain), 5); + } + } + + [Fact] + public void ValueIsFbmGradsValue() + { + var random = new System.Random(0xFB03); + for (var i = 0; i < 128; i++) + { + var p = Point(random); + Assert.Equal(math.fbm_grad(p, 5, 2.0f, 0.55f).w, math.fbm(p, 5, 2.0f, 0.55f), 4); + } + } + + [Fact] + public void OctaveCountClampsToSixteenLikeFbmGrad() + { + var p = new float3(0.3f, 1.7f, -2.2f); + Assert.Equal(math.fbm(p, 16, 1.1f, 0.9f), math.fbm(p, 1000, 1.1f, 0.9f)); + } + + [Fact] + public void OneArgumentFormIsFourOctavesLacunarityTwoGainHalf() + { + var random = new System.Random(0xFB04); + for (var i = 0; i < 64; i++) + { + var p = Point(random); + Assert.Equal(math.fbm(p, 4, 2.0f, 0.5f), math.fbm(p)); + } + } +} diff --git a/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs b/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs index c2b604f6..10e08380 100644 --- a/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs +++ b/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs @@ -904,6 +904,7 @@ static int4 clamp(int4 x, int4 a, int4 b) { if (a.x > b.x || a.y > b.y || a.z > // The site-array functions: a fixed-capacity array and a count, killed on the device (the lattice at rings up to 17). new Family($"vec4 cultmath_power_border(vec3, vec4[{SiteArrays.Capacity}], int)", "ulp-bounded", SiteArrays.PowerBorderArguments), new Family($"vec4 cultmath_weighted_lattice_cells(vec2, float, vec4[{SiteArrays.Capacity}], int, float, float, float, float, float, vec2, float)", "ulp-bounded", SiteArrays.LatticeArguments), + new Family("float cultmath_fbm(vec3, int, float, float)", "ulp-bounded", r => new object[] { Point3(r), 4, 2.0f, 0.5f }), }).ToArray(); // A point of magnitude m, m log-uniform in [lo, hi]: one component at +-m, the other two uniform in [-m, m], diff --git a/packages/cultmath/tests/CultMath.Tests/HlslSourceCompatibilityTests.cs b/packages/cultmath/tests/CultMath.Tests/HlslSourceCompatibilityTests.cs index 2c994be8..821ba94a 100644 --- a/packages/cultmath/tests/CultMath.Tests/HlslSourceCompatibilityTests.cs +++ b/packages/cultmath/tests/CultMath.Tests/HlslSourceCompatibilityTests.cs @@ -47,6 +47,8 @@ public sealed class HlslSourceCompatibilityTests Assert.NotNull(ShaderFunction(shader, "cultmath_snoise_hessian", typeof(float3))); Assert.NotNull(ShaderFunction(shader, "cultmath_integral_clamp_linear", typeof(float), typeof(float), typeof(float), typeof(float), typeof(float), typeof(float))); Assert.NotNull(ShaderFunction(shader, "cultmath_fbm_grad", typeof(float3), typeof(int), typeof(float), typeof(float))); + Assert.NotNull(ShaderFunction(shader, "cultmath_fbm", typeof(float3), typeof(int), typeof(float), typeof(float))); + Assert.NotNull(ShaderFunction(shader, "cultmath_fbm", typeof(float3))); Assert.NotNull(ShaderFunction(shader, "cultmath_ridged_grad", typeof(float3), typeof(int), typeof(float), typeof(float))); Assert.NotNull(ShaderFunction(shader, "cultmath_phacelle", typeof(float3), typeof(float3), typeof(float), typeof(float))); Assert.NotNull(ShaderFunction(shader, "cultmath_iv_snoise_ball", typeof(float3), typeof(float))); @@ -205,7 +207,7 @@ public sealed class HlslSourceCompatibilityTests Assert.True(mismatches.Count == 0, $"{mismatches.Count} mismatches:{Environment.NewLine}{string.Join(Environment.NewLine, mismatches.Take(12))}"); // The three site-array functions are compared by SiteArrayMirrorsMatchCSharp, which draws their counts and arrays. - Assert.Equal(140, compared.Count); + Assert.Equal(141, compared.Count); } /// diff --git a/packages/cultmath/tests/CultMath.Tests/PhacelleTests.cs b/packages/cultmath/tests/CultMath.Tests/PhacelleTests.cs index 71f5b452..e9c3377d 100644 --- a/packages/cultmath/tests/CultMath.Tests/PhacelleTests.cs +++ b/packages/cultmath/tests/CultMath.Tests/PhacelleTests.cs @@ -337,4 +337,33 @@ public sealed class PhacelleTests Assert.Equal(BitConverter.SingleToInt32Bits(expected.z), BitConverter.SingleToInt32Bits(actual.z)); Assert.Equal(BitConverter.SingleToInt32Bits(expected.w), BitConverter.SingleToInt32Bits(actual.w)); } + + // The Lipschitz envelope of the (cosine, sine) field in p, per docs/design.md ("Lipschitz bound"): the largest + // singular value of its 2x3 Jacobian never exceeds max(10, 1.25 |side|) / (1 - normalization), for normalization + // in [0, 0.9] and |side| in [0.25, 25]. tools/phacelle-lipschitz measures it by sampling and hill-climbing; this + // pins that no ordinary sample passes it (the climbed maximum is at most 0.88 of the envelope). + [Theory] + [InlineData(0.0f)] + [InlineData(0.5f)] + [InlineData(0.75f)] + [InlineData(0.9f)] + public void GradientNormStaysUnderTheDocumentedLipschitzEnvelope(float normalization) + { + var random = new System.Random(0x11B5); + foreach (var sideLength in new[] { 0.25f, 1.0f, 1.5f, 4.0f, 12.5f, 25.0f }) + { + var envelope = Math.Max(10.0, 1.25 * sideLength) / (1.0 - normalization); + for (var i = 0; i < 20000; i++) + { + var p = RandomPoint(random, 32.0f); + var side = math.normalize(RandomSide(random)) * sideLength; + var phasor = math.phacelle(p, side, random.NextSingle(), normalization); + var a = (double)math.dot(phasor.cosine.xyz, phasor.cosine.xyz); + var d = (double)math.dot(phasor.sine.xyz, phasor.sine.xyz); + var b = (double)math.dot(phasor.cosine.xyz, phasor.sine.xyz); + var norm = Math.Sqrt((a + d) / 2.0 + Math.Sqrt(Math.Max(0.0, (a + d) * (a + d) / 4.0 - (a * d - b * b)))); + Assert.True(norm <= envelope, $"|J| {norm} passes the envelope {envelope} at p {p}, side {side}, normalization {normalization}"); + } + } + } } diff --git a/packages/cultmath/tests/CultMath.Tests/fixtures/device-bounds-lavapipe.txt b/packages/cultmath/tests/CultMath.Tests/fixtures/device-bounds-lavapipe.txt index 42706157..0a61b572 100644 --- a/packages/cultmath/tests/CultMath.Tests/fixtures/device-bounds-lavapipe.txt +++ b/packages/cultmath/tests/CultMath.Tests/fixtures/device-bounds-lavapipe.txt @@ -126,6 +126,7 @@ lavapipe-glsl 121 float cultmath_lattice_distance(vec2, vec2, float, vec2, float lavapipe-glsl 122 float cultmath_lattice_smooth_step(float, float, float, float) ulp-bounded 256 0 0 6cbeddde536b12e83873f2e5ac60d16bef22049d2a7dea61af0ff1e0d5b84740 lavapipe-glsl 123 vec4 cultmath_power_border(vec3, vec4[128], int) ulp-bounded 188 65.72121683891783 0 8427c2b99109a4f59ff745fdb87f261deb1cbae34ce99bc1ae05ebb7f9963b4d lavapipe-glsl 124 vec4 cultmath_weighted_lattice_cells(vec2, float, vec4[128], int, float, float, float, float, float, vec2, float) ulp-bounded 179 3 0 fd3b58c4e2ba8a7bf801a1e6cdff82468abcb368442bc98b2583fda9d2e6f823 +lavapipe-glsl 125 float cultmath_fbm(vec3, int, float, float) ulp-bounded 43 190.375 0 8f852b55293bd75a4e2e64cd1d1f5083605c2ba2d0877cdf4e8e507c72890135 lavapipe-hlsl 0 float cultmath_snoise(vec3) ulp-bounded 94 122.6875 0 5d41c14241a13124f2e1b49f230f5df0c48d0d69fb1be9ef2f33dc1702bf0b0a lavapipe-hlsl 1 float cultmath_snoise(vec2) ulp-bounded 204 1 0 81d9c62726afdccbbe4ffef173b5c92731eb6bf5927b3979d653e50dbd5d4064 lavapipe-hlsl 2 vec4 cultmath_snoise_grad(vec3) ulp-bounded 71 617.5 0 f7e9ed1707cdb015efaba0e0150193309da0d4c125349518f8b7c60a17b25790 @@ -251,3 +252,4 @@ lavapipe-hlsl 121 float cultmath_lattice_distance(vec2, vec2, float, vec2, float lavapipe-hlsl 122 float cultmath_lattice_smooth_step(float, float, float, float) ulp-bounded 256 0 0 6cbeddde536b12e83873f2e5ac60d16bef22049d2a7dea61af0ff1e0d5b84740 lavapipe-hlsl 123 vec4 cultmath_power_border(vec3, vec4[128], int) ulp-bounded 188 65.72121683891783 0 8427c2b99109a4f59ff745fdb87f261deb1cbae34ce99bc1ae05ebb7f9963b4d lavapipe-hlsl 124 vec4 cultmath_weighted_lattice_cells(vec2, float, vec4[128], int, float, float, float, float, float, vec2, float) ulp-bounded 179 3 0 fd3b58c4e2ba8a7bf801a1e6cdff82468abcb368442bc98b2583fda9d2e6f823 +lavapipe-hlsl 125 float cultmath_fbm(vec3, int, float, float) ulp-bounded 49 190.375 0 cd02f850f1d01ff77a3cb1c49af2bb49e51bb18c395936703cb37b7729ad2c88 diff --git a/packages/cultmath/tests/CultMath.Tests/fixtures/glsl-parity.json b/packages/cultmath/tests/CultMath.Tests/fixtures/glsl-parity.json index f2ab1f19..244d068c 100644 --- a/packages/cultmath/tests/CultMath.Tests/fixtures/glsl-parity.json +++ b/packages/cultmath/tests/CultMath.Tests/fixtures/glsl-parity.json @@ -6820,7 +6820,7 @@ { "glsl": "vec2 cultmath_iv_exp(vec2)", "tolerance": "ulp-bounded, platform exp", - "platform": "Ubuntu 24.04.5 LTS; .NET 10.0.12", + "platform": "Debian GNU/Linux 13 (trixie); .NET 10.0.14", "cases": [ "41202b2a 4120314e -> 46ade79e 46ae2a6b", "c0d1a016 bfb9db96 -> 3abb4cbc 3e6fb77f", @@ -7083,7 +7083,7 @@ { "glsl": "CultPhasor cultmath_phacelle(vec3, vec3, float, float)", "tolerance": "ulp-bounded, platform exp, sin, cos; across platforms |diff| <= 2^-20 max(|v|, 1); on a device |diff| <= 2^-18 max(|v|, 1)", - "platform": "Ubuntu 24.04.5 LTS; .NET 10.0.12", + "platform": "Debian GNU/Linux 13 (trixie); .NET 10.0.14", "cases": [ "c01d8630 41b2cd8c 41ea274c bfa19894 40aeb6ce 40918978 3e9be843 3f000000 -> bf74d9fb 3fb71956 bf35fe4e 3f21280a c01277e2 403b5fe4 40464bbd bd5b4455", "c2234cf7 4237b112 419ae0c0 c0acbcd4 bf60f9a0 bfeb2b08 3ebf0a10 3f000000 -> c0d0048f 3f228da3 bfc85f60 3edaf41b c0171c80 be137f8c be1c92a3 bf5747bf", @@ -12591,7 +12591,7 @@ { "glsl": "float cultmath_cycles_power(float, float)", "tolerance": "ulp-bounded, platform pow", - "platform": "Ubuntu 24.04.5 LTS; .NET 10.0.12", + "platform": "Debian GNU/Linux 13 (trixie); .NET 10.0.14", "cases": [ "bfb8bc1c 00000000 -> 3f800000", "3f7fc090 3fa15ed0 -> 3f7fb009", @@ -12854,7 +12854,7 @@ { "glsl": "float cultmath_cycles_logarithm(float, float)", "tolerance": "ulp-bounded, platform log", - "platform": "Ubuntu 24.04.5 LTS; .NET 10.0.12", + "platform": "Debian GNU/Linux 13 (trixie); .NET 10.0.14", "cases": [ "416175a4 418f2e6d -> 3f6ac789", "40d2d3ad 416ecd13 -> 3f328da7", @@ -24907,7 +24907,7 @@ { "glsl": "float cultmath_cycles_arcsine(float)", "tolerance": "ulp-bounded, platform asin", - "platform": "Ubuntu 24.04.5 LTS; .NET 10.0.12", + "platform": "Debian GNU/Linux 13 (trixie); .NET 10.0.14", "cases": [ "3f74439c -> 3fa22776", "beaa06dc -> bead5166", @@ -24919,27 +24919,27 @@ "bf44c25b -> bf606b2a", "be9326d8 -> be9541be", "bf047a79 -> bf0b3e4e", - "3f6fb444 -> 3f9b2514", + "3f6fb444 -> 3f9b2513", "bec3bc1c -> bec8d8b0", "3ed94bc8 -> 3ee069a8", "be732cb0 -> be75852c", "bf525772 -> bf76dbfc", "3f5f4508 -> 3f87a01e", - "3f5243a0 -> 3f76b93a", + "3f5243a0 -> 3f76b939", "3f6f8480 -> 3f9ae13d", "bf43af08 -> bf5ebe7a", "3fb52362 -> 3fc90fdb", "3eae8380 -> 3eb2152a", "bf3ff8fb -> bf590ffc", "3f7bb06c -> 3fb189e5", - "3dee93e0 -> 3def1ede", + "3dee93e0 -> 3def1edd", "bfb0b96e -> bfc90fdb", "bf454824 -> bf613cb1", "3f23fb40 -> 3f31f9c7", "be9b0000 -> be9d788d", "3fb7c110 -> 3fc90fdb", "bf0c30e4 -> bf145b51", - "3e855c0c -> 3e86ea5c", + "3e855c0c -> 3e86ea5d", "bf0e2123 -> bf16ae2c", "3f72c708 -> 3f9fbe32", "3f98afd8 -> 3fc90fdb", @@ -24970,7 +24970,7 @@ "3f81d10a -> 3fc90fdb", "bf033714 -> bf09c506", "3fa3a04a -> 3fc90fdb", - "3f1281b8 -> 3f1bfaf2", + "3f1281b8 -> 3f1bfaf3", "bf34447a -> bf480038", "bf9eb144 -> bfc90fdb", "3f38d780 -> 3f4e86c5", @@ -25014,7 +25014,7 @@ "3f039538 -> 3f0a32b8", "3f4cd500 -> 3f6d70e3", "3ee655e4 -> 3eeee961", - "3ef23d20 -> 3efc5474", + "3ef23d20 -> 3efc5473", "3e0c9370 -> 3e0d0572", "3f9f079c -> 3fc90fdb", "3e4b1770 -> 3e4c7278", @@ -25038,7 +25038,7 @@ "3f982f94 -> 3fc90fdb", "3ef183b4 -> 3efb8213", "bed4d500 -> bedb7e63", - "bf49041d -> bf672e44", + "bf49041d -> bf672e45", "bf986f2a -> bfc90fdb", "3eeeeb04 -> 3ef89167", "bf05421c -> bf0c27dd", @@ -25072,7 +25072,7 @@ "3f48bf60 -> 3f66bf61", "3f953182 -> 3fc90fdb", "3e21e6d0 -> 3e229577", - "bf043606 -> bf0aee58", + "bf043606 -> bf0aee57", "3d94f740 -> 3d9518f5", "3c15e400 -> 3c15e489", "bfb51e92 -> bfc90fdb", @@ -25103,7 +25103,7 @@ "3f4133b0 -> 3f5aedab", "3f25a7cc -> 3f3429d9", "3f4f5e44 -> 3f71b78b", - "3f795244 -> 3fabc288", + "3f795244 -> 3fabc287", "3de214a0 -> 3de28ad3", "3e8fe798 -> 3e91deba", "bf9af793 -> bfc90fdb", @@ -25127,7 +25127,7 @@ "3ecad4fc -> 3ed08d21", "3e05a058 -> 3e06022f", "beb65270 -> beba69cf", - "3f5058c0 -> 3f7364a8", + "3f5058c0 -> 3f7364a7", "3fa6360c -> 3fc90fdb", "3f466ed4 -> 3f630d19", "3f700570 -> 3f9b993a", @@ -25144,12 +25144,12 @@ "beaaf660 -> beae4f6a", "3f92651c -> 3fc90fdb", "3f8dddfa -> 3fc90fdb", - "3f2ed97c -> 3f407a92", + "3f2ed97c -> 3f407a93", "be5e0a78 -> be5fd19b", "bf794a5d -> bfabb123", "bf166554 -> bf20c10e", "3ec7db68 -> 3ecd50d0", - "3f0f3a38 -> 3f1800b6", + "3f0f3a38 -> 3f1800b5", "bf9d2433 -> bfc90fdb", "be1b6e70 -> be1c08d6", "3f8cf9f4 -> 3fc90fdb", @@ -25170,7 +25170,7 @@ { "glsl": "float cultmath_cycles_arccosine(float)", "tolerance": "ulp-bounded, platform acos", - "platform": "Ubuntu 24.04.5 LTS; .NET 10.0.12", + "platform": "Debian GNU/Linux 13 (trixie); .NET 10.0.14", "cases": [ "3da419e0 -> 3fbecb6b", "bccc7dc0 -> 3fcc41e7", @@ -25185,7 +25185,7 @@ "3f99f728 -> 00000000", "3efe6a30 -> 3f867f99", "bf8e3141 -> 40490fdb", - "be1ccb60 -> 3fdcbd18", + "be1ccb60 -> 3fdcbd17", "bf6312e3 -> 402a57f6", "beca9b18 -> 3ffd2360", "bfa261f2 -> 40490fdb", @@ -25221,7 +25221,7 @@ "3e8561b8 -> 3fa753cc", "bf888ac6 -> 40490fdb", "3fbb7d54 -> 00000000", - "3ec05018 -> 3f97c656", + "3ec05018 -> 3f97c657", "bf8c0f8c -> 40490fdb", "bf72b2f0 -> 40345736", "3f244db8 -> 3f5fba77", @@ -25250,7 +25250,7 @@ "3f8f186c -> 00000000", "3f30b1e8 -> 3f4f1b53", "3d953310 -> 3fbfba8c", - "bde0dee0 -> 3fd7250e", + "bde0dee0 -> 3fd7250d", "3f7b8300 -> 3e4007f6", "3f35601c -> 3f488ecf", "bf9a050a -> 40490fdb", @@ -25272,7 +25272,7 @@ "bfb4c70e -> 40490fdb", "3e93057c -> 3fa3c820", "3f2b8624 -> 3f56293a", - "bf51e010 -> 40220aae", + "bf51e010 -> 40220aaf", "bf8aa06c -> 40490fdb", "3f9839c8 -> 00000000", "3f28eed8 -> 3f59a156", @@ -25297,7 +25297,7 @@ "3e8aea00 -> 3fa5e480", "3ed35888 -> 3f9298c3", "3f567510 -> 3f13e3ce", - "3e9761c8 -> 3fa2a464", + "3e9761c8 -> 3fa2a463", "3fbc3ca0 -> 00000000", "bf5814bd -> 4024d6ee", "3f807f68 -> 00000000", @@ -25306,7 +25306,7 @@ "3f1a4008 -> 3f6c92ef", "3fa491d4 -> 00000000", "3f385e00 -> 3f44484f", - "3e9ac620 -> 3fa1c0e6", + "3e9ac620 -> 3fa1c0e5", "3e9541ec -> 3fa3329f", "bf647da0 -> 402b1eac", "3dc1c080 -> 3fbcef2e", @@ -25351,7 +25351,7 @@ "beab7798 -> 3ff4c5fc", "3f0df694 -> 3f7ba4b1", "3f94dda6 -> 00000000", - "bf5c7d84 -> 4026f34c", + "bf5c7d84 -> 4026f34d", "3f9296ba -> 00000000", "bfbada1e -> 40490fdb", "3f8cf40a -> 00000000", @@ -25364,7 +25364,7 @@ "bf6b7605 -> 402f4022", "bfad549a -> 40490fdb", "3faa5d8c -> 00000000", - "3e8b7c88 -> 3fa5be6e", + "3e8b7c88 -> 3fa5be6f", "3f3fa580 -> 3f398dc6", "bf61690a -> 4029746e", "bf73a264 -> 403516b7", @@ -25427,13 +25427,13 @@ "3f930316 -> 00000000", "bf6bfdd5 -> 402f9730", "3fa53312 -> 00000000", - "bf1a0e9a -> 400ddba4" + "bf1a0e9a -> 400ddba5" ] }, { "glsl": "float cultmath_cycles_arctan2(float, float)", "tolerance": "ulp-bounded, platform atan", - "platform": "Ubuntu 24.04.5 LTS; .NET 10.0.12", + "platform": "Debian GNU/Linux 13 (trixie); .NET 10.0.14", "cases": [ "c08cbc16 c1549681 -> c0349aac", "418c8108 41948858 -> 3f41f3ee", @@ -25442,7 +25442,7 @@ "c1853a3e 4183660c -> bf4ad4c8", "40cc3750 c18864ad -> 4032239a", "c1841fce 414eb7b4 -> bf682df1", - "3f7f11c0 41915dcc -> 3d605f59", + "3f7f11c0 41915dcc -> 3d605f58", "c1190690 40822148 -> bf959a14", "41235546 414a8e7c -> 3f2db91b", "c173027e 4157ae48 -> bf584be7", @@ -25451,12 +25451,12 @@ "41504298 c1432d3c -> 4014b8bf", "41976732 4165afb0 -> 3f6bff17", "c12faa83 c19c5692 -> c0284d67", - "c0aa038c c0cb2194 -> c01c7634", + "c0aa038c c0cb2194 -> c01c7633", "c0df2a78 c0a67120 -> c00d8b25", "4144767c c11a39a5 -> 400f2006", "c00c8aa0 4194be56 -> bdf0c4af", "3f876310 c1937378 -> 404564aa", - "41636814 c1172a84 -> 400a13e2", + "41636814 c1172a84 -> 400a13e1", "3f81e2e0 bd4f6800 -> 3fcf71a7", "41309010 c08f8f1c -> 3ffa7c90", "40982a9c 3f904760 -> 3fab4541", @@ -25467,23 +25467,23 @@ "4192314a 4086f2c0 -> 3fac080a", "411b37ca c171da02 -> 40248b70", "c1664f18 c130242c -> c00e512f", - "40eced38 40bd9198 -> 3f655f42", - "4104386c 411d5130 -> 3f32ed70", + "40eced38 40bd9198 -> 3f655f43", + "4104386c 411d5130 -> 3f32ed71", "bdd98800 c15cd654 -> c04891c6", "c161bae2 c19f6675 -> c021a16c", "c15bccb4 4139d89a -> bf5e709e", "c1065de6 c1860dc7 -> c02b5428", "419a2318 416c82f8 -> 3f6a973f", - "bf911740 3eafb040 -> bfa36fa4", + "bf911740 3eafb040 -> bfa36fa5", "41961b7c c01fd768 -> 3fd9fffb", "4042f5d8 c00cea20 -> 400c95f1", - "c12f053d 418e307c -> bf0d3c4a", + "c12f053d 418e307c -> bf0d3c4b", "403d4400 c11dc866 -> 40366a62", "c15831c7 412e7716 -> bf644dcc", "c0d29330 41698de0 -> bed8d810", "c0fd3872 415963f8 -> bf0702af", "c131bb1f c074e670 -> bff386a5", - "417f6828 40a71880 -> 3fa09868", + "417f6828 40a71880 -> 3fa09869", "40497b80 41717390 -> 3e529a28", "413af82e c196608f -> 40257713", "4179eb80 bfb8a2f0 -> 3fd4d959", @@ -25492,8 +25492,8 @@ "414f2488 c180a1ba -> 401dad4f", "4036b5f0 c15671f1 -> 403ba162", "bf97a3d0 c0046bb8 -> c027c818", - "40ae84d8 c0f9a4b6 -> 402203ec", - "3feb4440 40f9d6e0 -> 3e6cc1c5", + "40ae84d8 c0f9a4b6 -> 402203eb", + "3feb4440 40f9d6e0 -> 3e6cc1c6", "419f7088 411a15a2 -> 3f8f723b", "c188441a bfeff970 -> bfd71812", "40560bd0 410fd5de -> 3eb65b86", @@ -25508,10 +25508,10 @@ "414c9fc4 418893dc -> 3f249745", "c033b3b8 c18b7729 -> c03ed777", "c13f3667 c152d7a7 -> c019eb30", - "c086fb50 41627eb4 -> be9446ba", + "c086fb50 41627eb4 -> be9446b9", "c13dde75 41858b9e -> bf1e348f", "41655ddc c13d8347 -> 4010b9bb", - "40a95660 41584940 -> 3ebf0aa4", + "40a95660 41584940 -> 3ebf0aa3", "4141fbc4 c0ce1146 -> 4003c77a", "c0091050 c155ea5c -> c03ee580", "40b8f0c0 c18079b9 -> 4032f416", @@ -25524,17 +25524,17 @@ "40a7d388 c07a5f68 -> 400d8c45", "4186baee c161afee -> 4011273b", "c1988920 3f471480 -> bfc3d822", - "3f70c440 40be95d8 -> 3e2060cf", + "3f70c440 40be95d8 -> 3e2060d0", "417834e8 415d5098 -> 3f57b555", "c1775234 40c0f8f8 -> bf99734e", "c1974114 4198ffc8 -> bf479800", "410c0ec4 bff12930 -> 3fe432a6", "413a6dc4 c09ce414 -> 3ffc0b0b", "be987ac0 c097edfc -> c0450d7e", - "bfa53460 4194fa8e -> bd8db6e0", + "bfa53460 4194fa8e -> bd8db6e1", "40d38cc8 c19c290d -> 403429aa", "415e9230 bea6b840 -> 3fcc0ec1", - "c1612e94 4199eb08 -> bf21ad98", + "c1612e94 4199eb08 -> bf21ad99", "c102419c 3f3e0580 -> bfbd6c6a", "c171e10c 3e75cd00 -> bfc70799", "c159f7c3 c040e368 -> bfe4ee5c", @@ -25543,18 +25543,18 @@ "c0ebecc4 4188a552 -> bed0a0ee", "40b612c0 419e96ba -> 3e8f1b96", "c1392859 c184cf09 -> c02219d5", - "40f88828 c0379bc8 -> 3ff65a7b", + "40f88828 c0379bc8 -> 3ff65a7c", "4183657e 418c205a -> 3f40d57c", "3d64c400 c049c398 -> 4047eda0", - "c184e5e2 c0ba5c6c -> bff438b2", - "c13cf1d2 c09df406 -> bffbbd3f", + "c184e5e2 c0ba5c6c -> bff438b3", + "c13cf1d2 c09df406 -> bffbbd40", "41951ea0 40d3e958 -> 3f9d5e14", "4117a1c4 4182e3fa -> 3f0666f9", "c100421b 3fa11c00 -> bfb52067", "c0a4c048 3fd9b1a0 -> bfa0392a", "c0bce6f0 c0a756e0 -> c012ed67", - "410f31a8 4089ad2c -> 3f8fb3fa", - "beb17800 40836d64 -> bdac6ea3", + "410f31a8 4089ad2c -> 3f8fb3f9", + "beb17800 40836d64 -> bdac6ea4", "c0724d88 bee688c0 -> bfd836b1", "3fb83bc0 c1693dec -> 4042c367", "c18c3dd4 4027c610 -> bfb60fc6", @@ -25562,7 +25562,7 @@ "41231d74 404d91d0 -> 3fa1fe4e", "c0e92c5a c04e1b80 -> bffe543d", "404ffd08 c1396f46 -> 403790b4", - "bf50eb60 41702f48 -> bd5e7502", + "bf50eb60 41702f48 -> bd5e7501", "c0294f90 412b4d2a -> be780e6d", "c0fe6df0 41350240 -> bf1cd3f4", "bfd3b0d0 41824f24 -> bdcf3ab0", @@ -25571,15 +25571,15 @@ "400eab20 c180166a -> 4040354a", "40b741d8 415a8318 -> 3ecb4b31", "c0b19f72 c1844941 -> c03455ba", - "418bd268 c0f5d76c -> 3ffe1262", + "418bd268 c0f5d76c -> 3ffe1263", "3fa6a0a0 c19bf37a -> 4044cb60", "417687a4 418fb914 -> 3f357bee", - "c104b28d 40b23950 -> bf7abbaa", + "c104b28d 40b23950 -> bf7abba9", "40b00cb0 be7bb000 -> 3fcec6d5", "41836b9a c15bc2b2 -> 40111937", "40697890 417344c4 -> 3e7121a8", "4190121e c158f0df -> 400dd562", - "c18bdd8b bf6a2c00 -> bfcfc0bd", + "c18bdd8b bf6a2c00 -> bfcfc0be", "418b5438 4191f240 -> 3f431ff0", "c0f7e4e4 410571fe -> bf3f9e8f", "c163d334 bd98d600 -> bfc9bb97", @@ -25590,27 +25590,27 @@ "c133cbd1 c12c03ab -> c015618c", "bf32bb00 c1111506 -> c04424d8", "40e3794c bfa93e10 -> 3fe099e8", - "419cd3d2 bf1c60c0 -> 3fcd0c96", + "419cd3d2 bf1c60c0 -> 3fcd0c97", "bf800240 40cf58c0 -> be1ccef2", "c1630418 4194bc52 -> bf26e0ae", - "419ee38a c0d13810 -> 3ff1c4a8", + "419ee38a c0d13810 -> 3ff1c4a9", "c0554ad8 bf756f80 -> bfecea8c", "4155c1e0 c086c8b0 -> 3ff02782", "c19438df c155bc54 -> c00c82ae", "4181ed52 c072d0e0 -> 3fe66fdc", "41335fee c12dcd2f -> 4015c95e", "c1571882 c194fd20 -> c0210be4", - "c19a88b4 c0b6e8d0 -> bfede30f", - "c153621e c19b2864 -> c022ca69", - "40a5abdc 419f6cf2 -> 3e822341", + "c19a88b4 c0b6e8d0 -> bfede310", + "c153621e c19b2864 -> c022ca68", + "40a5abdc 419f6cf2 -> 3e822342", "40d30c58 419f1e6c -> 3ea3ee9c", "418c0490 c0b33c62 -> 3ff0b4e5", - "c0831f14 40e27288 -> bf065d6a", - "bf2ad860 4075b2b0 -> be303f57", + "c0831f14 40e27288 -> bf065d69", + "bf2ad860 4075b2b0 -> be303f56", "bf04a640 bffc8c00 -> c038a00e", "bf41b3a0 40b8c260 -> be056f50", "4021d860 c14d4bd9 -> 403c9ba3", - "3d83a000 40cb8cf8 -> 3c258915", + "3d83a000 40cb8cf8 -> 3c258914", "c178b13e c0fba980 -> c0028267", "c0108e98 40935624 -> bee9826e", "40833c68 40d08ed0 -> 3f0fc87b", @@ -25623,13 +25623,13 @@ "c1000d87 419fc51c -> bec32579", "c0814a50 c18dda43 -> c03ab943", "c186e3b7 c15b7765 -> c0103ce8", - "4183a496 c01779a8 -> 3fdb58d2", + "4183a496 c01779a8 -> 3fdb58d3", "40e51c20 bfe49ed0 -> 3fe85ad7", - "4187b382 c1690142 -> 4011ef14", - "40d37970 419b19ac -> 3ea83333", + "4187b382 c1690142 -> 4011ef13", + "40d37970 419b19ac -> 3ea83332", "3fa7f3f0 c0b5afc8 -> 403a86cd", "c122c32b 416a72a0 -> bf1b5a62", - "40374b70 c19b6a93 -> 403fb1c2", + "40374b70 c19b6a93 -> 403fb1c3", "c08588a0 c19f609e -> c03bd8f2", "419cbe90 c170df46 -> 400e75e0", "4182e2b4 c1643109 -> 40126ac4", @@ -25642,9 +25642,9 @@ "c1300d51 c108ac40 -> c00ec793", "410261e6 c1588362 -> 40265f3f", "419adcac 40054e48 -> 3fbb5784", - "41798160 c0ecc4b0 -> 4000e25e", + "41798160 c0ecc4b0 -> 4000e25f", "40639318 c1702fdd -> 403a2d2c", - "c1794797 c1829f3b -> c0184bca", + "c1794797 c1829f3b -> c0184bc9", "c0904192 c0035a40 -> bfffbf67", "41787da0 c19a2a35 -> 401da5e0", "4120e654 c1014c4b -> 400fdab9", @@ -25664,15 +25664,15 @@ "4112e32a c18e9f42 -> 402aa0a2", "bfaa2d50 40ef51f8 -> be3427dc", "c16ae95c 406f7cb0 -> bfa91e64", - "40d2db80 405037e8 -> 3f8e5b81", + "40d2db80 405037e8 -> 3f8e5b82", "be920280 419b18c2 -> bc70fbde", "41823e9c c10676ec -> 4003074a", "40fc01e0 40a9689c -> 3f7a9c4a", "416ade10 c15a3b2c -> 40147298", "c12b4626 419bd752 -> bf00a1ec", - "413a29aa c0cd07be -> 4004befe", + "413a29aa c0cd07be -> 4004beff", "c199d0c3 c1866487 -> c0127d6a", - "419e0288 c1425a56 -> 4007d1b2", + "419e0288 c1425a56 -> 4007d1b3", "4144a97c 4083fd0c -> 3f9f9ec3", "4104e2a2 3f327440 -> 3fbe57fd", "c10cd1b9 40378e30 -> bfa0bd4e", @@ -25685,7 +25685,7 @@ "3fc08c60 c177750c -> 4042db49", "c10a43a9 c0be1246 -> c00b121d", "4061f8c0 40e4294c -> 3eeb6b1a", - "c0aa3df6 4165c098 -> beb5a9ce", + "c0aa3df6 4165c098 -> beb5a9cf", "c13c904c c1220f4d -> c011f7c3", "4141fe18 c13691ef -> 4014db0f", "c043e348 40bf5874 -> bef239e5", @@ -32770,6 +32770,268 @@ "c486ccb7 4464268f 42b60000 44088700 42475598 00000000 43258de7 44372289 44df86e2 00000000 43904267 42f00000 c2b40000 40e00000 42b80000 43200000 c2f00000 40e00000 42ba0000 43480000 c3160000 40e00000 42bc0000 43700000 c3340000 40e00000 42be0000 438c0000 c3520000 40e00000 42c00000 43a00000 c3700000 40e00000 42c20000 43b40000 c3870000 40e00000 42c40000 43c80000 c3960000 40e00000 42c60000 43dc0000 c3a50000 40e00000 42c80000 43f00000 c3b40000 40e00000 42ca0000 44020000 c3c30000 40e00000 42cc0000 440c0000 c3d20000 40e00000 42ce0000 44160000 c3e10000 40e00000 42d00000 44200000 c3f00000 40e00000 42d20000 442a0000 c3ff0000 40e00000 42d40000 44340000 c4070000 40e00000 42d60000 443e0000 c40e8000 40e00000 42d80000 44480000 c4160000 40e00000 42da0000 44520000 c41d8000 40e00000 42dc0000 445c0000 c4250000 40e00000 42de0000 44660000 c42c8000 40e00000 42e00000 44700000 c4340000 40e00000 42e20000 447a0000 c43b8000 40e00000 42e40000 44820000 c4430000 40e00000 42e60000 44870000 c44a8000 40e00000 42e80000 448c0000 c4520000 40e00000 42ea0000 44910000 c4598000 40e00000 42ec0000 44960000 c4610000 40e00000 42ee0000 449b0000 c4688000 40e00000 42f00000 44a00000 c4700000 40e00000 42f20000 44a50000 c4778000 40e00000 42f40000 44aa0000 c47f0000 40e00000 42f60000 44af0000 c4834000 40e00000 42f80000 44b40000 c4870000 40e00000 42fa0000 44b90000 c48ac000 40e00000 42fc0000 44be0000 c48e8000 40e00000 42fe0000 44c30000 c4924000 40e00000 43000000 44c80000 c4960000 40e00000 43010000 44cd0000 c499c000 40e00000 43020000 44d20000 c49d8000 40e00000 43030000 44d70000 c4a14000 40e00000 43040000 44dc0000 c4a50000 40e00000 43050000 44e10000 c4a8c000 40e00000 43060000 44e60000 c4ac8000 40e00000 43070000 44eb0000 c4b04000 40e00000 43080000 44f00000 c4b40000 40e00000 43090000 44f50000 c4b7c000 40e00000 430a0000 44fa0000 c4bb8000 40e00000 430b0000 44ff0000 c4bf4000 40e00000 430c0000 45020000 c4c30000 40e00000 430d0000 45048000 c4c6c000 40e00000 430e0000 45070000 c4ca8000 40e00000 430f0000 45098000 c4ce4000 40e00000 43100000 450c0000 c4d20000 40e00000 43110000 450e8000 c4d5c000 40e00000 43120000 45110000 c4d98000 40e00000 43130000 45138000 c4dd4000 40e00000 43140000 45160000 c4e10000 40e00000 43150000 45188000 c4e4c000 40e00000 43160000 451b0000 c4e88000 40e00000 43170000 451d8000 c4ec4000 40e00000 43180000 45200000 c4f00000 40e00000 43190000 45228000 c4f3c000 40e00000 431a0000 45250000 c4f78000 40e00000 431b0000 45278000 c4fb4000 40e00000 431c0000 452a0000 c4ff0000 40e00000 431d0000 452c8000 c5016000 40e00000 431e0000 452f0000 c5034000 40e00000 431f0000 45318000 c5052000 40e00000 43200000 45340000 c5070000 40e00000 43210000 45368000 c508e000 40e00000 43220000 45390000 c50ac000 40e00000 43230000 453b8000 c50ca000 40e00000 43240000 453e0000 c50e8000 40e00000 43250000 45408000 c5106000 40e00000 43260000 45430000 c5124000 40e00000 43270000 45458000 c5142000 40e00000 43280000 45480000 c5160000 40e00000 43290000 454a8000 c517e000 40e00000 432a0000 454d0000 c519c000 40e00000 432b0000 454f8000 c51ba000 40e00000 432c0000 45520000 c51d8000 40e00000 432d0000 45548000 c51f6000 40e00000 432e0000 45570000 c5214000 40e00000 432f0000 45598000 c5232000 40e00000 43300000 455c0000 c5250000 40e00000 43310000 455e8000 c526e000 40e00000 43320000 45610000 c528c000 40e00000 43330000 45638000 c52aa000 40e00000 43340000 45660000 c52c8000 40e00000 43350000 45688000 c52e6000 40e00000 43360000 456b0000 c5304000 40e00000 43370000 456d8000 c5322000 40e00000 43380000 45700000 c5340000 40e00000 43390000 45728000 c535e000 40e00000 433a0000 45750000 c537c000 40e00000 433b0000 45778000 c539a000 40e00000 433c0000 457a0000 c53b8000 40e00000 433d0000 457c8000 c53d6000 40e00000 433e0000 457f0000 c53f4000 40e00000 433f0000 4580c000 c5412000 40e00000 43400000 45820000 c5430000 40e00000 43410000 45834000 c544e000 40e00000 43420000 45848000 c546c000 40e00000 43430000 4585c000 c548a000 40e00000 43440000 45870000 c54a8000 40e00000 43450000 45884000 c54c6000 40e00000 43460000 45898000 c54e4000 40e00000 43470000 458ac000 c5502000 40e00000 43480000 458c0000 c5520000 40e00000 43490000 458d4000 c553e000 40e00000 434a0000 458e8000 c555c000 40e00000 434b0000 458fc000 c557a000 40e00000 434c0000 45910000 c5598000 40e00000 434d0000 45924000 c55b6000 40e00000 434e0000 45938000 c55d4000 40e00000 434f0000 4594c000 c55f2000 40e00000 43500000 45960000 c5610000 40e00000 43510000 45974000 c562e000 40e00000 43520000 45988000 c564c000 40e00000 43530000 4599c000 c566a000 40e00000 43540000 459b0000 c5688000 40e00000 43550000 459c4000 c56a6000 40e00000 43560000 459d8000 c56c4000 40e00000 43570000 459ec000 c56e2000 40e00000 43580000 45a00000 c5700000 40e00000 43590000 00000002 43820000 3f333333 3fcccccd 42f00000 3eb33333 00000000 00000000 3f800000 -> 3ef8c434 3f32636d 3efbcd58 3e549b04", "c4b3e76c 444241a0 42500000 435b9579 4136dbcf 00000000 43945431 43041651 43830dcc 00000000 43652355 c48bf352 44d33444 00000000 434dc873 c3000002 c10833d3 00000000 433550ff c28b6e94 c30f7278 00000000 438d43a6 44a4de09 c4f12ff1 00000000 425a0d22 44d428d3 430976c5 00000000 434b973e 441d5713 44a7fc0b 00000000 438e7c40 c4ab19d7 44f2b987 00000000 41e038cc c455d2d5 c2a36170 00000000 43908b8d c3801d60 c40e138a 00000000 431363cc 43396792 c37f2156 00000000 437ac80c 439f85f6 420c7863 00000000 42150b58 4428e36e 44c2bb96 00000000 43837958 c47c7670 44a88b01 00000000 4294d48d c40641aa c285e8ba 00000000 4232d05c c40ca53f c4a8ca3a 00000000 4378763b 42cfefd3 c306ba40 00000000 430371e3 44b979fd 434ebfb9 00000000 43421a7a 42b44286 43616d19 00000000 43047467 c2892c2a 42ac8e8b 00000000 4332087f c4f373b1 c39604df 00000000 42b3908c c4071e02 c4b04c5b 00000000 4347459e 43fd006f c41a827e 00000000 4208fda6 44c75602 43869ead 00000000 42421b44 4351a83b 440ee820 00000000 42cc9909 c48345c8 449bb4d1 00000000 42125362 c4abe6d8 c37c9d2e 00000000 433a98a6 c43a8ecd c5050f9b 00000000 42b796d8 4488f948 c49dcc59 00000000 43638b9c 4518e99d 43f2fa58 00000000 4271681e 4436363e 450837cb 00000000 437c8686 c49f0216 44b1f01c 00000000 438026fe c4af2be6 c395b304 00000000 43814487 c3f349af c4befb18 00000000 428c07fa 4424afd0 c4330845 00000000 42decd7b 4513cf17 44073fe5 00000000 438a0efc 442d8bbd 450f5844 00000000 434b07a5 c493ef20 449c3dfb 00000000 437f587e c4222d07 c31e43fc 00000000 43128220 c4066f1d c4ea31b9 00000000 4340306c 43e81d81 c3ee2e59 00000000 4330577c 4514ae2d 441a3491 00000000 43869616 439ae709 448ea55a 00000000 43226a3e c4068e80 440626bb 00000000 430d975e c49c9b56 c3ac1805 00000000 42dea520 c4161f98 c5129034 00000000 42da3948 44400c36 c43a07ca 00000000 43826b94 44c6d8dc 43e6e324 00000000 438edae5 4396e0d8 449ca83c 00000000 43643dd5 c35d19fc 4350154a 00000000 430efc77 c485b6e4 c3a3a64d 00000000 4312ff68 c3cdea28 c4e43378 00000000 4385fba4 44224024 c4145936 00000000 435e4c43 43a49d73 42d3e418 00000000 438636f8 43ed8fd2 450d12ed 00000000 4210bc80 c2dcc99b 42c41aba 00000000 4299b2ee c50fdfe9 c44262e4 00000000 42fe5060 c3dac9b9 c50be58c 00000000 42f0366f 44ca1d48 c4ae6032 00000000 4382f138 4475cf34 43adfc47 00000000 420467d2 4383e7ac 44b69e10 00000000 42939fb6 c4a5b2bc 448ad7eb 00000000 41f43fa8 c461b848 c3a71faa 00000000 434a4234 c358c6a6 c4a37e3e 00000000 423c3b16 42ae5790 c28ddcb8 00000000 435f71b1 44586d7a 43a75f50 00000000 431dfe64 43126575 44726ffe 00000000 42e181b4 c3da9fe9 43acb878 00000000 436eefe3 c4efcdc3 c4416fe4 00000000 423c53dc c344a113 c4b46166 00000000 435ffd97 44553a65 c4238580 00000000 430092b5 4499e952 440156a4 00000000 430fbb25 42c9a36d 444f404d 00000000 4369e56c c43b5358 440b6b0e 00000000 41cf9cce c5087fe5 c46ebaa1 00000000 42caf529 c21191e4 c3aa0683 00000000 4344d73b 443ee95e c409dbcb 00000000 41f53bb8 44f6e532 44606df7 00000000 42aa10aa 433460d1 44f3d985 00000000 43582457 c48b83c0 44436f9c 00000000 4350ab77 c4098067 c381cd3a 00000000 41ad0134 c32c4d09 c50a24e7 00000000 4293fef2 44bb391d c47e4d73 00000000 432790ce 44ec7b40 4467a0ac 00000000 43470d71 420e374b 440c07c0 00000000 425deb6d c4911239 443effdb 00000000 4366654f c43619f1 c3b8eb31 00000000 434e068d c2a05b66 c4cc6faf 00000000 4291eb66 44b5dd54 c468003e 00000000 42acbd25 44cd3c28 4457e72d 00000000 433ac26f 41e50db8 444eeade 00000000 431d0e95 c3beb1b5 436b9aef 00000000 435bf745 c4afd8d7 c43f8161 00000000 435bc798 c10e3dc0 c3dc6413 00000000 42e0327b 448376b9 c41d3ced 00000000 439027f4 42ccb7fb 4266a7eb 00000000 42561b63 4107706a 44b7ae4c 00000000 4386c984 c49102da 4427d07c 00000000 43041b2c c48de2f6 c4254afa 00000000 42dc4d73 417fe3ca c4e73dfa 00000000 436e328f 44fdd280 c48e0708 00000000 435a40e7 44dfcd51 4486b7c0 00000000 437af18e c22ffde1 44ee8d5d 00000000 42ebac6a c445a9ae 43d5c9a6 00000000 43543326 c45fbee4 c40b1d1a 00000000 43507e5b 425680ee c4b2d793 00000000 432a871c 45066678 c48c65e4 00000000 438c4680 44501288 44059013 00000000 435e3b80 c2e08f5e 45072ba4 00000000 428609a6 c4a3143d 44246ade 00000000 4395e45b c4556a6b c40d5fe9 00000000 4321ff85 4206eb23 c3fe1841 00000000 42ab0018 43addb6e c3290c04 00000000 4308e930 43dc68f5 43969f8a 00000000 430610e6 c2126c9e 43e25da0 00000000 42ae86ef c4c4feae 4438935d 00000000 42ef05dd c486c228 c43def39 00000000 438f4904 4321a791 c4d3da54 00000000 433ab2f6 44c00026 c42d31f8 00000000 42db619b 44f338d9 44b0b3b2 00000000 42c2bff2 c2dd8512 447bddda 00000000 4313918c c505ea13 44685e96 00000000 4372ce6f 459b0000 c5688000 40e00000 43550000 459c4000 c56a6000 40e00000 43560000 459d8000 c56c4000 40e00000 43570000 459ec000 c56e2000 40e00000 43580000 45a00000 c5700000 40e00000 43590000 0000007b 43820000 3f333333 3fcccccd 42f00000 3eb33333 3f19999a 3f4ccccd 3f800000 -> 3f1796ad 3f2abc83 3f147ad8 3f6031e3" ] + }, + { + "glsl": "float cultmath_fbm(vec3, int, float, float)", + "tolerance": "ulp-bounded", + "cases": [ + "c11a9d90 c04202a0 c20bc826 00000004 40000000 3f000000 -> 3f27d6ca", + "41601e80 4005e0a0 41eba008 00000004 40000000 3f000000 -> be8cf3fd", + "407e0d30 c181cd2c 41cbe660 00000004 40000000 3f000000 -> 3eebda0d", + "41b7f3d4 c129244c c0fdb2f0 00000004 40000000 3f000000 -> bd3ada1f", + "407005a0 4118392c 41a44bb4 00000004 40000000 3f000000 -> beabbce1", + "c1830e64 c2048dab 422a3126 00000004 40000000 3f000000 -> 3e53b796", + "407894c0 c2091ce8 4243e388 00000004 40000000 3f000000 -> beff701d", + "c1f06795 c23c1b2b c2412342 00000004 40000000 3f000000 -> 3ec7b869", + "c1bdbda4 41dc0d48 c22f43c4 00000004 40000000 3f000000 -> bec760f6", + "408126b0 c1ea0445 c1a7655d 00000004 40000000 3f000000 -> 3e0a4e06", + "413dbdcc 422bc160 40f21a68 00000004 40000000 3f000000 -> bea53f12", + "c1484ebc 420439be 416f96b0 00000004 40000000 3f000000 -> 3e72cffa", + "c1ba67c0 408252b0 421a9588 00000004 40000000 3f000000 -> bf451a7c", + "c16b1c64 41a06cd4 c176d898 00000004 40000000 3f000000 -> 3f02099c", + "4120d64c 41de56d4 40b8cd88 00000004 40000000 3f000000 -> 3f2bebc0", + "c1ca675a c230dc20 c22de33d 00000004 40000000 3f000000 -> 3f1cd196", + "4137ed30 4146d32c c21ce93a 00000004 40000000 3f000000 -> 3da3b336", + "c08f7cb0 4226b458 41db68b4 00000004 40000000 3f000000 -> be182486", + "41f4cfe4 c1ece732 c0c027f0 00000004 40000000 3f000000 -> 3daec608", + "c212a4e3 c1446638 41c4aed0 00000004 40000000 3f000000 -> be06a746", + "41ba2790 4247bbfe c213e474 00000004 40000000 3f000000 -> 3f08da39", + "c065a220 c21b758b c060a740 00000004 40000000 3f000000 -> 3f0948cb", + "420a0656 c206ebf6 41d3a918 00000004 40000000 3f000000 -> be0f2d50", + "c231bfd1 c22c5352 414c9ffc 00000004 40000000 3f000000 -> 3d5ad4f0", + "c2386461 c1fb5f35 c08a9a88 00000004 40000000 3f000000 -> bf0307b4", + "416666b8 411e5a8c c1c68d2b 00000004 40000000 3f000000 -> bf3c2a7e", + "c081e798 c241ab24 41adc588 00000004 40000000 3f000000 -> 3ecf6bca", + "42469f7a 422a298a 41052448 00000004 40000000 3f000000 -> bd9e0e93", + "c1fd92e8 c206a0f6 c242f2f6 00000004 40000000 3f000000 -> bea9dec8", + "41f11de8 40dc22f8 414ab55c 00000004 40000000 3f000000 -> bd8bc474", + "c1e82aab c2128efd c2069c1b 00000004 40000000 3f000000 -> be7c0319", + "c20fc1e0 41409478 41a0f4d8 00000004 40000000 3f000000 -> 3da2f1d0", + "c1e3a366 c211704c 418541ec 00000004 40000000 3f000000 -> 3f3968b5", + "c222dbdb c11ce808 421e0fd6 00000004 40000000 3f000000 -> 3eb06c7c", + "c19f6f92 40bdd8e0 40b040e8 00000004 40000000 3f000000 -> 3d4ea228", + "c0011390 c1062cd4 41b8c7e4 00000004 40000000 3f000000 -> bed7e250", + "c191f0aa c20731bd 4127d710 00000004 40000000 3f000000 -> 3e0d1a30", + "c1f97cd1 418b3020 c15db9a8 00000004 40000000 3f000000 -> 3dfd58fc", + "c23c8b5e 41bce8a0 c22a6d8e 00000004 40000000 3f000000 -> 3c465804", + "409693d0 c1af215b 42332b6c 00000004 40000000 3f000000 -> bee9b32d", + "c098bbf0 c236889e 41163eac 00000004 40000000 3f000000 -> 3f0bd913", + "c210d8cb 420a5584 422e3bac 00000004 40000000 3f000000 -> bebb6492", + "c063be60 421f5d7e 40d15a40 00000004 40000000 3f000000 -> 3ebd15a8", + "41cc6488 c0e4a4f8 c06f9100 00000004 40000000 3f000000 -> 3db49ff4", + "410861d0 c155845c 41363b78 00000004 40000000 3f000000 -> bdcb6293", + "4200d2ee 419cae84 c1564644 00000004 40000000 3f000000 -> 3edb892a", + "c23cbf0a 41a28f8c 41c5d480 00000004 40000000 3f000000 -> bf2d47fb", + "c1aeadcf bfcf1700 c1152790 00000004 40000000 3f000000 -> be5972ba", + "c23f486c c23f56ed c0813868 00000004 40000000 3f000000 -> 3ee6dc4a", + "41f1a4a0 c21b3682 4219b0ce 00000004 40000000 3f000000 -> bf0eadc6", + "414b9fe8 4186b7a4 420e2062 00000004 40000000 3f000000 -> 3e2980bf", + "41aeeb18 4160ee88 c162c594 00000004 40000000 3f000000 -> bee70d01", + "c19effaa c206defe 41aacb30 00000004 40000000 3f000000 -> 3de761d6", + "413f31c0 c241d553 3fe2e9a0 00000004 40000000 3f000000 -> bde2b38a", + "c205c755 40c6ab38 41bac5c0 00000004 40000000 3f000000 -> 3ed8ad73", + "c20f112c 4124a490 c19a0db2 00000004 40000000 3f000000 -> bdc30b1c", + "41c60570 c1eabc98 c237e2f2 00000004 40000000 3f000000 -> bf4faa5b", + "41a64804 3ff230a0 40f93c68 00000004 40000000 3f000000 -> bee98cca", + "c1ef7da7 c203c097 40bf80d8 00000004 40000000 3f000000 -> 3db61265", + "c1fa4ce3 c219905e 4201ac72 00000004 40000000 3f000000 -> bf387f6a", + "c019d480 4181e398 41e52800 00000004 40000000 3f000000 -> be033562", + "4190f4f4 c214b5b7 41d01f1c 00000004 40000000 3f000000 -> 3d5e261c", + "412b9a38 4212a2e8 41b4c68c 00000004 40000000 3f000000 -> 3f336c18", + "c1c37f7b 40052c30 405363f0 00000004 40000000 3f000000 -> 3e9fce4c", + "41742360 c1122dec 41963a2c 00000004 40000000 3f000000 -> 3d369949", + "c1d85a1d c2198f93 4228b1e0 00000004 40000000 3f000000 -> 3e151611", + "418aa674 4217c8c0 c1020040 00000004 40000000 3f000000 -> 3d9e5382", + "c20b2034 c232306a 422227ca 00000004 40000000 3f000000 -> 3d21dba6", + "420993c0 4227c3f8 c20c35b2 00000004 40000000 3f000000 -> 3e254db8", + "c1b20e56 3fe68be0 c0403c60 00000004 40000000 3f000000 -> 3e00593c", + "41eebd00 c21a5963 c2354e9f 00000004 40000000 3f000000 -> bf023291", + "421bb928 c20e9648 c16b1c78 00000004 40000000 3f000000 -> bf0b8dcb", + "41b90698 bfc839c0 c0d3a708 00000004 40000000 3f000000 -> bf1723c8", + "423d5354 40608460 41bd0c74 00000004 40000000 3f000000 -> bcc26220", + "41025788 bf4f6280 41949de4 00000004 40000000 3f000000 -> beed4e99", + "3f39b3c0 c231e4d4 c21be301 00000004 40000000 3f000000 -> be0bb9b2", + "421c0a76 423c6e3a c2323104 00000004 40000000 3f000000 -> bf40bdcd", + "415cf8ec 3fb0caa0 c1d2b23c 00000004 40000000 3f000000 -> be851f93", + "c1174dfc c18cfa28 412c88d4 00000004 40000000 3f000000 -> 3f111826", + "42186c38 4206e6ba c1e8f35c 00000004 40000000 3f000000 -> bec21f9a", + "41311500 c188248e c17245d8 00000004 40000000 3f000000 -> 3d6acd72", + "c1c331e9 c088f1f0 c1154f68 00000004 40000000 3f000000 -> 3f32b2ec", + "bfaf6440 41d29f60 c1bbea67 00000004 40000000 3f000000 -> 3d96329a", + "c1843796 be305a00 4152c8e8 00000004 40000000 3f000000 -> bdce91e5", + "bf9b27e0 419fffcc c178fe1c 00000004 40000000 3f000000 -> 3e94636d", + "4191f36c 40e24f50 40c86908 00000004 40000000 3f000000 -> beb06eb9", + "c1e04e4e c182a61e 4211a8cc 00000004 40000000 3f000000 -> 3e4f51ee", + "c23852b1 c1344684 40963120 00000004 40000000 3f000000 -> 3f06fbc7", + "c1074b08 c207dfba 41208124 00000004 40000000 3f000000 -> 3f44398c", + "41f81500 bfce6b20 41ffcd98 00000004 40000000 3f000000 -> 3db207ed", + "41c42d58 420c1714 416b5de8 00000004 40000000 3f000000 -> be56c8b1", + "c1dbf666 c15bc7b4 c1ebcae6 00000004 40000000 3f000000 -> be987233", + "c133a140 c18ba254 c23a1f4c 00000004 40000000 3f000000 -> be6063b7", + "c1b0ba6b c23f9e0f c1a66906 00000004 40000000 3f000000 -> 3e71480d", + "420a1232 40b13200 c02e16b0 00000004 40000000 3f000000 -> bda67ee4", + "c0f719f8 c20be886 41fb0cd8 00000004 40000000 3f000000 -> be9018c6", + "421ce668 41b26594 41ca7208 00000004 40000000 3f000000 -> 3f33ea18", + "c235eaec 418126bc 3d672000 00000004 40000000 3f000000 -> bea45437", + "c17889e4 40e4bf88 4230ff5a 00000004 40000000 3f000000 -> beb68251", + "41f150cc 420839ce c1a27d07 00000004 40000000 3f000000 -> bcbd7004", + "41f517bc 418cf4bc c1b079ee 00000004 40000000 3f000000 -> bb24d74c", + "c0aedff8 410f3624 416ce240 00000004 40000000 3f000000 -> 3f0d6ce0", + "4241dac2 c1bdbc18 c1821c58 00000004 40000000 3f000000 -> bea85f48", + "c2105a14 c1a43bf4 c1cbc9d9 00000004 40000000 3f000000 -> 3ebe4d06", + "4032c6d0 42303610 c19369ff 00000004 40000000 3f000000 -> 3ee7e743", + "40e6ea70 c1f4c9c7 4204c81e 00000004 40000000 3f000000 -> be98d471", + "c22a5870 4245107c c243f735 00000004 40000000 3f000000 -> bed2576b", + "41e533b8 42272418 41d0b3b4 00000004 40000000 3f000000 -> 3e0d2bde", + "c22d5237 41a00334 c1f8f891 00000004 40000000 3f000000 -> 3e1a4a1f", + "c20d624e 42182746 41e8ec44 00000004 40000000 3f000000 -> bd73af1a", + "c1bdc99a 4109bd28 bfc15ee0 00000004 40000000 3f000000 -> bdd4a46b", + "41be3e70 c02e9130 c17861bc 00000004 40000000 3f000000 -> be9a49dc", + "c242f78d c1204738 423a58b8 00000004 40000000 3f000000 -> bd8f7f9e", + "4201e604 c0c5f000 421af586 00000004 40000000 3f000000 -> bd939ee0", + "c016b680 41ca80f8 c0e579d8 00000004 40000000 3f000000 -> be949954", + "3f477c00 3fdd1520 41b0ba9c 00000004 40000000 3f000000 -> 3f61641f", + "c1fc2271 41da0074 c1440cb0 00000004 40000000 3f000000 -> 3d22d4bd", + "c21bc8c4 41b601ac 420b2952 00000004 40000000 3f000000 -> bea1ff75", + "c1aa8e9f c2400dfe 41ceac90 00000004 40000000 3f000000 -> bf0ee9ae", + "3fed25c0 c1422724 421bcbf0 00000004 40000000 3f000000 -> 3e7b8260", + "c0825938 42073d10 c13c1548 00000004 40000000 3f000000 -> 3e8108b9", + "4093dd90 42168aba 41a6e578 00000004 40000000 3f000000 -> bf70dcc5", + "41d04c14 41e81a68 c04e0de0 00000004 40000000 3f000000 -> 3f169ba9", + "423c6370 40bea6d8 41eb59d4 00000004 40000000 3f000000 -> be27a3b6", + "42126f66 c1c87ce9 40ae73e0 00000004 40000000 3f000000 -> bdecf67a", + "c216ecbb c197f579 c2061c65 00000004 40000000 3f000000 -> bec0f5a1", + "c185edd2 40bc7ec8 c1fdce1e 00000004 40000000 3f000000 -> beaeea8a", + "c04d9980 4238aeec c21cd8f3 00000004 40000000 3f000000 -> bf4c5f9d", + "c10a1ac8 c20b1c08 420f6e74 00000004 40000000 3f000000 -> bca013bc", + "415b2edc c09ccbc8 c096d8b0 00000004 40000000 3f000000 -> be5536d7", + "410a4524 bf182e80 c23f8806 00000004 40000000 3f000000 -> 3ee6c4f3", + "c2297336 c1573b54 412013c4 00000004 40000000 3f000000 -> 3c3ab7a0", + "3efd6c00 422c18e8 4216b5c2 00000004 40000000 3f000000 -> beeca0ab", + "41afbc10 41c5efcc 41b5b6e8 00000004 40000000 3f000000 -> bf364b64", + "c1c583a7 c1e4e94f c1e5a945 00000004 40000000 3f000000 -> bf34f4f8", + "41053fa4 c1cc7056 c00c0b50 00000004 40000000 3f000000 -> bdda9df2", + "c1a54a53 c2065a94 41a7d97c 00000004 40000000 3f000000 -> 3e6ae330", + "4115cab4 c1fb3fd3 41ffccbc 00000004 40000000 3f000000 -> be2050ce", + "41a565fc 42448e70 42168e26 00000004 40000000 3f000000 -> bd95b845", + "c1b458be c212fd9c 41b34d84 00000004 40000000 3f000000 -> bde52094", + "420c044a c216a5ac c180b2a6 00000004 40000000 3f000000 -> 3ea3b257", + "c24205c8 c138b768 c22dca6a 00000004 40000000 3f000000 -> bf026e60", + "41da69e0 41e7c53c 42199060 00000004 40000000 3f000000 -> 3e296457", + "4235c98a 413c61b4 c1404e8c 00000004 40000000 3f000000 -> bd267211", + "c1a9a44f 4134ac38 41f92fec 00000004 40000000 3f000000 -> bd77a9b6", + "c08e1418 c1e42f89 41c64724 00000004 40000000 3f000000 -> 3f071a60", + "421dfbb0 42042964 42231c22 00000004 40000000 3f000000 -> be057b84", + "c13f435c c17a3c80 c1aa7dc8 00000004 40000000 3f000000 -> bece20fe", + "41c27058 42451e9c c19981a2 00000004 40000000 3f000000 -> be79305d", + "c1eedcc7 c15098d0 c1497518 00000004 40000000 3f000000 -> be9e1b90", + "41b2ed98 c1d7b191 41ee2d04 00000004 40000000 3f000000 -> 3d44b899", + "c20af100 4213d9c0 41467648 00000004 40000000 3f000000 -> 3ec0aa40", + "c1332ce4 c1d17816 4203b932 00000004 40000000 3f000000 -> be11a895", + "c20d0a38 41f835f0 c090d638 00000004 40000000 3f000000 -> be1498a4", + "4116bbac c180dd68 409467f0 00000004 40000000 3f000000 -> bf0fd158", + "c187ff3c c19b7655 40e9a840 00000004 40000000 3f000000 -> 3e89df12", + "c244b197 c1c714ff 41dd4c6c 00000004 40000000 3f000000 -> 3ead3f11", + "c214956d c140a03c c19e4e02 00000004 40000000 3f000000 -> 3ef4d00f", + "41fd1540 c042ae00 41dfd2e8 00000004 40000000 3f000000 -> 3d973e78", + "c2331a6e c1b67be9 c12d31d4 00000004 40000000 3f000000 -> be750957", + "41cdeccc 40e51a98 c0ffb978 00000004 40000000 3f000000 -> be253870", + "3f7b69c0 c1d75a82 c1343b2c 00000004 40000000 3f000000 -> 3dbf25d2", + "41035764 c211e128 41c2a2a0 00000004 40000000 3f000000 -> 3f151eee", + "c1fa0b38 c22cf74a 423ea448 00000004 40000000 3f000000 -> bd6e638c", + "42276a60 41c60bd0 c23ff195 00000004 40000000 3f000000 -> bf359aaa", + "c09648b8 41e5007c c246206c 00000004 40000000 3f000000 -> 3ec9a87b", + "41c06838 c10b20d4 4195b38c 00000004 40000000 3f000000 -> be8ff22f", + "41bc1450 c1f57998 c2189bb5 00000004 40000000 3f000000 -> 3e28b2f1", + "411bf210 411830e4 420c4f46 00000004 40000000 3f000000 -> be20e42c", + "bee13d80 c182f740 c11fed84 00000004 40000000 3f000000 -> bf6b6b32", + "4209b41c c1836194 423a81ea 00000004 40000000 3f000000 -> 3eebe724", + "c0c7d2c8 c1300278 c1d110b4 00000004 40000000 3f000000 -> 3edf09dc", + "c23a2398 c2263ebc c21cc173 00000004 40000000 3f000000 -> 3f347bc5", + "c2086436 41c65514 c203da03 00000004 40000000 3f000000 -> be4a016a", + "4203e3b8 42005406 c1fd266b 00000004 40000000 3f000000 -> 3e92d85b", + "41f003dc c1e7ff9b 41534824 00000004 40000000 3f000000 -> bf51dab7", + "c1ae6ad8 c15ab124 4192a9c8 00000004 40000000 3f000000 -> 3ea4064b", + "41dc13c0 c1969d16 420f8a40 00000004 40000000 3f000000 -> 3f0909f0", + "41a3b388 c23f13c1 c1427f80 00000004 40000000 3f000000 -> 3e6ede51", + "c19eb6f5 4224f120 41591a18 00000004 40000000 3f000000 -> 3e6ab4d3", + "406a1ef0 c22567ab 41ef34f0 00000004 40000000 3f000000 -> bf055e0e", + "c17acd40 c17ae6e4 41b97304 00000004 40000000 3f000000 -> be66940a", + "c243dda3 bff368e0 c163e5e4 00000004 40000000 3f000000 -> bd501bea", + "41e12d8c c10295fc 41a17df0 00000004 40000000 3f000000 -> 3dd3be72", + "421ea106 4102614c 41841a84 00000004 40000000 3f000000 -> bf09bbcc", + "3fd67940 42222670 c14c4344 00000004 40000000 3f000000 -> 3ee83191", + "422df782 41edf52c c137cfe8 00000004 40000000 3f000000 -> 3d22e603", + "c1e10584 c1e51a20 423d30aa 00000004 40000000 3f000000 -> 3f0369ee", + "41ad5f78 c22c55c3 c23e623f 00000004 40000000 3f000000 -> bd8b828e", + "c21d0856 41ba57c4 c153b374 00000004 40000000 3f000000 -> bf83804f", + "42101786 41ba6fc4 c2032fdd 00000004 40000000 3f000000 -> 3e0487d8", + "c0307f90 4143e76c 41812468 00000004 40000000 3f000000 -> bf30ffd4", + "c14dd1ec bfad1f00 c00f2420 00000004 40000000 3f000000 -> bdccd9c1", + "c09a65b8 41e7bf24 41b736f4 00000004 40000000 3f000000 -> 3f093490", + "c1b468fb 3d4f3800 4231f934 00000004 40000000 3f000000 -> 3c21555a", + "424095ea 421768d8 41b83244 00000004 40000000 3f000000 -> bece4789", + "c1f50604 c1f9b40a c2193a31 00000004 40000000 3f000000 -> be4a50c7", + "c2458f10 c1554bf0 c21a0974 00000004 40000000 3f000000 -> bf1acbb9", + "c1c78b00 c191b69e 42152566 00000004 40000000 3f000000 -> be957456", + "420269ce 414a73d0 c1b4c7ed 00000004 40000000 3f000000 -> 3e697510", + "41a63780 42212ab4 41c671ac 00000004 40000000 3f000000 -> 3f139976", + "4243f362 42287f3e 4194453c 00000004 40000000 3f000000 -> 3c50a516", + "403eed70 c0f2b800 42379e78 00000004 40000000 3f000000 -> beba9818", + "c24684f1 c20dd7bc c101c264 00000004 40000000 3f000000 -> 3d3cca45", + "421de172 bfd77900 c244e4fc 00000004 40000000 3f000000 -> 3f050db9", + "4179c230 4231b1ba 41aa7e40 00000004 40000000 3f000000 -> 3e3e0e04", + "c23cc88c 41bc33a8 c1f77d37 00000004 40000000 3f000000 -> 3d7074f3", + "c1a4f6c3 42257aac 40902f38 00000004 40000000 3f000000 -> 3cded1fb", + "c1c76558 420da696 c155d488 00000004 40000000 3f000000 -> bdb2d8a1", + "c2312669 c1de84f2 c19c55ac 00000004 40000000 3f000000 -> bf733e95", + "41e6d99c 40910dc0 420ffa14 00000004 40000000 3f000000 -> be87cefb", + "c1ed1c98 41c32f10 421ab4de 00000004 40000000 3f000000 -> beac3f5c", + "424062a4 c1ac4fc1 40fda488 00000004 40000000 3f000000 -> bed84bad", + "c1c052d0 c09ac768 c0920138 00000004 40000000 3f000000 -> 3e8a6d70", + "41d8f554 c1f7fc22 c2370249 00000004 40000000 3f000000 -> 3eb1ddd1", + "419e6cd0 c21b7082 421968ce 00000004 40000000 3f000000 -> be530987", + "c21d2479 411727cc c14a3428 00000004 40000000 3f000000 -> 3dd46038", + "c20819bc 41ee64b4 421c8320 00000004 40000000 3f000000 -> bdbaa7c4", + "c226a55b c109a378 4243b008 00000004 40000000 3f000000 -> 3da8d91f", + "c1ed9a23 41bf4c20 c22d2758 00000004 40000000 3f000000 -> be4a641a", + "c190d081 c02eac10 c1ee290f 00000004 40000000 3f000000 -> 3e49c3d4", + "41772540 c1e3e37f 41201a34 00000004 40000000 3f000000 -> be5c48b4", + "40bcaa98 4198df7c 41bf595c 00000004 40000000 3f000000 -> 3f1b99b9", + "c21799da 418c1bd0 417f6670 00000004 40000000 3f000000 -> bd1b2a24", + "c2127570 41d6c1b8 c1ad1a80 00000004 40000000 3f000000 -> 3d032504", + "41bd0318 40109f50 41b2f178 00000004 40000000 3f000000 -> be738350", + "3e841880 40a8b758 41c22e30 00000004 40000000 3f000000 -> be993b38", + "bfdbbdc0 4233fe10 414bce50 00000004 40000000 3f000000 -> be35bd5c", + "422c6234 414e1a28 41c5deb8 00000004 40000000 3f000000 -> 3eaa7016", + "423b76f4 c217e8f1 c187ff32 00000004 40000000 3f000000 -> 3ec9b4b3", + "421f04d6 41de5f6c 40919080 00000004 40000000 3f000000 -> be522d95", + "3f9b7d20 42303ed8 423f91d4 00000004 40000000 3f000000 -> beed15a0", + "c1c65740 c2194ea5 423df3ae 00000004 40000000 3f000000 -> be9b386d", + "c0b846b8 c2105eea c0ff01f8 00000004 40000000 3f000000 -> be6e4c9a", + "c20e43e2 42427560 4227bc0c 00000004 40000000 3f000000 -> 3eb83eb6", + "41ab32b4 c23da44d c23c2e83 00000004 40000000 3f000000 -> bf1c83e6", + "412c4184 c1749b9c 421c8d2c 00000004 40000000 3f000000 -> be315e50", + "c1bb9168 41a0557c c1fae1b8 00000004 40000000 3f000000 -> be39850e", + "c18c7cde 420675ae 401172f0 00000004 40000000 3f000000 -> bec5ccdb", + "40efbf28 41b2ce34 410a1ed8 00000004 40000000 3f000000 -> bf1e2c8b", + "420d1730 41107978 40e2c578 00000004 40000000 3f000000 -> 3eb26d1a", + "c1114ee0 c1dd3d62 421ede34 00000004 40000000 3f000000 -> 3db35cba", + "c21a5874 4142baa4 42032204 00000004 40000000 3f000000 -> bcff40fb", + "c19c3e28 bfca5a80 c1169d98 00000004 40000000 3f000000 -> bf81fcc7", + "41c70a18 c22feef8 c10a28ac 00000004 40000000 3f000000 -> bea49aff", + "c18e1152 c181341a 423988ae 00000004 40000000 3f000000 -> 3e720a62", + "41a66f10 c1e26e4d 4124ab60 00000004 40000000 3f000000 -> 3e3bbee8", + "41ae3bc0 c15e65b4 41da7bec 00000004 40000000 3f000000 -> 3e0672ef", + "c0c46630 4153362c c228fb08 00000004 40000000 3f000000 -> bf217d87", + "c1617454 c1f9cb51 c21e36d6 00000004 40000000 3f000000 -> be923997", + "c08c2ae0 418db8f4 c12ad700 00000004 40000000 3f000000 -> bef08fdd", + "c1325020 410f7fe4 409c15b8 00000004 40000000 3f000000 -> be423c5a", + "420bc714 41bc1fb0 41d22824 00000004 40000000 3f000000 -> 3e0456ea", + "c23f2228 411fc738 c1194bd4 00000004 40000000 3f000000 -> 3b981998", + "c1eea110 c19da117 42112bee 00000004 40000000 3f000000 -> beafb6e7", + "bfb96dc0 3fd647a0 416066d8 00000004 40000000 3f000000 -> be699b27" + ] } ] } diff --git a/packages/cultmath/tools/phacelle-lipschitz/Program.cs b/packages/cultmath/tools/phacelle-lipschitz/Program.cs new file mode 100644 index 00000000..c149f1d6 --- /dev/null +++ b/packages/cultmath/tools/phacelle-lipschitz/Program.cs @@ -0,0 +1,92 @@ +// Measures the Lipschitz constant of math.phacelle's (cosine, sine) field, the number docs/design.md quotes and +// PhacelleTests.GradientNormStaysUnderTheDocumentedLipschitzEnvelope pins. +// dotnet run -c Release --project packages/cultmath/tools/phacelle-lipschitz -- +// e.g. ... -- 4000000 0,0.5,0.75,0.9 0.25,0.5,1,1.5,2,4,8,12.5,25 +// Columns: sampledMax (random p), climbedMax (hill-climbed from the 256 best samples; the number to quote), secantMax +// (value differences around the climbed argmax, the check that the analytic gradient is the field's slope), +// scalarMax (the larger of |grad cosine|, |grad sine| over the samples), p99.99 (the typical tail), and climbed*(1-n)/|side|. +using System; +using System.Linq; +using System.Threading.Tasks; +using CultMath; + +// Lipschitz bound of math.phacelle's (cosine, sine) field: sup over p of the operator norm of its 2x3 Jacobian, +// found by (1) random sampling of the exact analytic gradient, (2) hill-climbing from the top samples over +// (p, off, side direction), (3) a secant check on the VALUES (|f(p+d) - f(p)| / |d|) so the gradient itself is not trusted. +static double Op(float3 p, float3 side, float off, float n, out double comp) +{ + var r = math.phacelle(p, side, off, n); + double a = r.cosine.x*r.cosine.x + r.cosine.y*r.cosine.y + r.cosine.z*r.cosine.z; + double d = r.sine.x*r.sine.x + r.sine.y*r.sine.y + r.sine.z*r.sine.z; + double b = r.cosine.x*r.sine.x + r.cosine.y*r.sine.y + r.cosine.z*r.sine.z; + double tr = a + d, det = a*d - b*b; + comp = Math.Sqrt(Math.Max(a, d)); + var op = Math.Sqrt(tr/2 + Math.Sqrt(Math.Max(0, tr*tr/4 - det))); + return double.IsFinite(op) ? op : 0; +} +static float3 Dir(double u, double th, double len) { var s = Math.Sqrt(Math.Max(0, 1-u*u)); return new float3((float)(s*Math.Cos(th)*len), (float)(s*Math.Sin(th)*len), (float)(u*len)); } + +float[]? norms = null, sides = null; +try { norms = args.Length == 3 ? args[1].Split(',').Select(float.Parse).ToArray() : null; sides = args.Length == 3 ? args[2].Split(',').Select(float.Parse).ToArray() : null; } +catch (FormatException) { } +if (args.Length != 3 || !long.TryParse(args[0], out var N) || N <= 0 || norms is null || sides is null) +{ + Console.Error.WriteLine("usage: phacelle-lipschitz "); + Console.Error.WriteLine(" e.g. phacelle-lipschitz 4000000 0,0.5,0.75,0.9 0.25,0.5,1,1.5,2,4,8,12.5,25"); + return 2; +} +Console.WriteLine("n\t|side|\tN\tsampledMax\tclimbedMax\tsecantMax\tscalarMax(cos|sin)\tp99.99\tclimbed*(1-n)/|side|"); +foreach (var n in norms) foreach (var sl in sides) +{ + int T = Environment.ProcessorCount; + var tops = new (double v, float3 p, double u, double th, float off)[T][]; + var allv = new double[T][]; var scal = new double[T]; + Parallel.For(0, T, t => + { + var rng = new System.Random(unchecked(99991 * t + (int)(n * 1000) * 131 + (int)(sl * 100))); + var top = new (double v, float3 p, double u, double th, float off)[16]; + var list = new double[N / T]; + double sc = 0; + for (long i = 0; i < N / T; i++) + { + var p = new float3((float)(rng.NextDouble()*64-32), (float)(rng.NextDouble()*64-32), (float)(rng.NextDouble()*64-32)); + double u = rng.NextDouble()*2-1, th = rng.NextDouble()*Math.PI*2; float off = (float)rng.NextDouble(); + var v = Op(p, Dir(u, th, sl), off, n, out var c); + list[i] = v; if (c > sc) sc = c; + int m = 0; for (int k = 1; k < 16; k++) if (top[k].v < top[m].v) m = k; + if (v > top[m].v) top[m] = (v, p, u, th, off); + } + tops[t] = top; allv[t] = list; scal[t] = sc; + }); + var all = allv.SelectMany(x => x).ToArray(); Array.Sort(all); + double sampled = all[^1], p9999 = all[(int)(all.Length * 0.9999)]; + // hill-climb the best 16*T by random local search + var seeds = tops.SelectMany(x => x).OrderByDescending(x => x.v).Take(256).ToArray(); + var climbed = new (double v, float3 p, double u, double th, float off)[seeds.Length]; + Parallel.For(0, seeds.Length, s => + { + var rng = new System.Random(s + 17); + var cur = seeds[s]; double step = 0.05; + for (int it = 0; it < 10000; it++) + { + var q = new float3(cur.p.x + (float)((rng.NextDouble()-.5)*step), cur.p.y + (float)((rng.NextDouble()-.5)*step), cur.p.z + (float)((rng.NextDouble()-.5)*step)); + var u = Math.Clamp(cur.u + (rng.NextDouble()-.5)*step, -1, 1); var th = cur.th + (rng.NextDouble()-.5)*step; var off = cur.off + (float)((rng.NextDouble()-.5)*step); + var v = Op(q, Dir(u, th, sl), off, n, out _); + if (v > cur.v) cur = (v, q, u, th, off); else if (it % 1000 == 999) step *= 0.5; + } + climbed[s] = cur; + }); + var best = climbed.OrderByDescending(x => x.v).First(); + // secant check around the climbed argmax: values only, tiny displacements in random directions + double secant = 0; var sr = new System.Random(5); + var side0 = Dir(best.u, best.th, sl); + for (int i = 0; i < 20000; i++) + { + double e = Math.Pow(10, -2 - 2*sr.NextDouble()); var d = Dir(sr.NextDouble()*2-1, sr.NextDouble()*6.2832, e); + var a = math.phacelle(best.p, side0, best.off, n); var b = math.phacelle(best.p + d, side0, best.off, n); + double dc = b.cosine.w - a.cosine.w, ds = b.sine.w - a.sine.w; var dl = Math.Sqrt((double)d.x*d.x + (double)d.y*d.y + (double)d.z*d.z); + secant = Math.Max(secant, Math.Sqrt(dc*dc + ds*ds) / dl); + } + Console.WriteLine($"{n}\t{sl}\t{N}\t{sampled:F3}\t{best.v:F3}\t{secant:F3}\t{scal.Max():F3}\t{p9999:F3}\t{best.v*(1-n)/sl:F3}"); +} +return 0; diff --git a/packages/cultmath/tools/phacelle-lipschitz/phacelle-lipschitz.csproj b/packages/cultmath/tools/phacelle-lipschitz/phacelle-lipschitz.csproj new file mode 100644 index 00000000..3b8629ae --- /dev/null +++ b/packages/cultmath/tools/phacelle-lipschitz/phacelle-lipschitz.csproj @@ -0,0 +1,4 @@ + + Exenet10.0enabletruetruefalse + + diff --git a/packages/cultmath/unity/org.gamecult.cultmath/CHANGELOG.md b/packages/cultmath/unity/org.gamecult.cultmath/CHANGELOG.md index dfb84a2d..7edfa1b2 100644 --- a/packages/cultmath/unity/org.gamecult.cultmath/CHANGELOG.md +++ b/packages/cultmath/unity/org.gamecult.cultmath/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this package are documented in this file. Earlier releases (0.2.0-0.2.3) predate this package's changelog and are not backfilled here; see `docs/semver-policy.md` for why. +## [Unreleased] + +### Added + +- `math.fbm(float3 p, int octaves, float lacunarity, float gain)` and `math.fbm(float3 p)` (four octaves, + lacunarity 2, gain 0.5): the value-only octave sum of `snoise`, the cost of `fbm_grad` without the gradient. + The shaders carry `cultmath_fbm` in HLSL and GLSL; octaves clamp to [0, 16] as `fbm_grad`'s do. + ## [0.5.0] ### Breaking diff --git a/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl b/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl index d3eea396..fc9f7a70 100644 --- a/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl +++ b/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl @@ -342,6 +342,26 @@ float4 cultmath_fbm_grad(float3 p, int octaves, float lacunarity, float gain) return float4(gradient, value); } +// Value-only octave sum of cultmath_snoise; see the C# math.fbm comment. The one-argument form is four octaves, +// lacunarity 2, gain 0.5. +float cultmath_fbm(float3 p, int octaves, float lacunarity, float gain) +{ + octaves = clamp(octaves, 0, 16); + float amplitude = 1.0; + float frequency = 1.0; + float value = 0.0; + for (int i = 0; i < octaves; i++) + { + value += amplitude * cultmath_snoise(p * frequency); + frequency *= lacunarity; + amplitude *= gain; + } + + return value; +} + +float cultmath_fbm(float3 value) { return cultmath_fbm(value, 4, 2.0, 0.5); } + // Ridged multifractal noise (Musgrave, Texturing and Modeling, ch. 16); see the C# math.ridged_grad // comment for the fold/sign derivation, the deliberate crease at n = 0, and why octaves is clamped. float4 cultmath_ridged_grad(float3 p, int octaves, float lacunarity, float gain)