18

我想在无符号中执行一些算术运算,并且需要取负整数的绝对值,例如

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-complement 中,那么隐式转换和显式位操作可能是标准的吗?如果可能的话,我想避免这种假设。

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...
}
4

5 回答 5

26

从有符号到无符号的转换是明确定义的:您得到相应的代表模 2 N。因此,以下将为您提供正确的绝对值n

int n = /* ... */;

unsigned int abs_n = n < 0 ? UINT_MAX - ((unsigned int)(n)) + 1U
                           : (unsigned int)(n);

更新:正如@a​​ka.nice 建议的那样,我们实际上可以替换UINT_MAX + 1U0U

unsigned int abs_n = n < 0 ? -((unsigned int)(n))
                           : +((unsigned int)(n));
于 2012-09-01T21:36:14.217 回答
6

在否定的情况下,取some_signed_value+1。否定它(这是安全的,因为它不可能INT_MIN)。转换为无符号。然后加一个;

于 2012-09-01T21:49:45.833 回答
2

你总是可以测试>= -INT_MAX,这总是很好定义的。对您来说唯一有趣的情况是 ifINT_MIN < -INT_MAX和 that some_signed_value == INT_MIN。您必须单独测试该案例。

于 2012-09-01T21:36:29.137 回答
1

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

处理迂腐案件:

1有一些特殊情况|SOME_INT_MIN|

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 允许整数类型的有符号无符号版本的最大值相同。这些天很少见到这种情况。

2 种方法:
1)使用更广泛的整数类型(如果存在)。

#if -INTMAX_MAX <= SOME_INT_MIN
imaxabs((intmax_t)x)
#endif

2)使用宽(st)浮点(FP)类型。
转换为宽 FP 将适用于SOME_INT_MIN(2 的补码),因为该值为 -(power-of-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 longintmax_t

于 2020-04-15T19:28:12.543 回答
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;
          }
 }
于 2015-07-05T18:50:50.617 回答