正确获取INT_MIN的绝对值的方法

时间:2012-09-01 21:29:52

标签: c

我想在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...
}

5 个答案:

答案 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_MAXsome_signed_value == INT_MIN,则很有趣。你必须单独测试这个案例。

答案 3 :(得分:1)

我想在unsigned中执行一些算术运算,并且需要取负int的绝对值,...

要处理学究案件:

|SOME_INT_MIN| 1 有一些特殊情况:

1。非二进制补码

这些天人们的补体和体征幅度很少见。

SOME_INT_MIN == -SOME_INT_MAXsome_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表示intlonglong longintmax_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;
          }
 }