1

Why, given:

int a = ..., b = ... ;

is this unsafe:

a - b

but this is safe:

a > b

By safe I mean guaranteed not to be affected by overflows (I'm writing a Comparator of ints).

Kiel
  • 271
  • 3
  • 10
  • If `a` is positive and `b` is negative and their difference is bigger than MAX_INTEGER, the overflow. – Sotirios Delimanolis Sep 05 '13 at 21:18
  • yes, please focus on the second part (`a>b`) – Kiel Sep 05 '13 at 21:18
  • There's no possibility to overflow since you aren't adding or subtracting anywhere or multiplying/dividing, just comparing. – Sotirios Delimanolis Sep 05 '13 at 21:20
  • how is comparison of ints implemented then? – Kiel Sep 05 '13 at 21:21
  • catch the overflow and `return a > 0` – cmd Sep 05 '13 at 21:21
  • 3
    *I'm writing a Comparator of ints* do not reinvent the wheel, use `Integer#compare(int a, int b)` – Luiggi Mendoza Sep 05 '13 at 21:21
  • @LuiggiMendoza please focus on the question :) – Kiel Sep 05 '13 at 21:21
  • @Kiel Perhaps the underlying native code for comparison doesn't restrict the type to 4 bytes. You are [correct](http://en.wikibooks.org/wiki/Microprocessor_Design/ALU_Flags) in saying `>` uses subtraction. – Sotirios Delimanolis Sep 05 '13 at 21:23
  • 1
    From [JSL 15.20.1. Numerical Comparison Operators <, <=, >, and >=](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.1): *Binary numeric promotion is performed on the operands ... If the promoted type of the operands is int or long, then signed integer comparison is performed.* what don't you exactly understand? And by my last comment, I focused on the question: **do not reinvent the wheel**! – Luiggi Mendoza Sep 05 '13 at 21:28
  • how is it performed so that it doesn't overflow. Please reread the question - it's "Why is comparing ints safe in Java?", not "How to write a comparator". – Kiel Sep 05 '13 at 21:28
  • Why do you assume that a subtraction would be performed during a `>` operator? The answer to your question is that "The spec says so." – recursive Sep 05 '13 at 21:29
  • Because atm I have no idea how to do this other way, plus i've seen this approach in asm code many times – Kiel Sep 05 '13 at 21:30
  • This is mostly done by the JVM implementation. So, to get an *exact* answer you could review how HotSpot implements this, but you can't be sure since JRockit and IBM JVM can implement it in another way (just to mention some of them). – Luiggi Mendoza Sep 05 '13 at 21:32
  • [This is an old JVM spec document](http://docs.oracle.com/javase/specs/jvms/se5.0/html/Overview.doc.html) but it might be useful to you. See section `3.11.3 Arithmetic Instructions` – Sotirios Delimanolis Sep 05 '13 at 21:33
  • @Kiel: I'm curious. Can you think of a way to implement it using a subtraction? If so, what is it? – recursive Sep 05 '13 at 21:33
  • (afaik) intel cpu does comparison with `SUB`s, using both signed and usigned math – Kiel Sep 05 '13 at 21:43
  • 1
    @Kiel Intel has lots of different CPU's. Maybe the old 4004 used SUB for comparison ... but every CPU I've seen since after about 1970 has comparison instructions. Plus, any compiler that does implement > as a subtract instruction would be smart enough to generate code that doesn't fault on overflow, so any intermediate overflows would be dealt with internally and hidden from the programmer. – ajb Sep 05 '13 at 22:12
  • I think the difference is that when using `<` the comparison is done by JVM who can check the state of overflow flag after `CMP`, while when you do `-` you can not determine if there was an overlfow – Katona Sep 05 '13 at 22:14
  • @ajb *to generate code that doesn't fault on overflow* - yeaah, this is what I'd expected to see in an answer - the code ;] – Kiel Sep 06 '13 at 06:01

2 Answers2

2

The comparison a > b is itself safe, because neither a nor b are changed. The operation a - b can be unsafe because overflow is possible.

However, a previous overflow may affect the correctness of such a comparison a > b done later. Subtracting a really large negative number will result in overflow, in that the result can be less than the original number (in math, subtracting a negative number should increase the original number), meaning a > b may be an unexpected result.

If a - b is used in a Comparator, at first it looks like it satisfies the contract of Comparator: return a number less than zero, equal to zero, or greater than zero if the value is less than, equal to, or greater than another value. But that's only true if overflow does not occur.

If a = 1000 and b = Integer.MIN_VALUE + 100 (a very large negative number, -2147483548), then a - b will overflow. The true mathematical result would be 500 - Integer.MIN_VALUE, a value larger than Integer.MAX_VALUE (2147484548). So the positive return value would indicate that a > b, which is obviously true.

But with overflow, the value winds up being less than zero (-2147482748), erroneously indicating that a < b.

rgettman
  • 176,041
  • 30
  • 275
  • 357
1

Well it depends... See System.nanoTime(), which recommends t1 - t0 < 0, not t1 < t0 for time comparison...

ZhongYu
  • 19,446
  • 5
  • 33
  • 61
  • I think this is not because `<` can overflow but because of the nature of the value of `System.nanoTime()`, see this answer: http://stackoverflow.com/a/18414157/594406 – Katona Sep 05 '13 at 22:21