我需要在C ++中实现非常快速的log2(float x)函数。
我发现了一个非常有趣的实现(而且非常快!)
#include <intrin.h>
inline unsigned long log2(int x)
{
unsigned long y;
_BitScanReverse(&y, x);
return y;
}
但是这个函数仅适用于输入中的整数值。
问题:有没有办法将此功能转换为 double 类型的输入变量?
UPD :
我发现了这个实现:
typedef unsigned long uint32;
typedef long int32;
static inline int32 ilog2(float x)
{
uint32 ix = (uint32&)x;
uint32 exp = (ix >> 23) & 0xFF;
int32 log2 = int32(exp) - 127;
return log2;
}
比前一个示例快得多,但输出是无符号类型。
是否可以使此功能返回 double 类型?
提前致谢!
答案 0 :(得分:6)
如果你只需要对数的整数部分,那么你可以直接从浮点数中提取它。
便携地:
#include <cmath>
int log2_fast(double d) {
int result;
std::frexp(d, &result);
return result-1;
}
可能更快,但依赖于未指定和未定义的行为:
int log2_evil(double d) {
return ((reinterpret_cast<unsigned long long&>(d) >> 52) & 0x7ff) - 1023;
}
答案 1 :(得分:5)
MSVC + GCC兼容版本,提供XX.XXXXXXX + -0.0054545
float mFast_Log2(float val) {
union { float val; int32_t x; } u = { val };
register float log_2 = (float)(((u.x >> 23) & 255) - 128);
u.x &= ~(255 << 23);
u.x += 127 << 23;
log_2 += ((-0.3358287811f) * u.val + 2.0f) * u.val -0.65871759316667f;
return (log_2);
}
答案 2 :(得分:4)
编辑:有关更好的版本,请参阅下面评论中的“按作业链接”链接。
Fast log() function(约快5倍)
也许对你感兴趣。代码在这里工作;但它并非无限精确。由于代码在网页上被破坏(&gt;已被删除),我将在此处发布:
inline float fast_log2 (float val)
{
int * const exp_ptr = reinterpret_cast <int *> (&val);
int x = *exp_ptr;
const int log_2 = ((x >> 23) & 255) - 128;
x &= ~(255 << 23);
x += 127 << 23;
*exp_ptr = x;
val = ((-1.0f/3) * val + 2) * val - 2.0f/3; // (1)
return (val + log_2);
}
inline float fast_log (const float &val)
{
return (fast_log2 (val) * 0.69314718f);
}
答案 3 :(得分:2)
您可以查看this implementation,但是:
答案 4 :(得分:2)
C ++ 11将std::log2添加到<cmath>
。
答案 5 :(得分:0)
这是对第一个答案的改进,它不依赖于IEEE实现,尽管我认为它只能在IEEE机器上快速frexp()
基本上是无成本函数。
不是丢弃frexp
返回的分数,而是可以使用它进行线性插值。如果积分值为正,则分数值介于0.5和1.0之间,因此我们将介于0.0和1.0之间并将其添加到指数中。
在实践中,看起来这种快速评估对于大约5-10%是好的,总是返回一个稍低的值。我确信通过调整2*
缩放因子可以使它更好。
#include <cmath>
double log2_fast(double d) {
int exponent;
double fraction = std::frexp(d, &exponent);
return (result-1) + 2* (fraction - 0.5);
}
您可以通过以下方式验证这是合理的快速近似值:
#include <cmath>
int main()
{
for(double x=0.001;x<1000;x+=0.1)
{
std::cout << x << " " << std::log2(x) << " " << log2_fast(x) << "\n";
}
}
答案 6 :(得分:-2)
这个函数不是C ++,它是MSVC ++特有的。此外,我非常怀疑任何这样的内在函数存在。如果他们这样做,标准函数将被配置为使用它。所以只需调用标准提供的库。
答案 7 :(得分:-2)
不,但是如果你只需要结果的组成部分并且不坚持可移植性,那就更快了。因为您只需要提取浮动的指数部分!