reversing two's complement for 18bit int

让人想犯罪 __ 提交于 2019-12-02 08:55:38

The almost-portable way (with assumption that negative integers are natively 2s-complement) is to simply inspect bit 17, and use that to conditionally mask in the sign bits:

constexpr SomeType sign_bits = ~SomeType{} << 18;
int regularNum = twosCompNum & 1<<17 ? twosCompNum | sign_bits : twosCompNum;

Note that this doesn't depend on the size of your int type.

The constant 8192 is wrong, it should be 16384 = (1<<14).

int regularNum = (twosCompNum << 14) / (1<<14);

With this, the answer is correct, -12800.

It is correct, because the input (unsigned) number is 249344 (0x3CE00). It has its highest bit set, so it is a negative number. We can calculate its signed value by subtracting "max unsigned value+1" from it: 0x3CE00-0x40000=-12800.

Note, that if you are on a platform, for which right signed shift does the right thing (like on x86), then you can avoid division:

int regularNum = (twosCompNum << 14) >> 14;

This version can be slightly faster (but has implementation-defined behavior), if the compiler doesn't notice that division can be exactly replaced by a shift (clang 7 notices, but gcc 8 doesn't).

Two problems: first your test input is not an 18-bit two's complement number. With n bits, two's compliment permits -(2 ^ (n - 1)) <= value < 2 ^ (n - 1). In the case of 18 bits, that's -131072 <= value < 131071. You say you input 249344 which is outside of this range and would actually be interpreted as -12800.

The second problem is that your powers of two are off. In the answer you cite, the solution offered is of the form

mBitOutput = (mBitCast)(nBitInput << (m - n)) / (1 << (m - n));

For your particular problem, you desire

int output = (nBitInput << (32 - 18)) / (1 << (32 - 18));
// or equivalent
int output = (nBitInput << 14) / 16384;

Try this out.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!