如何对浮点数执行按位运算
我试过这个:
float a = 1.4123; a = a & (1 << 3);
我得到一个编译器错误,说&
的操作数不能是floattypes。
当我这样做时:
float a = 1.4123; a = (int)a & (1 << 3);
我正在运行程序。 唯一的事情就是按四舍五入后得到的数字的整数表示进行按位运算。
以下也是不允许的。
float a = 1.4123; a = (void*)a & (1 << 3);
我不明白为什么int
可以被抛出void*
但不能float
。
我正在这样做来解决在Stack Overflow问题中描述的问题如何使用遗传algorithm求解线性方程组? 。
在语言层面上,不存在“浮点数的按位操作”这样的事情。 C / C ++中的位运算用于数值的表示。 在C / C ++中没有定义浮点数值的表示。 浮点数在值表示的层次上没有位,这就是为什么你不能对它们应用按位操作。
你所能做的就是分析浮点数占用的原始内存的位内容。 为此,您需要使用下面build议的联合或者(等同地,并且只在C ++中)将浮点对象重新解释为一个unsigned char
对象数组,如
float f = 5; unsigned char *c = reinterpret_cast<unsigned char *>(&f); // inspect memory from c[0] to c[sizeof f - 1]
另外,请不要尝试像其他答案所build议的那样将float
对象重新解释为int
对象。 这是没有什么意义的,这是非法的,这不能保证在优化中遵循严格别名规则的编译器工作。 在C ++中检查内存内容的唯一合法方法是将其重新解释为[signed/unsigned] char
的数组。
另外请注意,在技术上不能保证你的系统上的浮点表示是IEEE754(尽pipe在实践中它是除非你明确地允许它不是,然后只针对-0.0,±无穷大和NaN)。
如果您试图更改浮点表示中的位,可以这样做:
union fp_bit_twiddler { float f; int i; } q; qf = a; qi &= (1 << 3); a = qf;
正如AndreyT所指出的那样,访问像这样的联合会调用未定义的行为,而编译器可能会伸长arm并扼杀你。 做他的build议。
float a = 1.4123; unsigned int* inta = reinterpret_cast<unsigned int*>(&a); *inta = *inta & (1 << 3);
看看下面的内容。 受快速平方根的启发:
#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; }
@mobrule:
更好:
#include <stdint.h> ... union fp_bit_twiddler { float f; uint32_t u; } q; /* mutatis mutandis ... */
对于这些值 int可能是好的,但一般来说,你应该使用无符号整型进行位移以避免算术移位的影响。 uint32_t甚至可以在int不是32位的系统上工作。
浮点运算的浮点运算(Python配方)中的Python实现通过表示二进制数字的方式工作,二进制数字无限地向左和向右延伸。 由于浮点数在大多数架构上都有一个有符号的零,所以它使用补码来表示负数(实际上它只是假装这样做并使用一些技巧来实现外观)。
我相信它可以适应在C ++中工作,但是必须小心谨慎,以便在均衡指数时不会让右移溢出。
按位运算符不应该在浮点数上使用,因为浮点数是硬件特定的,无论您使用什么硬件都是相似的。 你想冒什么风险?“在我的机器上运行好了”? 相反,对于C ++,您可以通过在“对象”包装器上重载stream操作符来获得与位移操作符类似的“感觉”:float:
// 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; }
你将有一个剩余的,你可以根据你想要的实现扔掉。
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的回应相似,除了它只创build一个相同寄存器中位的视图。 所以当你操作*b
, a
值会相应地改变。
FWIW,在浮点运算上有一个真实的用例(我刚刚碰到它) – 为仅支持GLSL的老版本的GPU编写的着色器(1.2及更早版本不支持按位运算符) ,如果浮点数转换为整数,那么精度会有所下降。
按位操作可以使用余数(模)和不等式检查在浮点数上实现。 例如:
float A = 0.625; //value to check; ie, 160/256 float mask = 0.25; //bit to check; ie, 1/4 bool result = (mod(A, 2.0 * mask) >= mask); //non-zero if bit 0.25 is on in A
上面假定A在[0..1]之间,掩码中只有一个“位”来检查,但是可以推广到更复杂的情况。
这个想法是基于在它是可能实现位运算符使用整数algorithm中find的一些信息
如果甚至没有内置的mod函数,那么也可以相当容易地实现。 例如:
float mod(float num, float den) { return num - den * floor(num / den); }