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

时间:2011-01-20 03:16:52

标签: 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;
}

当我尝试使用“double”或“float”实例化模板时程序失败。

6 个答案:

答案 0 :(得分:15)

简洁地说,你没有。

当应用于doublefloat时,按位运算符没有意义,标准表示按位运算符(~&,{{1} },|^>>以及分配变体)不接受<<double个操作数。

floatdouble都有3个部分 - 符号位,指数和尾数。假设您可以转移float权利。特别地,指数意味着没有简单的平移来转换位模式 - 符号位将移动到指数中,指数的最低位将转移到尾数中,完全不明显的含义。在IEEE 754中,实际尾数位前面有一个隐含的1位,这也使解释变得复杂。

类似的评论适用于任何其他位运算符。

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


来自评论:

  

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

这段代码是几年前为SPARC(大端)架构编写的。

double

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

如果您使用的是英特尔(小端),您可能需要调整代码来处理反向位顺序。但它显示了如何使用#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); }

答案 1 :(得分:10)

您不能直接将位运算符应用于floatdouble,但您仍然可以通过将变量放在union中并使用适当大小的字符数组来间接访问这些位,然后从这些字符中读取位。例如:

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;
}

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

答案 2 :(得分:4)

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

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

上的按位运算符

例如

double d = 12.34;
const unsigned char *c = reinterpret_cast<unsigned char *>(&d);

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

再次注意,在一般情况下,为了访问类型int的内部表示,您必须做同样的事情。它通常适用于char类型以外的任何类型。

答案 3 :(得分:3)

对指向long long *的双精度指针进行逐位转换并取消引用。 例如:

inline double bit_and_d(double* d, long long mask) {
  long long t = (*(long long*)d) & mask;
  return *(double*)&t;
}

编辑:这几乎肯定会与gcc严格别名的执行相冲突。使用各种变通办法之一。 (memcpy,工会,__attribute__((__may_alias__))等)

答案 4 :(得分:1)

其他解决方案是获取指向浮点变量的指针并将其转换为指向相同大小的整数类型的指针,然后获取此指针指向的整数的值。现在你有一个整数变量,其浮点数与二进制表示相同,你可以使用你的按位运算符。

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;
}

但请记住:你必须转换为具有相同大小的类型。否则可能会发生不可预测的事情(如缓冲区溢出,访问冲突等)。

答案 5 :(得分:0)

就像其他人所说的那样,可以通过将>>> def track_history(f): ... hist = [] ... def wrapper(*a, **kw): ... hist.append((a, kw)) ... return f(*a, **kw) ... wrapper.call_history = hist ... return wrapper ... >>> >>> @track_history ... def f(x, y=None): ... return x, y ... >>> >>> print(f.call_history) [] >>> >>> f('foo') ('foo', None) >>> f(1, 0) (1, 0) >>> >>> f.call_history [(('foo',), {}), ((1, 0), {})] 强制转换为const path = require(`path`) exports.createPages = ({ graphql, actions }) => { const { createPage } = actions return graphql(` query { allWordpressPost { edges { node { title excerpt slug link } } } allWordpressWpProperty { edges { node { slug title content featured_media { localFile { childImageSharp { original { width height src } } } } acf { size } } } } } `).then(result => { result.data.allWordpressPost.edges.forEach(({ node }) => { createPage({ path: node.slug, component: path.resolve(`./src/templates/blog-post.js`), context: { // This is the $slug variable // passed to blog-post.js slug: node.slug }, }) }); result.data.allWordpressWpProperty.edges.forEach(({ node }) => { createPage({ path: node.slug, component: path.resolve(`./src/templates/property.js`), context: { // This is the $slug variable // passed to property.js slug: node.slug }, }) }); }) } (有时只是double*)来在双精度位上使用按位运算符。

long long*

在我的计算机上,此代码显示:

long*