Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a safe way to get the unsigned absolute value of a signed integer, without triggering overflow?

Consider a typical absolute value function (where for the sake of argument the integral type of maximum size is long):

unsigned long abs(long input);

A naive implementation of this might look something like:

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

This code triggers undefined behavior, because the negation of input may overflow, and triggering signed integer overflow is undefined behavior. For instance, on 2s complement machines, the absolute value of std::numeric_limits<long>::min() will be 1 greater than std::numeric_limits<long>::max().

What can a library author do to work around this problem?

like image 780
Billy ONeal Avatar asked Jun 26 '13 07:06

Billy ONeal


People also ask

What is the advantage of unsigned integers over signed integers?

Both can store 256 different values, but signed integers use half of their range for negative numbers, whereas unsigned integers can store positive numbers that are twice as large. An n-bit unsigned variable has a range of 0 to (2n)-1.

Can unsigned integers overflow?

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

How do we distinguish a signed integer from one that is unsigned?

A signed integer is a 32-bit datum that encodes an integer in the range [-2147483648 to 2147483647]. An unsigned integer is a 32-bit datum that encodes a nonnegative integer in the range [0 to 4294967295]. The signed integer is represented in twos complement notation.

How do I convert signed to unsigned manually?

Mathematically, the conversion from signed to unsigned works as follows: (1) do the integer division of the signed integer by 1 + max , (2) codify the signed integer as the non-negative remainder of the division. Here max is the maximum integer you can write with the available number of bits, 16 in your case.


1 Answers

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.

like image 167
Billy ONeal Avatar answered Oct 02 '22 14:10

Billy ONeal