如何在 C++ 上的“double”上使用按位运算符?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4743115/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I use bitwise operators on a "double" on C++?
提问by Juan Pablo Santos
I was asked to get the internal binary representation of different types in C. My program currently works fine with 'int' but I would like to use it with "double" and "float". My code looks like this:
我被要求在 C 中获取不同类型的内部二进制表示。我的程序目前在“int”下运行良好,但我想将它与“double”和“float”一起使用。我的代码如下所示:
template <typename T>
string findBin(T x) {
string binary;
for(int i = 4096 ; i >= 1; i/=2) {
if((x & i) != 0) binary += "1";
else binary += "0";
}
return binary;
}
The program fails when I try to instantiate the template using a "double" or a "float".
当我尝试使用“double”或“float”实例化模板时,程序失败。
回答by Jonathan Leffler
Succinctly, you don't.
简而言之,你没有。
The bitwise operators do not make sense when applied to double
or float
, and the standard says that the bitwise operators (~
, &
, |
, ^
, >>
, <<
, and the assignment variants) do not accept double
or float
operands.
当应用于位运算符没有意义double
或者float
,标准说,位运算符(~
,&
,|
,^
,>>
,<<
,和分配变型),不接受double
或float
操作数。
Both double
and float
have 3 sections - a sign bit, an exponent, and the mantissa. Suppose for a moment that you could shift a double
right. The exponent, in particular, means that there is no simple translation to shifting a bit pattern right - the sign bit would move into the exponent, and the least significant bit of the exponent would shift into the mantissa, with completely non-obvious sets of meanings. In IEEE 754, there's an implied 1 bit in front of the actual mantissa bits, which also complicates the interpretation.
双方double
并float
有3个部分-符号位,指数和尾数。假设您可以double
向右移动。指数,特别是,意味着没有简单的转换来右移位模式 - 符号位将移入指数,指数的最低有效位将移入尾数,完全不明显的意义。在 IEEE 754 中,实际尾数位前面有一个隐含的 1 位,这也使解释复杂化。
Similar comments apply to any of the other bit operators.
类似的注释适用于任何其他位运算符。
So, because there is no sane or useful interpretation of the bit operators to double
values, they are not allowed by the standard.
因此,由于位运算符对double
值没有合理或有用的解释,因此标准不允许使用它们。
From the comments:
来自评论:
I'm only interested in the binary representation. I just want to print it, not do anything useful with it.
我只对二进制表示感兴趣。我只是想打印它,而不是用它做任何有用的事情。
This code was written several years ago for SPARC (big-endian) architecture.
这段代码是几年前为 SPARC(大端)架构编写的。
#include <stdio.h>
union u_double
{
double dbl;
char data[sizeof(double)];
};
union u_float
{
float flt;
char data[sizeof(float)];
};
static void dump_float(union u_float f)
{
int exp;
long mant;
printf("32-bit float: sign: %d, ", (f.data[0] & 0x80) >> 7);
exp = ((f.data[0] & 0x7F) << 1) | ((f.data[1] & 0x80) >> 7);
printf("expt: %4d (unbiassed %5d), ", exp, exp - 127);
mant = ((((f.data[1] & 0x7F) << 8) | (f.data[2] & 0xFF)) << 8) | (f.data[3] & 0xFF);
printf("mant: %16ld (0x%06lX)\n", mant, mant);
}
static void dump_double(union u_double d)
{
int exp;
long long mant;
printf("64-bit float: sign: %d, ", (d.data[0] & 0x80) >> 7);
exp = ((d.data[0] & 0x7F) << 4) | ((d.data[1] & 0xF0) >> 4);
printf("expt: %4d (unbiassed %5d), ", exp, exp - 1023);
mant = ((((d.data[1] & 0x0F) << 8) | (d.data[2] & 0xFF)) << 8) | (d.data[3] & 0xFF);
mant = (mant << 32) | ((((((d.data[4] & 0xFF) << 8) | (d.data[5] & 0xFF)) << 8) | (d.data[6] & 0xFF)) << 8) | (d.data[7] & 0xFF);
printf("mant: %16lld (0x%013llX)\n", mant, mant);
}
static void print_value(double v)
{
union u_double d;
union u_float f;
f.flt = v;
d.dbl = v;
printf("SPARC: float/double of %g\n", v);
// image_print(stdout, 0, f.data, sizeof(f.data));
// image_print(stdout, 0, d.data, sizeof(d.data));
dump_float(f);
dump_double(d);
}
int main(void)
{
print_value(+1.0);
print_value(+2.0);
print_value(+3.0);
print_value( 0.0);
print_value(-3.0);
print_value(+3.1415926535897932);
print_value(+1e126);
return(0);
}
The commented out 'image_print()` function prints an arbitrary set of bytes in hex, with various minor tweaks. Contact me if you want the code (see my profile).
注释掉的“image_print()”函数以十六进制打印任意一组字节,并进行了各种细微的调整。如果您需要代码,请与我联系(请参阅我的个人资料)。
If you're using Intel (little-endian), you'll probably need to tweak the code to deal with the reverse bit order. But it shows how you can do it - using a union
.
如果您使用的是 Intel(小端),您可能需要调整代码以处理相反的位顺序。但它展示了如何做到这一点 - 使用union
.
回答by templatetypedef
You cannot directly apply bitwise operators to float
or double
, but you can still access the bits indirectly by putting the variable in a union
with a character array of the appropriate size, then reading the bits from those characters. For example:
您不能直接将按位运算符应用于float
or double
,但您仍然可以通过将变量放入union
具有适当大小的字符数组的 a 中,然后从这些字符中读取位来间接访问这些位。例如:
string BitsFromDouble(double value) {
union {
double doubleValue;
char asChars[sizeof(double)];
};
doubleValue = value; // Write to the union
/* Extract the bits. */
string result;
for (size i = 0; i < sizeof(double); ++i)
result += CharToBits(asChars[i]);
return result;
}
You may need to adjust your routine to work on chars, which usually don't range up to 4096, and there may also be some weirdness with endianness here, but the basic idea should work. It won't be cross-platform compatible, since machines use different endianness and representations of doubles, so be careful how you use this.
您可能需要调整您的例程来处理字符,字符的范围通常不超过 4096,而且这里的字节序可能有些奇怪,但基本思想应该可行。它不会跨平台兼容,因为机器使用不同的字节顺序和双精度表示,所以要小心使用它。
回答by AnT
Bitwise operators don't generally work with "binary representation" (also called object representation) of anytype. Bitwise operators work with value representationof the type, which is generally different from object representation. That applies to int
as well as to double
.
按位运算符通常不适用于任何类型的“二进制表示”(也称为对象表示)。按位运算符处理类型的值表示,这通常与对象表示不同。这同样适用于。int
double
If you really want to get to the internal binary representation of an object of any type, as you stated in your question, you need to reinterpret the object of that type as an array of unsigned char
objects and then use the bitwise operators on these unsigned char
s
如果您真的想获得任何类型对象的内部二进制表示,如您在问题中所述,您需要将该类型的对象重新解释为对象数组,unsigned char
然后在这些unsigned char
s上使用按位运算符
For example
例如
double d = 12.34;
const unsigned char *c = reinterpret_cast<unsigned char *>(&d);
Now by accessing elements c[0]
through c[sizeof(double) - 1]
you will see the internal representation of type double
. You can use bitwise operations on these unsigned char
values, if you want to.
现在通过访问元素c[0]
,c[sizeof(double) - 1]
您将看到 type 的内部表示double
。unsigned char
如果需要,您可以对这些值使用按位运算。
Note, again, that in general case in order to access internal representation of type int
you have to do the same thing. It generally applies to anytype other than char
types.
再次注意,在一般情况下,为了访问类型的内部表示,int
您必须做同样的事情。它通常适用于类型以外的任何char
类型。
回答by KitsuneYMG
Do a bit-wise cast of a pointer to the double to long long *
and dereference.
Example:
对指向 double 的指针进行按位转换long long *
并取消引用。例子:
inline double bit_and_d(double* d, long long mask) {
long long t = (*(long long*)d) & mask;
return *(double*)&t;
}
Edit: This is almost certainly going to run afoul of gcc's enforcement of strict aliasing. Use one of the various workarounds for that. (memcpy
, unions, __attribute__((__may_alias__))
, etc)
编辑:这几乎肯定会违反 gcc 对严格别名的强制执行。为此,请使用各种解决方法之一。( memcpy
, 工会__attribute__((__may_alias__))
, 等)
回答by jaboja
Other solution is to get a pointer to the floating point variable and cast it to a pointer to integer type of the same size, and then get value of the integer this pointer points to. Now you have an integer variable with same binary representation as the floating point one and you can use your bitwise operator.
另一种解决方案是获取一个指向浮点变量的指针并将其强制转换为指向相同大小的整数类型的指针,然后获取该指针指向的整数的值。现在您有一个与浮点数相同的二进制表示的整数变量,您可以使用按位运算符。
string findBin(float f) {
string binary;
for(long i = 4096 ; i >= 1; i/=2) {
long x = * ( long * ) &y;
if((x & i) != 0) binary += "1";
else binary += "0";
}
return binary;
}
But remember: you have to cast to a type with same size. Otherwise unpredictable things may happen (like buffer overflow, access violation etc.).
但请记住:您必须转换为具有相同大小的类型。否则可能会发生不可预测的事情(如缓冲区溢出、访问冲突等)。
回答by Josh
As others have said, you can use a bitwise operator on a double by casting double*
to long long*
(or sometimes just long*
).
正如其他人所说,您可以通过强制转换double*
为long long*
(或有时只是long*
)对 double 使用按位运算符。
int main(){
double * x = (double*)malloc(sizeof(double));
*x = -5.12345;
printf("%f\n", *x);
*((long*)x) &= 0x7FFFFFFFFFFFFFFF;
printf("%f\n", *x);
return 0;
}
On my computer, this code prints:
在我的计算机上,此代码打印:
-5.123450
5.123450