C++ 快速找到以2为底的对数的整数部分

C++ 快速找到以2为底的对数的整数部分,c++,c,floating-point,ieee-754,C++,C,Floating Point,Ieee 754,什么是计算浮点数以2为底的对数的整数部分的有效方法?差不多 N = ceil( log2( f )) 或 对于浮点f。我想这是可以非常有效地实现的,因为人们可能只需要访问浮点指数 编辑2:我主要对精确性不感兴趣。我可以容忍+-1的错误。我列举了这两个变量作为例子,因为其中一个在计算上可能比另一个便宜(但我不知道) 我需要这个来控制算法的精度,其中参数f是一些公差,需要日志来控制术语的数量。准确计算日志并不重要 编辑:这不是其他许多问题的重复,这些问题要求整数参数的log2(例如)。这是关于浮点

什么是计算浮点数以2为底的对数的整数部分的有效方法?差不多

N = ceil( log2( f ))

对于浮点f。我想这是可以非常有效地实现的,因为人们可能只需要访问浮点指数

编辑2:我主要对精确性不感兴趣。我可以容忍+-1的错误。我列举了这两个变量作为例子,因为其中一个在计算上可能比另一个便宜(但我不知道)

我需要这个来控制算法的精度,其中参数f是一些公差,需要日志来控制术语的数量。准确计算日志并不重要


编辑:这不是其他许多问题的重复,这些问题要求整数参数的log2(例如)。这是关于浮点参数和一个完全不同的故事。特别是对于f<1,这在整数方法中是不可能的。标准库函数就是这样做的:它将double分解为整数指数和归一化尾数

如果您对对数的下限感到满意,而不是将对数四舍五入到最接近的整数,那么使用较新的标准库函数可能会更好


请注意,这两个函数对零和无穷大的处理方式不同,因此它们不能完全互换。

受rici的启发,他给我指出了frexp,我想我找到了答案。在C99和最近的C++中,我们的函数正好符合我所需要的

int ilogb( float arg );
int ilogb( double arg );
相当于

(int)logb( arg )
它返回的值比frexp少一个。所以frexp结果对应于

floor(log2(arg)+1 
和ilogb(arg)到


这是一个可怕的黑客行为,它从little endian
float
中提取指数,尽管我不能保证可移植性等

#include <stdio.h>

int main(void) {
    float f;
    unsigned i;
    unsigned *ip = (unsigned*)&f;

    printf("Enter a float: ");
    scanf("%f", &f);
    i = *ip;
    i = (i >> 23) & 0xFF;
    i -= 127;
    printf("%f %d\n", f, (int)i);
    return 0;
}

对于内置FPU的现代CPU,在硬件中实现对数运算,如果一个手工实现能够击败直接
底层(log2(f))
方法,我会感到惊讶。没有重复。我的问题是关于浮点数的log2。不是整数的对数2。因为小于1的数字的对数是负数,所以应该向上或向下取整由你决定。你不能只提取指数并减去127(单精度)或1023(双精度)?@WeatherVane:我很乐意使用这两种版本…谢谢,这是我一直在寻找的解决方案。但是,我认为ilogb函数可能更适合。谢谢你指给我看。@andreas:你可能是对的。我想我显示了我的年龄:-)注意,你不应该使用指针取消引用来进行类型双关,因为这是一种未定义的行为(大多数编译器会用
-Wall
发出警告)。应该改用联合体。@Simon:我认为从联合体中读取与您写入的不同类型的信息也很重要。我错了吗?@WaetherVane:你的黑客攻击可能对big endian同样有效。仅当浮点和整数具有不同的endianness时,它才起作用。不,它是从C99开始定义的(虽然技术上不是C++):注意:这不会返回次正常值的正确答案:
f
floor(log2(arg))
#include <stdio.h>

int main(void) {
    float f;
    unsigned i;
    unsigned *ip = (unsigned*)&f;

    printf("Enter a float: ");
    scanf("%f", &f);
    i = *ip;
    i = (i >> 23) & 0xFF;
    i -= 127;
    printf("%f %d\n", f, (int)i);
    return 0;
}
Enter a float: 0.125
0.125000 -3