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

时间:2011-08-26 11:45:59

标签: 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);
}

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

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

    return ((int)(Value*Factor))/Factor;
}

pow和除法当然被LUT查找和相应的乘法替换时,为了更好的可读性,这里省略了。

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

提前致谢

3 个答案:

答案 0 :(得分:3)

改为使用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;
}

严格来说,这是未定义的行为。根据C和C ++标准,写入一个union的一个成员然后从另一个成员读取而不首先写入该另一个成员是不合法的。

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

答案 1 :(得分:2)

重新解释为int违反了别名规则。重新解释为unsigned char[4]不会。您需要支持NumberOfBits值&gt; = 8吗?如果没有,您可以在ptr[3]

上执行bitshift

答案 2 :(得分:0)

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