【发布时间】:2011-02-24 17:49:25
【问题描述】:
给定两个浮点数,我正在寻找一种有效的方法来检查它们是否具有相同的符号,如果两个值中的任何一个为零(+0.0或 -0.0),它们应该被认为具有相同的符号。
例如,
- SameSign(1.0, 2.0) 应该返回 true
- SameSign(-1.0, -2.0) 应该返回 true
- SameSign(-1.0, 2.0) 应该返回 false
- SameSign(0.0, 1.0) 应该返回 true
- SameSign(0.0, -1.0) 应该返回 true
- SameSign(-0.0, 1.0) 应该返回 true
- SameSign(-0.0, -1.0) 应该返回 true
在 C++ 中 SameSign 的简单但正确的实现是:
bool SameSign(float a, float b)
{
if (fabs(a) == 0.0f || fabs(b) == 0.0f)
return true;
return (a >= 0.0f) == (b >= 0.0f);
}
假设是 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;
}
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;
}
我正在寻找两件事:
使用位技巧、FPU 技巧甚至 SSE 内在函数更快、更高效地实现
SameSign。SameSign到三个值的有效扩展。
编辑:
我对@987654330@ 的三个变体(原始问题中描述的两个变体,加上斯蒂芬的一个变体)进行了一些性能测量。每个函数运行 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 个时钟节拍):
- 朴素变体:15 个滴答声
- 位魔法变体:13 个滴答声
- 斯蒂芬斯的变种:6 滴答声
【问题讨论】:
-
任何特定的语言/平台?
-
嘿,谢谢你的好问题 :) 最好是 x86 上的 C/C++。
标签: floating-point compare sign zero negative-number