反转二进制补码为18bit int

时间:2018-08-17 01:59:18

标签: c++ twos-complement

我有一个18的整数,该数字为2的补码,我想将其转换为带符号的数字,以便更好地使用它。在我使用的平台上,整数是4字节(即32位)。根据这篇文章:

Convert Raw 14 bit Two's Complement to Signed 16 bit Integer

我尝试了以下方法来转换数字:

using SomeType = uint64_t;
SomeType largeNum = 0x32020e6ed2006400;
int twosCompNum = (largeNum & 0x3FFFF);
int regularNum = (int) ((twosCompNum << 14) / 8192);

我将数字左移14位以使符号位成为最高有效位,然后除以8192(二进制,是1,然后是13个零)以恢复幅度(如以上文章中所述)。但是,这似乎对我不起作用。例如,输入249344给我-25600,表面上看来并不正确。我在做什么错了?

3 个答案:

答案 0 :(得分:1)

常量8192是错误的,应该为16384 = (1<<14)

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

这样,答案是正确的,-12800

这是正确的,因为输入(无符号)号是249344(0x3CE00)。它设置了最高位,所以它是一个负数。我们可以通过从中减去“最大无符号值+1”来计算其有符号值:0x3CE00-0x40000=-12800

请注意,如果您在平台上进行正确的符号移位(例如在x86上)可以执行正确的操作,则可以避免除法:

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

如果编译器没有注意到可以用shift完全代替除法(clang 7表示,但gcc 8则没有),则该版本可能会稍快一些(但具有实现定义的行为)。

答案 1 :(得分:1)

几乎可移植的方式(假设负整数本身就是2s补码)是简单地检查第17位,并使用它有条件地屏蔽符号位:

true

请注意,这与您的false类型的大小无关。

答案 2 :(得分:0)

两个问题:首先,您的测试输入不是18位二进制补码。使用n位,二进制的补码允许-(2 ^ (n - 1)) <= value < 2 ^ (n - 1)。如果是18位,则为-131072 <= value < 131071。您说您输入的249344不在此范围内,实际上将被解释为-12800

第二个问题是您的2的幂都关闭了。在您引用的答案中,提供的解决方案的格式为

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

对于您的特定问题,您渴望

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

尝试一下。