2

我在尝试通过提取位字符串的一部分来对数字进行符号扩展时遇到问题。当它是负数时,这有问题,它将数字环绕到正侧。这是我的代码:

//  printf("add1 \n");
unsigned short r1 = (instruction>>6)&7;
signed short amount = (instruction& 31);   //right here! i am trying to get the last 5 bits and store it in a register but i can't figure out how to make it negative if it is negative
//  printf("\namount is %d \n", amount);
unsigned short dest = (instruction>>9)&7;
state->regs[dest] = state->regs[r1]+amount;
setCC(state,state->regs[r1]+amount);
4

5 回答 5

3

对于位模式,使用十六进制常量而不是十进制通常更容易。

signed short amount = (instruction & 0x1F);

然后对数字进行符号扩展,检查符号位(假设这里的符号位是提取的 5 个位中的最左侧)。如果已设置,请进行二进制反转并加 1。取 5 位值的 2 的补码(取反并加一),然后取全角结果的 2 的补码(取反并加 1)。

if (amount & 0x10)
    amount = ~(amount^0x1F + 1) + 1;

例如。

             5-bit "bitfield"
             X XXXX
0000 0000 0001 1111
0000 0000 0000 0000 invert x ^ 0x1F (= 1 1111)
0000 0000 0000 0001 add 1
1111 1111 1111 1110 invert ~
1111 1111 1111 1111 add 1

0000 0000 0001 0000
0000 0000 0000 1111 invert x ^ 0x1F (= 1 1111)
0000 0000 0001 0000 add 1
1111 1111 1110 1111 invert ~
1111 1111 1111 0000 add 1

哎呀。更简单:

-(x^0x1F + 1)  Assuming the machine operates with 2's-complement

0000 0000 0001 0110
0000 0000 0000 1001 invert
0000 0000 0000 1010 add 1 (yielding the full-width absolute value)
1111 1111 1111 0110 negate
于 2013-04-25T17:27:10.597 回答
2

使用位域:

union {
      int a;
      struct {
         int a:5;
         int b:3;
         unsigned int c:20;
      } b;
} u = 0xdeadbeef;

int b = u.b.b;  // should sign extend the 3-bit bitfield starting from bit 5
于 2013-04-25T17:33:17.110 回答
1

来自 Hacker's Delight 2-6。假设 5 位数据必须进行符号扩展(符号位的值为 16)。

最佳情况:如果高位全为零:

(i ^ 16) - 16

下一个最佳情况(与 OP 一样instruction):如果高位包含必须丢弃的数据:

(i & 15) - (i & 16)
于 2018-08-08T15:39:05.073 回答
1

以下是无需测试即可对 5 位二进制补码值进行签名扩展的方法:

int amount = (instruction & 31) - ((instruction & 16) << 1);

更一般地说,如果字段宽度为n,非零且小于 中的位数int,您可以编写:

int amount = (instruction & ~(~1U << (n - 1) << 1)) -
             ((instruction & (1U << (n - 1)) << 1);
于 2017-07-18T16:22:28.257 回答
0

您可以检查符号位并相应地修复结果:

int width_of_field = 5;
signed short amount = (instruction& 31);
if (amount & (1 << width_of_field >> 1)) // look at the sign bit
{
    amount -= 1 << width_of_field; // fix the result
}

或者,使用左移后右移:

width_of_field = 5;
signed short amount = (instruction& 31);
// It is possible to omit the "& 31", because of the left shift below
amount <<= 16 - width_of_field;
amount >>= 16 - width_of_field;

注意:必须使用两个语句来避免提升到int(大概有 32 位)的影响。

于 2013-04-25T19:28:32.050 回答