我想在unsigned中执行一些算术,并且需要取负值int的绝对值,比如
do_some_arithmetic_in_unsigned_mode(int some_signed_value)
{
unsigned int magnitude;
int negative;
if(some_signed_value<0) {
magnitude = 0 - some_signed_value;
negative = 1;
} else {
magnitude = some_signed_value;
negative = 0;
}
...snip...
}
但是INT_MIN可能有问题,0 - 如果在带符号算术中执行,INT_MIN是UB。 什么是在C中执行此操作的标准/健壮/安全/有效方式?
编辑:
如果我们知道我们是2补码,那么隐式转换和显式位操作可能是标准的吗?如果可能的话,我想避免这种假设。
do_some_arithmetic_in_unsigned_mode(int some_signed_value)
{
unsigned int magnitude=some_signed_value;
int negative=some_signed_value<0;
if (negative) {
magnitude = (~magnitude) + 1;
}
...snip...
}
答案 0 :(得分:22)
从有符号到无符号的转换是明确定义的:您得到相应的代表模2 N 。因此,以下内容将为您提供n
的正确绝对值:
int n = /* ... */;
unsigned int abs_n = n < 0 ? UINT_MAX - ((unsigned int)(n)) + 1U
: (unsigned int)(n);
更新:正如@ aka.nice建议的那样,我们实际上可以用UINT_MAX + 1U
替换0U
:
unsigned int abs_n = n < 0 ? -((unsigned int)(n))
: +((unsigned int)(n));
答案 1 :(得分:6)
在否定的情况下,请some_signed_value+1
。否定它(这是安全的,因为它不能是INT_MIN
)。转换为无符号。然后添加一个;
答案 2 :(得分:2)
您始终可以测试>= -INT_MAX
,这总是很明确。唯一的情况是,如果INT_MIN < -INT_MAX
和some_signed_value == INT_MIN
,则很有趣。你必须单独测试这个案例。
答案 3 :(得分:1)
我想在
unsigned
中执行一些算术运算,并且需要取负int
的绝对值,...
要处理学究案件:
|SOME_INT_MIN|
1 有一些特殊情况:
1。非二进制补码
这些天人们的补体和体征幅度很少见。
SOME_INT_MIN == -SOME_INT_MAX
和some_abs(some_int)
的定义很明确。这是简单的情况。
#if INT_MIN == -INT_MAX
some_abs(x); // use matching abs, labs, llabs, imaxabs
#endif
2。 SOME_INT_MAX == SOME_UINT_MAX
,2的补语
C允许整数类型的 signed 和 unsigned 版本的最大值相同。这些天很少见。
2种方法:
1)使用较宽的整数类型(如果存在)。
#if -INTMAX_MAX <= SOME_INT_MIN
imaxabs((intmax_t)x)
#endif
2)使用宽(st)浮点(FP)类型。
转换为宽FP将适用于SOME_INT_MIN
(2的补码),因为该值是-(2的幂)。对于其他较大的负数,强制转换可能会失去一个宽整数而不是那么宽long double
的精度。例如。 64位long long
和64位long double
。
fabsl(x); // see restriction above.
3。 SOME_INT_MAX < SOME_UINT_MAX
这是@Kerrek SB的答案的常见案例。下面也处理情况1。
x < 0 ? -((unsigned) x) : ((unsigned) x);
高级替代方案
在代码执行.... + abs(x)
的情况下,一个明确定义的替代方法是减去负绝对值:.... - nabs(x)
。或像abs(x) < 100
中一样,使用nabs > -100
。
// This is always well defined.
int nabs(int x) {
return (x < 0) x : -x;
}
1 SOME_INT
表示int
,long
,long long
或intmax_t
。
答案 4 :(得分:0)
static unsigned absolute(int x)
{
if (INT_MIN == x) {
/* Avoid tricky arithmetic overflow possibilities */
return ((unsigned) -(INT_MIN + 1)) + 1U;
} else if (x < 0) {
return -x;
} else {
return x;
}
}