Math HLSL中的高效条件天花板和地板

Math HLSL中的高效条件天花板和地板,math,floating-point,numbers,shader,hlsl,Math,Floating Point,Numbers,Shader,Hlsl,我已经花了很长一段时间试图弄明白这一点,但我不能完全正确。我要做的是根据不同的浮点将浮点四舍五入到最接近的整数 我基本上需要这样一个函数: float roundParam(float val, float dir) { if (dir >= 0) return ceil(val); else return floor(val); } 这当然是非常低效的,因为它需要每个向量组件一个分支。我算出来了,但它对整数是无效的: float roun

我已经花了很长一段时间试图弄明白这一点,但我不能完全正确。我要做的是根据不同的
浮点
浮点
四舍五入到最接近的整数

我基本上需要这样一个函数:

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);
}

可能使用由
dir
选择的指针数组

下面是C。不清楚这种方法在
hsl,shader

float roundParam(float val, float dir) {
  static float (*f[2])(float) = {ceilf, floorf};
  return f[!!signbit(dir)](val);
}

在C语言中,您可以使用以下可良好矢量化的函数。也许您可以在
hlsl
中使用相同的想法。此解决方案仅适用于不关心
+0
-0
(带符号零)之间的差异的
-dir

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;
}

在C语言中,您可以使用以下可良好矢量化的函数。也许您可以在
hlsl
中使用相同的想法。此解决方案仅适用于不关心
+0
-0
(带符号零)之间的差异的
-dir

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;
}

由于@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);
}
float-roundParam(float-val,float-dir)
{
返回天花板(val)*(float)(dir>=0)+地板(val)*(float)(dir怎么样:

float roundParam(float val, float dir)
{
return ceil(val)*(float)(dir>=0)+floor(val)*(float)(dir<0);
}
float-roundParam(float-val,float-dir)
{


返回ceil(val)*(float)(dir>=0)+float(val)*(float)(dir)哪个更重要:对于所有
float
?@chux,它需要对正常的浮动(数字)起作用,但我不关心NaN或无穷大。它是否需要在
dir==0.0
时工作?哪个更重要:所有
浮点值的效率或正确性?@chux>它需要在正常浮点值(数字)下工作,但我不关心NaN或无穷大。当
dir==0.0
时它需要工作吗?不幸的是,在HLSL中没有指针,没有函数指针,最重要的是没有真正的函数(它们只是语法糖,总是内联的)。这是GPU工作方式的一个限制。此外,在本地工作组中执行的所有线程都必须执行相同的指令,以实现最佳性能(因此首先出现问题)。不幸的是,在HLSL中没有指针,没有函数指针,最重要的是没有真正的函数(它们只是语法糖,总是内联的)。这是GPU工作方式的一个限制。此外,在本地工作组中执行的所有线程都必须执行相同的指令,以实现最佳性能(因此首先出现问题)。不幸的是,HLSL中没有
联合
s,尽管使用
asfloat
asint
可以实现这一点。我移植了您的函数,得到了
float3 roundParam_v2(float3 val,float3 dir){float3 x,y,d;x=val;d=dir;d=asfloat(asint(d)&0x8000000);/*提取符号位*/x=asfloat(asint(x)^asint(d));/*如果设置了signbit,则乘以x1.0f*/y=ceil(x);/*注意地板(z)=-ceil(-z)*/y=asfloat(asint(y)^asint(d));/*如果设置了signbit,则乘以x1.0f*/return y;}
不幸的是,它并没有真正达到我想要的效果。不过,谢天谢地,我发现了一个基于观察的解决方案,
floor(z)=-ceil(-z)
是我使用HLSL内部函数编写的。不幸的是,HLSL中没有
联合
s,尽管使用
asfloat
asint
可以实现这一点。我移植了您的函数,得到了
float3 roundParam_v2(float3 val,float3 dir){float3 x,y,d;x=val;d=dir;d=asfloat(asint(d)&0x8000000);/*提取符号位*/x=asfloat(asint(x)^asint(d));/*如果设置了signbit,则乘以x1.0f*/y=ceil(x);/*注意地板(z)=-ceil(-z)*/y=asfloat(asint(y)^asint(d));/*如果设置了signbit,则乘以x1.0f*/return y;}
不幸的是,它并没有真正达到我想要的效果。不过,谢天谢地,我发现了一个解决方案,这是基于我使用HLSL内部函数编写的
floor(z)=-ceil(-z)
。当加法形成四舍五入和时,会生成错误的答案。难道不希望
返回dirSign*ceil(dirSign*val)
?无论哪种方式,当
dir==0
时,这个和答案都会失败。实际上我在考虑
dirSign*floor(dirSign*val)
,但我认为
+2x
xor
更有效。显然这里不是这样。很高兴你可以使用
ceil(x)=-floor(-x)
idea.@wim GPU不擅长整数运算。事实上,直到几年前,它们才完全支持整数运算。它们的能力来自浮点运算。上面使用的“函数”
sign
floor
实际上是高度优化的GPU内部函数。它们也非常支持并行化(一次可以比CPU执行数百或数千次操作)。缺点是GPU线程在所谓的“扭曲”(AMD称之为“波前”)中工作,给定“扭曲”中的所有线程必须执行相同的精确操作(因此没有动态分支)。当加法形成四舍五入的和时,生成错误的答案。是否希望
返回dirSign*ceil(dirSign*val);
?无论哪种方式,此选项和答案都是f