如何在C++上的"double"上使用按位运算符?

Jua*_*tos 9 c++ bitwise-operators

我被要求在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;
}
Run Code Online (Sandbox Code Playgroud)

当我尝试使用"double"或"float"实例化模板时,程序失败.

Jon*_*ler 16

简而言之,你没有.

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

双方doublefloat有3个部分-符号位,指数和尾数.假设你可以转移一个double权利.指数,特别是,这意味着没有简单的平移移位的比特模式右-符号位会移动到指数,和指数的至少显著位将移位到尾数,具有完全非显而易见的集合的含义.在IEEE 754中,在实际尾数位前面有一个隐含的1位,这也使解释复杂化.

类似的注释适用于任何其他位运算符.

因此,由于对double值运算符没有理解或有用的解释,因此标准不允许这些解释.


来自评论:

我只对二进制表示感兴趣.我只是想打印它,而不是做任何有用的东西.

这段代码是几年前为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);
}
Run Code Online (Sandbox Code Playgroud)

注释掉的'image_print()`函数以十六进制打印任意字节集,并进行各种小调整.如果您需要代码,请与我联系(参见我的个人资料).

如果您使用的是英特尔(小端),您可能需要调整代码来处理反向位顺序.但它显示了你如何做到 - 使用一个union.

  • 这不是重点。重点是你的陈述,这是错误的。 (3认同)
  • 您的回答证明没有提供此类功能*因为*没有使用它的合理或有用的目的。AnT 充分解释了他的答案中缺少(或至少应该)此功能的真正原因。你的观点是错误的,就像大多数人在案件提出后使用“同意不同意”和“只是我的观点”这句话一样。 (3认同)
  • “......没有对位运算符的合理或有用的解释来加倍值......” **False.** Downvote。 (2认同)
  • 简单。你是谁说检查或使用双值中的位没有理智或有用的目的?好像您知道所有可能的软件中双精度和位的所有可能用法,以便做出这样的声明。 (2认同)

tem*_*def 10

您不能直接将位运算符应用于floatdouble,但您仍然可以通过将变量放在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;
}
Run Code Online (Sandbox Code Playgroud)

你可能需要调整你的例程来处理字符,这些字符通常不超过4096,并且这里也可能有一些古怪的字节序,但基本的想法应该有效.它不是跨平台兼容的,因为机器使用不同的字节序和双精度表示,所以要小心你如何使用它.