Fra*_*une 10 floating-point compare sign zero negative-number
给定两个浮点数,我正在寻找一种有效的方法来检查它们是否具有相同的符号,假设如果这两个值中的任何一个为零(+0.0或-0.0),则应认为它们具有相同的符号标志.
例如,
SameSign
C++中一个天真但正确的实现是:
bool SameSign(float a, float b)
{
if (fabs(a) == 0.0f || fabs(b) == 0.0f)
return true;
return (a >= 0.0f) == (b >= 0.0f);
}
Run Code Online (Sandbox Code Playgroud)
假设IEEE浮点模型,这里的变体SameSign
编译为无分支代码(至少使用Visual C++ 2008):
bool SameSign(float a, float b)
{
int ia = binary_cast<int>(a);
int ib = binary_cast<int>(b);
int az = (ia & 0x7FFFFFFF) == 0;
int bz = (ib & 0x7FFFFFFF) == 0;
int ab = (ia ^ ib) >= 0;
return (az | bz | ab) != 0;
}
Run Code Online (Sandbox Code Playgroud)
与binary_cast
定义如下:
template <typename Target, typename Source>
inline Target binary_cast(Source s)
{
union
{
Source m_source;
Target m_target;
} u;
u.m_source = s;
return u.m_target;
}
Run Code Online (Sandbox Code Playgroud)
我正在寻找两件事:
SameSign
使用比特技巧,FPU技巧甚至SSE内在函数更快,更有效地实现.
有效扩展SameSign
到三个值.
编辑:
我已经对三个变体SameSign
(原始问题中描述的两个变体,加上Stephen的变体)进行了一些性能测量.每个函数运行200-400次,在101个浮点数组中的所有连续值对上随机填充-1.0,-0.0,+ 0.0和+1.0.每次测量重复2000次并保持最小时间(以消除所有高速缓存效应和系统引起的减速).代码是使用Visual C++ 2008 SP1编译的,具有最大优化和启用SSE2代码生成.测量在Core 2 Duo P8600 2.4 Ghz上进行.
下面是时间,不计算从数组中获取输入值的开销,调用函数并检索结果(相当于6-7个时钟信号):
Ste*_*non 15
如果您不需要支持无穷大,您可以使用:
inline bool SameSign(float a, float b) {
return a*b >= 0.0f;
}
Run Code Online (Sandbox Code Playgroud)
这在大多数现代硬件上实际上非常快,并且完全可移植.然而,它在(零,无穷大)情况下无法正常工作,因为零*无穷大是NaN,并且无论符号如何,比较都将返回false.当a和b都很小时,它也会在某些硬件上产生非正常停顿.
也许是这样的:
inline bool same_sign(float a, float b) {
return copysignf(a,b) == a;
}
Run Code Online (Sandbox Code Playgroud)
请参阅 copysign 的手册页以获取有关其功能的更多信息(您也可能需要检查 -0 != +0)
或者如果您有 C99 函数,则可能是这样
inline bool same_sign(float a, float b) {
return signbitf(a) == signbitf(b);
}
Run Code Online (Sandbox Code Playgroud)
作为旁注,在 gcc 上,至少 copysign 和 signbit 都是内置函数,因此它们应该很快,如果您想确保使用内置版本,您可以执行 __builtin_signbitf(a)
编辑:这也应该很容易扩展到 3 值情况(实际上这两个都应该......)
inline bool same_sign(float a, float b, float c) {
return copysignf(a,b) == a && copysignf(a,c) == a;
}
// trust the compiler to do common sub-expression elimination
inline bool same_sign(float a, float b, float c) {
return signbitf(a) == signbitf(b) && signbitf(a) == signbitf(c);
}
// the manpages do not say that signbit returns 1 for negative... however
// if it does this should be good, (no branches for one thing...)
inline bool same_sign(float a, float b, float c) {
int s = signbitf(a) + signbitf(b) + signbitf(c);
return !s || s==3;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
10114 次 |
最近记录: |