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)
,但我认为和+2xxor
更有效。显然这里不是这样。很高兴你可以使用ceil(x)=-floor(-x)
idea.@wim GPU不擅长整数运算。事实上,直到几年前,它们才完全支持整数运算。它们的能力来自浮点运算。上面使用的“函数”sign
和floor
实际上是高度优化的GPU内部函数。它们也非常支持并行化(一次可以比CPU执行数百或数千次操作)。缺点是GPU线程在所谓的“扭曲”(AMD称之为“波前”)中工作,给定“扭曲”中的所有线程必须执行相同的精确操作(因此没有动态分支)。当加法形成四舍五入的和时,生成错误的答案。是否希望返回dirSign*ceil(dirSign*val);
?无论哪种方式,此选项和答案都是f