views:

255

answers:

7

What is the fastest way of checking the condition

l + 1 < r

for int l,r in Java?

l and r are not constant and I know that l <= r. The comparison is a stopping condition for a while loop in a binary search implementation. I am of course benchmarking my code, both in a separate test (searching a large array) and in the code which uses it.

What I am looking for, I imagine, is some sort of a bit operation which would be faster than the present condition. But I don't know.

+4  A: 

I think that's probably as fast as it's going to get. That'll reduce to very simple bytecode, and the JIT (just-in-time compiler) will probably reduce that to a very simple native implementation.

(Unrelated: interesting to see a 'quant dev' use Java btw. Doesn't happen that often)

Brian Agnew
If you're downvoting, please indicate why
Brian Agnew
Yes, we lose some performance compared to C++, but we're not into algo trading and Java has many benefits over C++. And performance is often database-bound, anyway...
quant_dev
+10  A: 

This kind of micro-optimization is almost always a bad idea; your performance for such a small bit will be entirely dependent on how the hotspot compiler optimizes your code, and subtle cache effects having to do with the surrounding code.

Daniel Martin
I've done such micro-optimizations in Java before and achieved good results.
quant_dev
A: 

What all these guys said. The compiler is going to optimize that away for you. Write it so it looks and reads properly to you and move on.

K-Boo
+2  A: 

Well the underlying comparison must either:

add 1 to l, compare the result to r

or

subtract 1 from r and compare the result to l

All modern hardware will have the same raw performance for either operation (where addition and subtraction of any native data type has identical performance in terms of cycles to complete and pipeline side effects).

The only way this will have any effect is if:

one of l or r are known constants at compile time. eg.

l + 1 < 5
5 + 1 < r

in this case a poor optimizing compiler may not realise it can convert the first into l < 4

but all java compilers are required to spot that the second case is 6 < r

The other is if the data types of l and r are different.

The operation of :

  1. floating point addition/subtraction then comparison to an int
    verses
  2. integral addition/subtraction then comparison with a double may be different.

It is fair to say that the chances of this being a serious issue in your application are negligible since the cycle cost of any of these is tiny compared to the pipeline hit of any branch mispredictions associated with the decision.

Also a decent JIT may do all sorts of optimizations in relation to the surrounding code that outweigh the micro optimization performed.

ShuggyCoUk
This comparison is in a loop which is the main part of a method which is run many, many times in my code.
quant_dev
Again - it is not the comparison that is the slowdown, it a combination of: pulling in l and r (or one of them) into your cache and the poor branch perdiction behaviour of searches like this.
ShuggyCoUk
Just because a sampling/instrumenting profiler says that you spend most of your time 'on that line' does not mean that you spent that time *executing* that code. I suggets investing in a profiler that lets you sample on cache misses or branch mispredicts. You job should allow for that sort of investment (if it doesn't you need a batter employer)
ShuggyCoUk
I get the point about branch prediction, but unfortunately most of the time I am doing binary search on arrays with length >20, so I doubt a linear search (without branch prediction problems) would have been faster.My employer doesn't like spending money, but thanks to that we have no cashflow problems now, despite the crisis :D
quant_dev
I'd benchmark it if I were you, you might find you can go beyond 20 and still be faster.Also note that the way you write the Binary part of the BinarySearch can affect the performance (since the calculation of the next index to check can be done well (no branches) or badly (with braches)
ShuggyCoUk
Btw, can you recommend a profiler for Java which samples cache misses and/or branch mispredicts?
quant_dev
I cannot recommend it (no experience) but the only one I know of is AMD's CodeAnalyst http://developer.amd.com/documentation/articles/Pages/32120a07151.aspx
ShuggyCoUk
A: 

Your best bet is to tweak the JVM rather than the code - given that this is your bottleneck.

Try starting the jvm with the arguments -server -XX:+AggressiveOpts.

Robert Munteanu
I have little control over the JVM arguments used to run production code.
quant_dev
+2  A: 

Have a variable lr1 which always equals (l - r + 1). Whenever you increment or decrement l, do the same to lr1. Similarly for r.

Then your test becomes (lr1 < 0), and the instructions to modify lr1 are executed no more often than necessary.

I feel a little silly giving you a micro-optimization, which in most cases is penny-wise, pound-foolish. Like if you're comparing strings, it will totally swamp that test.

ADDED: Since you're doing binary search, I would mention Jon Bentley's cool unrolling of binary search. First you pad the table A up to a power of 2, like 1024. Then you write something like this:

i = 0;
if (X >= A[i+512]) i += 512;
if (X >= A[i+256]) i += 256;
   . . .
if (X >= A[i+  1]) i +=   1;

and finally test if (X == A[i]). Or, if you don't want to pad it, let the if statements be something like
if (i+512 < N && X >= A[i+512]) i += 512;

Mike Dunlavey
A: 

How about moving your equality test outside of the while loop, so you check .equals() only after termination. btw I couldn't find any bit twiddling ways to test whether l+1<r. If your array lengths are known to be less than certain sizes, what if you use a different datatype for indices? char/short/byte?

Ron
What equality test?
quant_dev