清除单个精度浮点数的位

C++: Clear bits of a single precision float

本文关键字:浮点数 精度 单个 清除      更新时间:2023-10-16

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

上述程序中常用的表达式之一涉及将32位浮点数转换为整数(即不是实际将其舍入为int,而是将相同的数据解释为int -想想reinterpret_cast),对其执行一些位旋转魔术,然后将其转换回浮点数(再次不是实际转换,而是重新解释相同的数据)。虽然这在OpenCL中工作得很好,但在c++和gcc中,这违反了严格的别名规则,如果启用了优化,则会破坏程序,并且根据体系结构,可能涉及昂贵的load-hit-store,因为浮点寄存器和整数寄存器是分开的。

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

float ClearFloatBits(float Value, int NumberOfBits) {
    return __int_as_float((__float_as_int(Value) >> NumberOfBits) << NumberOfBits);
}

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

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

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

有更好的方法吗?让我特别恼火的是(int)到舍入的转换,我想这是最昂贵的部分。如果有帮助的话,可以保证传递给函数的浮点数是介于1.0(含)和2.0(不含)之间的数字。

Thanks in advance

使用联合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;
}

严格来说,这是未定义的行为。根据C和c++标准,是非法的,如果对union的一个成员进行写操作,然后从另一个成员中读取,而不首先对该成员进行写操作,则的结果是未定义的。

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

重新解释为int违反了混叠规则。将其重新解释为unsigned char[4]则不然。是否需要支持NumberOfBits值>=8 ?如果没有,你可以在ptr[3]

上进行位移

不能使用floor()而不是转换为int类型吗?