1

Consider that the sign (+1 or -1) is known and there is a code that parses unsigned integer. That unsigned integer can be equal to -numeric_limits<int64_t>::max(). How to correctly compare without triggering undefined behavior?

int8_t sign = /* +1 or -1 */;
uint64_t result = /* parse the remaining string as unsigned integer */;
if( result > uint64_t(numeric_limits<int64_t>::max()))
{
    if(sign == 1) return false; // error: out of range for int64_t
    // Is the below code correct or how to implement correctly its intent?
    if(result == uint64_t(-numeric_limits<int64_t>::min()))
    {
        return true;
    }
    return false;
}
Serge Rogatch
  • 13,865
  • 7
  • 86
  • 158
  • shouldn't this be the usual case:`abs(numeric_limits::min()) == numeric_limits::max()`? then the second if will never evaluate to true. – m.s. Oct 26 '15 at 10:52
  • 1
    `-numeric_limits::min()` will miserably fail on most implementation since it will convert to something that is out of range (`-128` => `+128` for typical `int8`, which is not possible, so you'll probably get `0 `). – Holt Oct 26 '15 at 10:55
  • 1
    @m.s. In the usual case (2's complement) `abs(min) = max + 1`. When using ones' complement or sign-magnitude, `abs(min) = max`, and there is no problem, but this is the "esoteric" case. – anatolyg Oct 26 '15 at 10:56
  • @m.s., that is kind of my concern, but the following program stores correctly the negation of `numeric_limits::min()` in an `uint64_t`: https://ideone.com/uHIcCD . But that's just an example for that specific compiler, not a general rule. – Serge Rogatch Oct 26 '15 at 10:56
  • 1
    If you are assuming Two's complement (looks like for me?), then you should simply remove one from `result` and compare it to `max`. – Holt Oct 26 '15 at 10:58
  • Wrong order of operations -> `-uint64_t(numeric_limits::min())`. – Marc Glisse Oct 26 '15 at 12:04
  • @MarcGlisse, that way you would negate an unsigned integer. What do you expect to get? – Serge Rogatch Oct 26 '15 at 12:13
  • @SergeRogatch Don't let Microsoft's idiotic warnings confuse you, negating an unsigned integer is a perfectly fine operation, modulo 2^bitsize. – Marc Glisse Oct 27 '15 at 11:38

1 Answers1

3

As noted by Holt, you're effectively assuming 2's complement arithmetic. Therefore, you can replace -min by max+1:

if(result == uint64_t(numeric_limits<int64_t>::max()) + 1)

This avoids the undefined behavior (signed integer overflow) that results when negating the minimal value.

It might be a good idea to verify your system really uses 2's complement (depends on how strictly you want to comply with the C++ standard). This can be achieved by comparing -max with min:

if (numeric_limits<int64_t>::max() + numeric_limits<int64_t>::min() == 0)
{
    // If not two's complement:
    // Too large absolute value == error, regardless of sign
    return false;

    // on all sane (2's complement) systems this will be optimized out
}

There are no possibilities for other relations between min and max; this is explained here.

Community
  • 1
  • 1
anatolyg
  • 26,506
  • 9
  • 60
  • 134
  • It seems the code you gave should return `false` rather than `true` because it's not possible to represent such negative value in case `-min`==`max` – Serge Rogatch Oct 26 '15 at 11:40