簡體   English   中英

負數:如何將signed int中的符號位更改為0?

[英]Negative numbers: How can I change the sign bit in a signed int to a 0?

我在想這個世界是有效的,但事實並非如此:

int a = -500;
a = a << 1;
a = (unsigned int)a >> 1;
//printf("%d",a) gives me "2147483148"

我的想法是左移會移除最左邊的符號位,所以右移它作為無符號整數將保證它是一個邏輯移位而不是算術。 為什么這不正確?

也:

int a = -500;
a = a << 1;
//printf("%d",a) gives me "-1000"

TL; DR:最簡單的方法是使用<stdlib.h>abs函數。 答案的其余部分涉及在計算機上表示負數。

負整數(幾乎總是)以2的補碼形式表示 (見下面的注釋)

獲得數字否定的方法是:

  1. 取整數的二進制表示(包括數據類型的前導零,除了將用作符號位的MSB)。
  2. 取上述數字的1的補碼。
  3. 在1的補碼中加1
  4. 前綴符號位

500為例,

  1. 取二進制表示500_000 0001 1111 0100_是符號位的占位符)。
  2. 取1的補碼/倒數: _111 1110 0000 1011
  3. 在1的補碼中加1_111 1110 0000 1011 + 1 = _111 1110 0000 1100 當您將符號位替換為零時,這與您獲得的2147483148相同。
  4. 前綴0表示正數, 1表示負數: 1111 1110 0000 1100 (這與上面的2147483148不同。你得到上述值的原因是因為你獲得了MSB)。

反轉標志是一個類似的過程。 如果您使用16位或32位數字導致您看到的大值,那么您將得到領先的數字。 在每種情況下LSB應該相同。

注意:有些機器具有1的補碼表示,但它們是少數。 2的補碼通常是首選,因為0具有相同的表示,即-00在2的補碼表示法中表示為全零。

左移負整數調用未定義的行為,因此您不能這樣做。 你可以使用你的代碼,如果你做a = (unsigned int)a << 1; 你得到500 = 0xFFFFFE0C ,左移1 = 0xFFFFFC18

a = (unsigned int)a >> 1; 確實保證邏輯移位,所以你得到0x7FFFFE0C 這是小數2147483148。

但這是不必要的復雜。 更改符號位的最佳和最便攜的方法是a = -a 任何其他代碼或方法都值得懷疑。

但是如果你堅持做點蠢事,你也可以做點什么

(int32_t)a & ~(1u << 31)

這可以移植到32位系統,因為(int32_t)保證二進制補碼,但1u << 31假設32位int類型。

演示:

#include <stdio.h>
#include <stdint.h>

int main (void)
{
  int a = -500;
  a = (unsigned int)a << 1;
  a = (unsigned int)a >> 1;
  printf("%.8X = %d\n", a, a);

  _Static_assert(sizeof(int)>=4, "Int must be at least 32 bits.");
  a = -500;
  a = (int32_t)a & ~(1u << 31);
  printf("%.8X = %d\n", a, a);

  return 0;
}

當您放入“另外”部分時,在第一次左移1位后,DOES按預期反映-1000。

問題在於你的轉換為unsigned int。 如上所述,負數表示為2的補碼,意味着符號由最左位(最高有效位)確定。 當轉換為unsigned int時,該值不再表示符號,但會增加int可以采用的最大值。

假設32位整數,MSB用於表示-2 ^ 31(= -2147483648),現在在無符號整數中表示正2147483648,增加2 * 2147483648 = 4294967296.將此值添加到原始值-1000並且您得到4294966296.右移將此除以2,然后到達2147483148。

希望這可能會有所幫助:( 使用C二進制表示中打印一個int修改打印函數)

void int2bin(int a, char *buffer, int buf_size) {
    buffer += (buf_size - 1);

    for (int i = buf_size-1; i >= 0; i--) {
        *buffer-- = (a & 1) + '0';

        a >>= 1;
    }
}

int main() {
    int test = -500;
    int bufSize = sizeof(int)*8 + 1;
    char buf[bufSize];
    buf[bufSize-1] = '\0';
    int2bin(test, buf, bufSize-1);
    printf("%i (%u): %s\n", test, (unsigned int)test,  buf);
    //Prints:   -500 (4294966796): 11111111111111111111111000001100


    test = test << 1;
    int2bin(test, buf, bufSize-1);
        printf("%i (%u): %s\n", test, (unsigned int)test, buf);
    //Prints:   -1000 (4294966296): 11111111111111111111110000011000


    test = 500;
    int2bin(test, buf, bufSize-1);
    printf("%i (%u): %s\n", test, (unsigned int)test, buf);
    //Prints:   500 (500): 00000000000000000000000111110100


    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM