繁体   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