HLSL 中的高效条件上限和下限
Efficient conditional ceiling and floor in HLSL
我已经尝试解决这个问题很长时间了,但我无法完全正确。我想要做的是根据不同的 float
.
将 float
舍入到最接近的整数
我基本上需要一个应该像这样工作的函数:
float roundParam(float val, float dir)
{
if (dir >= 0)
return ceil(val);
else
return floor(val);
}
这当然是非常低效的,因为每个向量分量都需要一个分支。我想通了,但它打破了整数:
float roundParam(float val, float dir)
{
return round(val + 0.5 * sign(dir));
}
也许使用由 dir
选择的指针数组?
下面是 C。不清楚这种方法在 hsl, shader
中的可用性如何
float roundParam(float val, float dir) {
static float (*f[2])(float) = {ceilf, floorf};
return f[!!signbit(dir)](val);
}
在 C 中,您可以使用以下可向量化的函数。也许您可以在 hlsl
中使用相同的想法。此解决方案仅适用于您不关心 dir
.
的 +0
和 -0
(带符号零)之间的区别
float roundParam_v2(float val, float dir)
{
union fl_i32{float f; int i;} x, y, d;
x.f = val;
d.f = dir;
d.i = d.i & 0x80000000; /* extract the sign bit */
x.i = x.i ^ d.i; /* multiply x 1.0f if signbit is set */
y.f = ceilf(x.f); /* note that floor(z) = - ceil( -z) */
y.i = y.i ^ d.i; /* multiply x 1.0f if signbit is set */
return y.f;
}
感谢@wim 和他对 floor(x) = -ceil(-x)
和 ceil(x) = -floor(-x)
的观察,我能够创建这个解决问题的函数:
float3 roundParam(float3 val, float3 dir)
{
float3 dirSign = sign(dir);
return dirSign * floor(dirSign * val) + dirSign;
}
怎么样:
float roundParam(float val, float dir)
{
return ceil(val)*(float)(dir>=0)+floor(val)*(float)(dir<0);
}
它可能会进一步优化,但编译器可能已经进行了优化。
顺便说一句,如果您将 [flatten]
标记添加到 if
条件,它可能已经被编译器优化了。而这么简单的分支,不管你打不打标签,它很可能已经被编译器压扁了。
检查编译后的代码并查看分支是否已被删除会很有趣。我目前处于afk状态,所以无法查看...
我已经尝试解决这个问题很长时间了,但我无法完全正确。我想要做的是根据不同的 float
.
float
舍入到最接近的整数
我基本上需要一个应该像这样工作的函数:
float roundParam(float val, float dir)
{
if (dir >= 0)
return ceil(val);
else
return floor(val);
}
这当然是非常低效的,因为每个向量分量都需要一个分支。我想通了,但它打破了整数:
float roundParam(float val, float dir)
{
return round(val + 0.5 * sign(dir));
}
也许使用由 dir
选择的指针数组?
下面是 C。不清楚这种方法在 hsl, shader
float roundParam(float val, float dir) {
static float (*f[2])(float) = {ceilf, floorf};
return f[!!signbit(dir)](val);
}
在 C 中,您可以使用以下可向量化的函数。也许您可以在 hlsl
中使用相同的想法。此解决方案仅适用于您不关心 dir
.
+0
和 -0
(带符号零)之间的区别
float roundParam_v2(float val, float dir)
{
union fl_i32{float f; int i;} x, y, d;
x.f = val;
d.f = dir;
d.i = d.i & 0x80000000; /* extract the sign bit */
x.i = x.i ^ d.i; /* multiply x 1.0f if signbit is set */
y.f = ceilf(x.f); /* note that floor(z) = - ceil( -z) */
y.i = y.i ^ d.i; /* multiply x 1.0f if signbit is set */
return y.f;
}
感谢@wim 和他对 floor(x) = -ceil(-x)
和 ceil(x) = -floor(-x)
的观察,我能够创建这个解决问题的函数:
float3 roundParam(float3 val, float3 dir)
{
float3 dirSign = sign(dir);
return dirSign * floor(dirSign * val) + dirSign;
}
怎么样:
float roundParam(float val, float dir)
{
return ceil(val)*(float)(dir>=0)+floor(val)*(float)(dir<0);
}
它可能会进一步优化,但编译器可能已经进行了优化。
顺便说一句,如果您将 [flatten]
标记添加到 if
条件,它可能已经被编译器优化了。而这么简单的分支,不管你打不打标签,它很可能已经被编译器压扁了。
检查编译后的代码并查看分支是否已被删除会很有趣。我目前处于afk状态,所以无法查看...