C查找最大二进制补码整数

时间:2018-10-17 15:45:03

标签: c binary twos-complement

我的任务是找到最大的2的补码整数或TMax。我完全不知道该怎么做。我知道正确的值是0x7fffffff或2147483647,但我不知道如何确切地获得此结果。这是32位整数的最大数目。我不能使用函数或条件,最多只能使用4个操作。任何人都可以尝试帮我解释一下吗?我知道找到某个位数的最大数量的方法是2 ^(bits-1)-1,所以2 ^(31)-1 = 2147483647

4 个答案:

答案 0 :(得分:1)

假设您知道您的计算机使用二进制补码表示法,那么您将以标准兼容的方式这样做:

unsigned int x = ~0u;
x >>= 1;
printf("max int = %d\n", (int)x);

通过使用unsigned int,可以防止由于右移负值而导致的任何实现定义的行为。

答案 1 :(得分:1)

  

找到最大二进制补码

int TMax = -1u >> 1找到最大的-1u/2

时,

INT_MAX == UINT_MAX/2int就足够了

即使int被编码为2的补码或现在稀有的1s补码或符号幅度,此“操作”也有效。


更好用

#include <limits.h>
int TMax = INT_MAX;

其他技巧可能涉及未定义,实现定义,未指定的行为,最好在C语言中避免。

答案 2 :(得分:1)

在两种情况下,您可能正在寻找最大正数,要么是给定整数数据类型,要么是给定位数。也是两个解决方案。

向右填充并向右移动

使用大小与所需的二进制补码数据类型的大小完全匹配的整数数据类型,您也许可以通过以下方式解决问题:

(unsigned 'type') ^0)>>1 

或等效地

(unsigned 'type') ^0)/2.

例如,在short为16位的计算机上,

(unsigned short) ^0   ==>  0xFFFF  (65535)
((unsigned short) ^0 ) >> 1  ==>  0x7FFF  (32767)

在32位数据类型上,此方法为我们提供0x7FFFFFFF(2147483647)。

在C中,整数类型仅具有最小大小,即c.f。 int 可以为16位,32位或更大。但是,计算中使用的字长必须与预期目标的字长完全匹配。

此外,请注意数据必须是无符号类型。有符号类型的右移通常实现为符号扩展移位(将符号位复制到结果中)。

仅设置符号位并减去1

第二种技术适用于等于或大于所需二进制补码字长的位数的任何字长,

(unsigned integer_type) 1<<(n-1)-1

例如,在任何大于或大于16的整数字长中,我们可以找到16的TMAX为

(unsigned integer_type) 1<<15  ==>  binary 1000 0000 0000 0000  (0x8000)
(unsigned integer_type) (1<<15 - 1) == > 0111 1111 1111 1111 (0x7FFF)

这很健壮,几乎可以在任何提供适当字长的情况下使用。

如果计算中的字长是目标的字长,则必须再次对计算的数据类型进行无符号签名。对于较大的单词,这不是必需的。

示例

在第一个示例中,我们显示了第二种方法适用于32位,使用long或long long类型。

#include <stdio.h>

int main() {

  printf( "%ld\n", (long) ( ( ((unsigned long) 1)<<31 ) - 1 ) );
  printf( "%lld\n", (long long) ( ( ((unsigned long long) 1)<<31 ) - 1 ) );

}

输出:

2147483647
2147483647

在这里,我们展示了第一种方法,即从int设置的所有位开始向右移,当int不完全是32位时,该方法将失败,如上所述,在C中无法保证。

#include <stdio.h>

int main() {

  printf( "from long long %lld  (%zu bits)\n", ( (unsigned long long) ~0 )>>1,
      sizeof(unsigned long long)*8 );

  printf( "from long %ld  (%zu bits)\n",  ( (unsigned long) ~0 )>>1,
      sizeof(unsigned long)*8  );

  printf( "from int %d  (%zu bits)\n",  ( (unsigned int) ~0 )>>1,
      sizeof(unsigned int)*8  );

  printf( "from short %d  (%zu bits)\n",  ( (unsigned short) ~0 )>>1,
      sizeof(unsigned short)*8  );
}

输出:

from long long 9223372036854775807  (64 bits)
from long 9223372036854775807  (64 bits)
from int 2147483647  (32 bits)
from short 32767  (16 bits)

同样,请记住,C语言仅保证任何整数数据类型的最小大小。 int 可以为16位或32位或更大,具体取决于您的平台。

答案 3 :(得分:0)

感谢大家的帮助!事实证明我不能使用宏,无符号或long。我来到了这个解决方案:

~(1 << 31)

这会生成正确的输出,所以我将留给它!