如何在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:19:44  来源:igfitidea点击:

How do I use bitwise operators on a "double" on C++?

c++bitwise-operators

提问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 doubleor float, and the standard says that the bitwise operators (~, &, |, ^, >>, <<, and the assignment variants) do not accept doubleor floatoperands.

当应用于位运算符没有意义double或者float,标准说,位运算符(~&|^>><<,和分配变型),不接受doublefloat操作数。

Both doubleand floathave 3 sections - a sign bit, an exponent, and the mantissa. Suppose for a moment that you could shift a doubleright. 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.

双方doublefloat有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 doublevalues, 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 floator double, but you can still access the bits indirectly by putting the variable in a unionwith a character array of the appropriate size, then reading the bits from those characters. For example:

您不能直接将按位运算符应用于floator 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 intas well as to double.

按位运算符通常不适用于任何类型的“二进制表示”(也称为对象表示)。按位运算符处理类型的值表示,这通常与对象表示不同。这同样适用于。intdouble

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 charobjects and then use the bitwise operators on these unsigned chars

如果您真的想获得任何类型对象的内部二进制表示,如您在问题中所述,您需要将该类型的对象重新解释为对象数组,unsigned char然后在这些unsigned chars上使用按位运算符

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 charvalues, if you want to.

现在通过访问元素c[0]c[sizeof(double) - 1]您将看到 type 的内部表示doubleunsigned char如果需要,您可以对这些值使用按位运算。

Note, again, that in general case in order to access internal representation of type intyou have to do the same thing. It generally applies to anytype other than chartypes.

再次注意,在一般情况下,为了访问类型的内部表示,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