如何对浮点数执行按位运算

时间:2009-11-12 16:36:15

标签: c++ floating-point genetic-algorithm bitwise-operators

我试过了:

float a = 1.4123;
a = a & (1 << 3);

我收到编译错误,指出&的操作数不能是float类型。

当我这样做时:

float a = 1.4123;
a = (int)a & (1 << 3);

我让程序运行。唯一的一点是按位运算是在四舍五入后得到的数字的整数表示上完成的。

以下也是不允许的。

float a = 1.4123;
a = (void*)a & (1 << 3);

我不明白为什么int可以投放到void*而不是float

我这样做是为了解决Stack Overflow问题 How to solve linear equations using a genetic algorithm? 中描述的问题。

10 个答案:

答案 0 :(得分:71)

在语言层面,没有“对浮点数进行按位运算”这样的事情。 C / C ++中的按位运算用于数字的值表示。并且在C / C ++中没有定义浮点数的值表示。浮点数在值表示级别没有位,这就是为什么不能对它们应用按位运算的原因。

您所能做的就是分析浮点数占用的原始内存的位内容。为此,您需要使用下面建议的union或(等效地,仅在C ++中)将浮点对象重新解释为unsigned char个对象的数组,如

float f = 5;
unsigned char *c = reinterpret_cast<unsigned char *>(&f);
// inspect memory from c[0] to c[sizeof f - 1]

请注意,请不要尝试将float对象重新解释为int对象,正如其他答案所示。这没有多大意义,这是非法的,并且不能保证在优化中遵循严格别名规则的编译器中工作。检查C ++中内存内容的唯一合法方法是将其重新解释为[signed/unsigned] char的数组。

另请注意,从技术上讲,您无法保证系统上的浮点表示是IEEE754(尽管在实践中它是除非您明确允许它不存在,然后仅针对-0.0,±无穷大和NaN) )。

答案 1 :(得分:18)

如果您尝试更改浮点表示中的位,可以执行以下操作:

union fp_bit_twiddler {
    float f;
    int i;
} q;
q.f = a;
q.i &= (1 << 3);
a = q.f;

正如AndreyT所说,访问这样的联合会调用未定义的行为,编译器可能会成长并扼杀你。做他的建议而不是。

答案 2 :(得分:8)

float a = 1.4123;
unsigned int* inta = reinterpret_cast<unsigned int*>(&a);
*inta = *inta & (1 << 3);

答案 3 :(得分:6)

看看以下内容。灵感来自快速反平方根:

#include <iostream>
using namespace std;

int main()
{
    float x, td = 2.0;
    int ti = *(int*) &td;
    cout << "Cast int: " << ti << endl;
    ti = ti>>4;
    x = *(float*) &ti;
    cout << "Recast float: " << x << endl;
    return 0; 
}

答案 4 :(得分:4)

@mobrule:

更好:

#include <stdint.h>
...
union fp_bit_twiddler {
    float f;
    uint32_t u;
} q;

/* mutatis mutandis ... */

对于这些值 int可能没问题,但通常你应该使用 用于位移的无符号整数,以避免算术移位的影响。和 即使在int不是32位的系统上,uint32_t也能正常工作。

答案 5 :(得分:2)

浮点式按位运算的 Floating point bitwise operations (Python recipe) 中的Python实现通过表示二进制中的数字来实现,该数字从小数点向左和向右无限延伸。因为浮点数在大多数架构上都有一个零符号,所以它使用ones' complement来表示负数(实际上它只是假装这样做并使用一些技巧来实现外观)。

我确信它可以适应在C ++中工作,但必须小心,以便在均衡指数时不要让正确的移位溢出。

答案 6 :(得分:2)

您可以解决the strict-aliasing rule并在类型为uint32_tfloat上执行按位操作(如果您的实现已定义,大多数都这样做),可以使用{ {3}}:

float a = 1.4123f;
uint32_t b;

std::memcpy(&b, &a, 4);
// perform bitwise operation
b &= 1u << 3;
std::memcpy(&a, &b, 4);

答案 7 :(得分:1)

不应在浮点数上使用按位运算符,因为浮点数是特定于硬件的,无论您使用何种硬件都具有相似性。您希望在“我的机器上运行良好”的风险项目/工作?相反,对于C ++,你可以通过在一个浮点数的“对象”包装上重载流操作符来为位移运算符获得类似的“感觉”:

// Simple object wrapper for float type as templates want classes.
class Float
{
float m_f;
public:
    Float( const float & f )
    : m_f( f )
    {
    }

    operator float() const
    {
        return m_f;
    }
};

float operator>>( const Float & left, int right )
{
    float temp = left;
    for( right; right > 0; --right )
    {
        temp /= 2.0f;
    }
    return temp;
}

float operator<<( const Float & left, int right )
{
    float temp = left;
    for( right; right > 0; --right )
    {
        temp *= 2.0f;
    }
    return temp;
}

int main( int argc, char ** argv )
{
    int a1 = 40 >> 2; 
    int a2 = 40 << 2;
    int a3 = 13 >> 2;
    int a4 = 256 >> 2;
    int a5 = 255 >> 2;

    float f1 = Float( 40.0f ) >> 2; 
    float f2 = Float( 40.0f ) << 2;
    float f3 = Float( 13.0f ) >> 2;
    float f4 = Float( 256.0f ) >> 2;
    float f5 = Float( 255.0f ) >> 2;
}

您将有一个剩余部分,您可以根据所需的实施方式将其丢弃。

答案 8 :(得分:1)

float a = 1.4123;
int *b = (int *)&a;
*b = *b & (1 << 3);
// a is now the IEEE floating-point value caused by the manipulation of *b
// equals 1.121039e-44 (tested on my system)

这类似于Justin的响应,除了它只创建与a相同的寄存器中的位视图。因此,当您操纵*b时,a的值会相应更改。

答案 9 :(得分:0)

FWIW,浮点上的逐位操作有一个真实的用例(我最近刚碰到它) - 为只支持旧版本的GLSL的GPU编写的着色器(1.2及更早版本不支持bit-明智的操作员),如果浮子被转换为整数,那么精度将会下降。

可以使用余数(模)和不等式检查在浮点数上实现逐位运算。例如:

float mod(float num, float den)
{
    return num - den * floor(num / den);
}

以上假设A介于[0..1]之间,并且掩码中只有一个“位”要检查,但可以针对更复杂的情况进行推广。

这个想法是基于is-it-possible-to-implement-bitwise-operators-using-integer-arithmetic

中的一些信息

如果甚至没有内置的mod函数,那么也可以相当容易地实现。例如:

{{1}}