在给定整数数据类型或给定位数的情况下,您可能会在两种情况下寻找最大正数。这也是两种解决方案。
填充并向右移动
使用与所需二进制补码数据类型的大小完全匹配的整数数据类型,您可以通过以下方式解决问题
(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 不完全是 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 位或更大,具体取决于您的平台。