简体   繁体   English

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

[英]C++: Clear bits of a single precision float

I'm currently converting a program that was originally intended for OpenCL to C++ and I'm having a bit of trouble with one particular part of it. 我目前正在将原本打算用于OpenCL的程序转换为C ++,但其中的某个特定部分有些麻烦。

One of the expressions commonly used in said program involves taking a 32 bit float, converting it to an integer (ie not actually rounding it to an int, but interpreting the same data as an int - think reinterpret_cast), performing some bit twiddling magic on it and then converting it back to a float (once again, not actual conversion, but reinterpretation of the same data). 所述程序中常用的一种表达方式是采用32位浮点数,将其转换为整数(即​​,实际上不将其舍入为int,而是将相同的数据解释为int-请考虑reinterpret_cast),执行一些魔术操作。然后将其转换回浮点数(再次,不是实际转换,而是对相同数据的重新解释)。 While this works well in OpenCL, with C++ and gcc this violates strict aliasing rules, breaking the program if optimization is enabled and, depending on the architecture, may involve an expensive load-hit-store since float and integer registers are separated. 尽管这在OpenCL中运行良好,但使用C ++和gcc却违反了严格的别名规则,如果启用了优化,则会破坏程序,并且由于体系结构的不同,由于浮点数和整数寄存器是分开的,因此可能涉及昂贵的加载命中存储。

I've been able to avoid most of these expressions efficiently, but there is one I'm not sure about whether it could be done faster. 我已经能够有效地避免大多数这些表达式,但是我不确定其中是否可以更快地完成。 Basically, the intention is to clear a number of bits from the right of a float; 基本上,目的是清除浮点数右边的一些位; the OpenCL code does this similar to this: OpenCL代码与此类似:

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

Since this is essentially rounding down from a specified (binary) digit, my C++ version now looks like this: 由于这实际上是从指定的(二进制)数字取整,因此我的C ++版本现在看起来像这样:

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

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

Where the pow and the division are of course replaced by a LUT lookup and a respective multiplication, here omitted for better readability. 当然, pow和除法用LUT查找和相应的乘法代替,此处出于更好的可读性而省略。

Is there a better way to do this? 有一个更好的方法吗? What bugs me in particular is the (int) conversion to round down, which I guess is the most expensive part. 特别令我烦恼的是要舍入的(int)转换,我认为这是最昂贵的部分。 It is guaranteed that the float passed to the function is a number between 1.0 (inclusive) and 2.0 (exclusive), if that helps. 如果有帮助,可以保证传递给函数的浮点数是介于1.0(含)和2.0(不含)之间的数字。

Thanks in advance 提前致谢

Use the union hack instead: 请改用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;
}

Strictly speaking, this is undefined behavior. 严格来说,这是未定义的行为。 Per both the C and C++ standards, it is illegal to write the result of writing to one member of a union and then reading from another member without first writing to that other member is undefined. 根据C和C ++标准, 将写入 结果写入联盟的一个成员然后从另一个成员读取而不先写入另一个成员是未定义的, 这是非法的

However, this usage of unions is so widespread and so ancient that no compiler writer that I know of obeys the standard. 但是,这种联合的用法是如此广泛和古老,以至于我所认识的编译器作者都没有遵守该标准。 In practice, the behavior is very well defined and is exactly what you would expect. 在实践中,行为定义得很清楚,正是您所期望的。 That said, this hack might not work if ported to some very strange architecture machine that uses a very strictly conforming compiler. 就是说,如果将该hack移植到使用非常严格符合要求的编译器的某些非常奇怪的体系结构计算机上,则可能无法正常工作。

Reinterpreting as an int violates aliasing rules. 重新解释为int违反别名规则。 Reinterpreting as a unsigned char[4] doesn't. 重新解释为unsigned char[4]不会。 Do you need to support NumberOfBits values >=8 ? 您是否需要支持NumberOfBits值> = 8? If not, you can just do the bitshift on ptr[3] 如果没有,您可以在ptr[3]上进行ptr[3]

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM