C++:清除单个精度浮点数的位

Ben*_*rli 5 c++ floating-point

我目前正在将最初用于OpenCL的程序转换为C++,并且我在其中的一个特定部分遇到了一些麻烦.

在所述程序中常用的表达式之一涉及采用32位浮点数,将其转换为整数(即​​实际上不将其舍入为int,但将相同的数据解释为int - 认为reinterpret_cast),执行一些有点狡猾的魔法它然后将其转换回浮点数(再一次,不是实际的转换,而是重新解释相同的数据).虽然这在OpenCL中运行良好,但是C++和gcc违反了严格的别名规则,如果启用了优化,则会破坏程序,并且根据体系结构,可能会涉及昂贵的加载命中存储,因为浮点数和整数寄存器是分开的.

我已经能够有效地避免大多数这些表达,但有一个我不确定它是否可以更快地完成.基本上,目的是清除浮点右边的一些位; OpenCL代码与此类似:

float ClearFloatBits(float Value, int NumberOfBits) {
    return __int_as_float((__float_as_int(Value) >> NumberOfBits) << NumberOfBits);
}
Run Code Online (Sandbox Code Playgroud)

由于这基本上是从指定的(二进制)数字向下舍入,我的C++版本现在看起来像这样:

float ClearFloatBits(float Value, int NumberOfBits) {
    float Factor = pow(2.0f, 23 - NumberOfBits);

    return ((int)(Value*Factor))/Factor;
}
Run Code Online (Sandbox Code Playgroud)

pow当然,除了LUT查找和相应的乘法,其中和除法被省略,为了更好的可读性,这里省略了.

有一个更好的方法吗?特别让我感到困惑的是向下舍入的(int)转换,我猜这是最昂贵的部分.保证传递给函数的float是1.0(包括)和2.0(不包括)之间的数字,如果有帮助的话.

提前致谢

Dav*_*men 4

使用 union hack 来代替:

float ClearFloatBits(float Value, int NumberOfBits) {
   union { unsigned int int_val; float flt_val; } union_hack;
   union_hack.flt_val = Value;
   (union_hack.int_val >>= NumberOfBits) <<= NumberOfBits;
   return union_hack.flt_val;
}
Run Code Online (Sandbox Code Playgroud)

严格来说,这是未定义的行为。根据 C 和 C++ 标准,如果先写入联合体的一个成员,然后从另一个成员读取,而没有先写入该其他成员,则写入该结果是非法的,这是未定义的。

然而,联合的这种用法是如此广泛和古老,以至于据我所知没有编译器编写者遵守该标准。实际上,该行为定义得非常明确,并且正是您所期望的。也就是说,如果移植到一些使用非常严格的编译器的非常奇怪的架构机器上,这个黑客可能不起作用。