diff --git a/packages/cultmath/shaders/CultMath.Cycles.glsl b/packages/cultmath/shaders/CultMath.Cycles.glsl index d640762f..67639b07 100644 --- a/packages/cultmath/shaders/CultMath.Cycles.glsl +++ b/packages/cultmath/shaders/CultMath.Cycles.glsl @@ -42,7 +42,8 @@ float cultmath_cycles_power(float a, float b) if (a < 0.0) { float magnitude = pow(-a, b); - return b - 2.0 * floor(0.5 * b) != 0.0 ? -magnitude : magnitude; + // Odd exactly when the remainder is 1: an infinite exponent leaves NaN here and is even, as powf(a, +-inf) is never negative. + return b - 2.0 * floor(0.5 * b) == 1.0 ? -magnitude : magnitude; } return pow(a, b); } diff --git a/packages/cultmath/tests/CultMath.Tests/fixtures/cycles-oracle/infinite.json b/packages/cultmath/tests/CultMath.Tests/fixtures/cycles-oracle/infinite.json new file mode 100644 index 00000000..fef190a9 --- /dev/null +++ b/packages/cultmath/tests/CultMath.Tests/fixtures/cycles-oracle/infinite.json @@ -0,0 +1,75 @@ +{ + "oracle": "tools/cycles-oracle/oracle.py (Blender 5.2.2 LTS, build d13f752e3b9c, Cycles CPU, 1 sample, Emit bake, float Non-Color images)", + "blender": "5.2.2 LTS", + "build_hash": "d13f752e3b9c", + "platform": "Linux", + "encoding": "each case is 'operands -> results', every scalar a float32 bit pattern in hex, colours flattened as r g b", + "family": "infinite", + "functions": [ + { + "function": "cycles_power", + "node": "ShaderNodeMath POWER", + "cases": [ + "bf800000 inf -> 3f800000", + "bf800000 -inf -> 3f800000", + "c0000000 inf -> inf", + "c0000000 -inf -> 00000000", + "bf000000 inf -> 00000000", + "bf000000 -inf -> inf", + "80000000 inf -> 00000000", + "80000000 -inf -> 00000000", + "3f000000 inf -> 00000000", + "3f000000 -inf -> inf", + "40000000 inf -> inf", + "40000000 -inf -> 00000000", + "3f800000 inf -> 3f800000", + "00000000 inf -> 00000000", + "00000000 -inf -> 00000000", + "inf 40400000 -> inf", + "-inf 40400000 -> -inf", + "-inf 40000000 -> inf", + "inf bf800000 -> 00000000", + "-inf bf800000 -> 00000000", + "-inf inf -> inf", + "inf inf -> inf" + ] + }, + { + "function": "cycles_modulo", + "node": "ShaderNodeMath MODULO", + "cases": [ + "inf 3f800000 -> nan", + "-inf 3f800000 -> nan", + "inf 40400000 -> nan", + "-inf 40400000 -> nan", + "inf 3dcccccd -> nan", + "-inf 3dcccccd -> nan", + "inf c0000000 -> nan", + "40a00000 inf -> 40a00000", + "c0a00000 inf -> c0a00000", + "40a00000 -inf -> 40a00000", + "inf inf -> nan", + "-inf inf -> nan", + "00000000 inf -> 00000000", + "inf 00000000 -> 00000000" + ] + }, + { + "function": "cycles_map_range_smoothstep", + "node": "ShaderNodeMapRange SMOOTHSTEP", + "cases": [ + "-inf -inf 3f800000 40000000 40400000 -> nan", + "-inf 3f800000 -inf 40000000 40400000 -> nan", + "-inf 3f800000 40a00000 40000000 40400000 -> 40000000", + "-inf c0a00000 3f800000 40000000 40400000 -> 40000000", + "inf c0a00000 3f800000 40000000 40400000 -> 40400000", + "inf 3f800000 c0a00000 40000000 40400000 -> 40000000", + "inf inf 3f800000 40000000 40400000 -> 40000000", + "inf 3f800000 inf 40000000 40400000 -> 40400000", + "-inf inf 3f800000 40000000 40400000 -> 40400000", + "-inf 3f800000 inf 40000000 40400000 -> 40000000", + "3f800000 -inf inf 40000000 40400000 -> nan" + ] + } + ] +}