Hacker News new | ask | show | jobs
by seivadmas 4191 days ago
WTF? The article states:

  x = 1987654321 and y = -1987654321? Then the difference between them is -319658654 (negative) which proves that x is less than y. That’s less than correct.
Which is completely 100% wrong. Surely the difference would be x - y i.e (1987654321 - (-1987654321)) = (1987654321 + 1987654321) = 3975308642.

Which is perfectly ok, because that's positive and so proves x is greater than y. So this comparison works just fine for negative integers...

3 comments

(int32_t)3975308642 == -319658654

Overflow makes intuitive arithmetic do unusual things.

Similarly, using a+b/2 for binary search midpoints is wrong. http://googleresearch.blogspot.com/2006/06/extra-extra-read-...

The writer assumes that the reader understands and knows about how integer overflows work in C.
Exactly, don't use subtraction for comparison in C.

The previous commenter may have entered that into say, a Python console where it wouldn't exhibit that behavior.

Don't use subtraction for comparison in any language that uses floating-point (like Lua or JS) or silent overflow (like, typically, C, C++, Java, and C#). There are a few languages, like Python, where integer subtractions that overflow will transparently produce bignums, but they are kind of the exception.
Ah I see the problem. Actually I used a Ruby console.

So what then is the CORRECT way of doing this comparison in C, avoiding potential overflow pitfalls?

The correct way to do a comparison is to use a comparison operator...... If x< y etc...

    return (x > y) - (x < y);
That can be very expensive operation. Potentially two branches, not counting return from subroutine.
If performance really is of concern, qsort() or similar functions probably shouldn't be used. Instead a dedicated function, which allows to choose a specific algorithm (qsort() doesn't have to use quicksort) and also doesn't involve calling a comparison function pointed to by a function pointer, can be used.
I would hope that on modern compilers on modern architectures, this would be done with zero branches. That is the case in a quick test on my machine (gcc 4.6.3).
The simplest way to implement that would be two SETxx instructions and a subtract on 386+, SLT/SGT on MIPS, two subtracts (or one compare and one subtract) and two predicated moves on ARM. No branching required at all.
Not really. Maybe on an old atom.
Exactly, don't use subtraction for comparison in C.... when the difference might exceed 2^31.

For many data types, like time, that will normally never happen, making subtraction the safest no-brainpower-needed approach. If in doubt, use the next larger integer type.

If you ever want to make a vulnerability researcher drool visibly, have a C programmer say, "that will normally never happen, making ${XXX} the safest no-brainpower-needed approach".
Actually, with time, the sign of (iXX)((uXX)x-(uXX)y) is the "odometer comparison" of x and y, which handles overflow more gracefully than the typical < comparison.
You know what causes bugs in C (besides memory leaks)? Complex or clever expressions that don't reveal their semantics at first glance. As an example from elsewhere in the thread:

    return (x > y) - (x < y);
Quick. What's that do?

What will the next person who looks at the code think it does?

If it's in a function called "cmp", I think they will guess.
A C programmer should know that comparisons evaluate to 1 for true and 0 for false.
It returns 1 - 0 if x > y, 0 - 1 if x < y, and 0 - 0 if x == y.

Duh.

Yeah but that's what happens when people become so adapted to their tools that they forget how real math/world works... and they even have the nerve to stand up for their flawed tools.

I actually like and use C everyday, but it would be aberrant for me to say essentially what the article implies: "A math algorithm is wrong because it doesn't work in C"