我被分配了一个问题,其中有人可能放入任何类型的有符号/无符号整数,并且两个函数必须使用按位运算等返回相应的最小值和最大值。
我正在尝试调整我所知道的关于两个补码的范围 - 范围由 - (2 n-1 )定义为(2 n-1 - 1)表示有符号值,0表示(2 n - 1表示无符号值。
但是,当我使用以下方法进行无符号时:
void create_minmax_unsigned() {
unknownun exponent = (sizeof(unknownun) * 8) - 1;
unknownun max = (1 << exponent) - 1;
printf("The max is %d", max);
}
签名:
void create_minmax_signed() {
unknowns exponent = (sizeof(unknowns) * 8) - 1;
unknowns min = ((1 << exponent) + 1) - 1;
unknowns max = (1 << exponent) - 1;
}
这种方法适用于char(un / s),short(un / s),int(un / s),long(un / s)但不长,即64位。
编辑:它实际上为所有int类型返回正确的位数。但是,对于long long
,它没有显示正确的范围。
答案 0 :(得分:0)
您不能只移动1 << (sizeof(signed type)*CHAR_BIT-1)
,因为这是未定义的行为(如果sizeof(signed type) >= sizeof(int)
)。另外,(x+1)-1
是什么? (提示:x
,除非x
是INT_MAX,在这种情况下它是未定义的)。所以这不会给你一个负数,是吗?
答案 1 :(得分:0)
long long
计算失败的原因是,分配的RHS计算为int
,并且您尝试按int
过大的值进行移位。
这个spiel逐步发展答案 - 只有最终的代码才真正可行。早期版本有各种问题需要解决,一次只能解决一个问题。
您需要将RHS强制转换为指定的类型:
void create_minmax_unsigned() {
unknownun exponent = (sizeof(unknownun) * 8) - 1;
unknownun max = ((unknownun)1 << exponent) - 1;
printf("The max is %d", max);
}
void create_minmax_signed() {
unknowns exponent = (sizeof(unknowns) * 8) - 1;
unknowns min = (((unknowns)1 << exponent) + 1) - 1;
unknowns max = ((unknowns)1 << exponent) - 1;
}
返回多个值时遇到问题。使用<inttypes.h>
和intmax_t
或uintmax_t
强制转换可以使您的打印代码更加强大:
void create_minmax_unsigned() {
unknownun exponent = (sizeof(unknownun) * 8) - 1;
unknownun max = ((unknownun)1 << exponent) - 1;
printf("The max is %" PRIuMAX, (uintmax_t)max);
}
void create_minmax_signed() {
unknowns exponent = (sizeof(unknowns) * 8) - 1;
unknowns min = (((unknowns)1 << exponent) + 1) - 1;
unknowns max = ((unknowns)1 << exponent) - 1;
printf("The max is %" PRIdMAX, (intmax_t)max);
printf("The min is %" PRIdMAX, (intmax_t)min);
}
到目前为止,这使得您的计算基本不变;它只是确保值的类型正确。但是,您的计算容易受到数字溢出的影响,这可能(非常)非常糟糕 - 它会导致带符号整数类型的未定义行为和无符号类型的错误答案。
对于无法使用较大类型来覆盖罪恶的无符号类型,您需要仔细创建2 n -1,因为2<sup>n</sup>
大于can存储,所以它看起来像0.当你减去1时,你会得到正确的答案,但你真的不需要移位/取幂。
void create_minmax_unsigned() {
unknownun max = (unknownun)0 - 1;
printf("The max is %" PRIuMAX, (uintmax_t)max);
}
对于签名类型,您不能使用2 n-1 - 1,因为无法表示2 n-1 。但是,您可以使用2 *(2 n-2 - 1)+ 1。负限制是减去一个值的值,导致:
未经测试的代码(错误):
void create_minmax_signed() {
unknowns exponent = (sizeof(unknowns) * 8) - 2;
unknowns max = 2 * ((unknowns)1 << exponent) + 1;
unknowns min = -max - 1;
printf("The max is %" PRIdMAX, (intmax_t)max);
printf("The min is %" PRIdMAX, (intmax_t)min);
}
经测试的代码(不是那么多错误):
#include <inttypes.h>
#include <stdio.h>
typedef signed long long unknowns;
void create_minmax_signed(void);
void create_minmax_signed(void)
{
unknowns exponent = (sizeof(unknowns) * 8) - 2;
unknowns max = 2 * (((unknowns)1 << exponent) - 1) + 1;
unknowns min = -max - 1;
printf("The max is %+" PRIdMAX "\n", (intmax_t)max);
printf("The min is %+" PRIdMAX "\n", (intmax_t)min);
}
int main(void)
{
create_minmax_signed();
return 0;
}
汇编:
/usr/bin/gcc -g -O3 -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wold-style-declaration -Werror mnx.c -o mnx
示例运行:
$ ./mnx
The max is +9223372036854775807
The min is -9223372036854775808
$