13

考虑一个典型的绝对值函数(为了论证,最大大小的整数类型很长):

unsigned long abs(long input);

一个天真的实现可能看起来像:

unsigned long abs(long input)
{
    if (input >= 0)
    {
        // input is positive
        // We know this is safe, because the maximum positive signed
        // integer is always less than the maximum positive unsigned one
        return static_cast<unsigned long>(input);
    }
    else
    {
        return static_cast<unsigned long>(-input); // ut oh...
    }
}

此代码触发未定义的行为,因为input可能溢出的否定,触发有符号整数溢出是未定义的行为。例如,在 2s 补码机器上, 的绝对值std::numeric_limits<long>::min()将大于 1 std::numeric_limits<long>::max()

图书馆作者可以做些什么来解决这个问题?

4

2 回答 2

20

One can cast to the unsigned variant first. This provides well defined behavior. If instead, the code looks like this:

unsigned long abs(long input)
{
    if (input >= 0)
    {
        // input is positive
        return static_cast<unsigned long>(input);
    }
    else
    {
        return -static_cast<unsigned long>(input); // read on...
    }
}

we invoke two well defined operations. Converting the signed integer to the unsigned one is well defined by N3485 4.7 [conv.integral]/2:

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n where n is the number of bits used to represent the unsigned type). [ Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). — end note ]

This basically says that when making the specific conversion of going from signed to unsigned, one can assume unsigned-style wraparound.

The negation of the unsigned integer is well defined by 5.3.1 [expr.unary.op]/8:

The negative of an unsigned quantity is computed by subtracting its value from 2^n , where n is the number of bits in the promoted operand.

These two requirements effectively force implementations to operate like a 2s complement machine would, even if the underlying machine is a 1s complement or signed magnitude machine.

于 2013-06-26T07:11:03.320 回答
0

如果为负就加一个。

unsigned long absolute_value(long x) {
  if (x >= 0) return (unsigned long)x;
  x = -(x+1);
  return (unsigned long)x + 1;
}
于 2019-02-03T23:32:58.897 回答