views:

593

answers:

7

Hi This was the question asked in my interview Which one is faster in java and why?

  1. Math.max(a,b);
  2. (a>b)?a:b
+12  A: 

Math.max(a, b) is a static function (meaning no virtual call overhead) and will likely be inlined by the JVM to the same instructions as (a > b) ? a : b.

dsimcha
The compiler does not inline JVM instructions, the JIT profiler inlines the machine code :)
BlueRaja - Danny Pflughoeft
@BlueRaja: I've edited my response, since technically you're right (I think), but it's really a minor detail in the context of the question.
dsimcha
IIRC, the JIT won't actually perform any optimization until the block in question has been executed many (thousands?) times. The only safe answer to performance questions (especially in Java) is: "It depends..."
TMN
@TMN: Ok, but assuming you're looking for a **practical** response rather than a legalese response, why would you ever optimize function call overhead for something that's getting called that infrequently?
dsimcha
Since the question was asked during an interview, I assumed that they were looking for a "legalese"-type response. One possible case could be if you're trying to optimize a last-chance exception handler that should never be invoked, but has to execute quickly if it ever is. I just made that up; of course, in the real world you don't worry about trivial optimizations like that.
TMN
+13  A: 

Here is the code for Math.max() in Java:

public static int max(int a, int b) {
    return (a >= b) ? a : b;
}

So, the code would probably be (almost) exactly the same speed.

(Lets be honest, if you are worrying about speed improvements at such a low level, you probably have far greater problems in your code.)

jjnguy
Actually, the code given the question still branches when `a` and `b` are equal which would make it worse. I know someone is going to say something about method lookups but, honestly, don't use Java if you care about that. When someone sees `Math.max` they know what you are doing and that's what matters.
Sinan Ünür
Why would branching on `a == b` be worse? Let's suppose that `a` and `b` are truely random `int` s. Then wouldn't `a > b` branch equally as often as `a >= b`?
trinithis
@Sinan: When you look at the bytecode you can see that the conditional operator always branches, so using `>=` instead of `=` would just make it use the other route when the values are equal. And current Java VMs can achieve amazing performance also for low level operations that is sometimes hard to beat even by C or ASM. High performance and Java isn't necessarily a contradiction anymore if you know what to avoid.
x4u
@x4u OK. Thank you for the information. I upvoted @jjnguy's answer at the time for him taking the time to look up what is done in the source. In any case, my point was not that Java is slow, but that there is absolutely no point in worrying about the speed difference between inlining and calling a static method unless there is some horrible bug that you are trying avoid or some other crazy thing.
Sinan Ünür
A: 

Not the same. When you are writing (a > b) ? a : b you don't have an extra function call, so it will be faster. It's the equivalent of inlining in C++. But this will not make any difference in real life. Math.max(a,b) is more readable so I would use it.

XMLDUDE
no, see dsimcha answer
Valentin Rocher
Any function call will add overhead, even if is not virtual. If you examine the machine code, you will see that when the function is called, the parameters are packed on the stack; when the function will return, result value is extracted from the stack. All this will consume CPU cycles.
XMLDUDE
@XMLDUDE: What you describe is exactly what the inlining optimization is designed to get around. Tiny functions like max are almost always inlined by any decent compiler or JIT.
dsimcha
+1 you were right
stacker
+3  A: 

Performance questions always call for a test before you can start speculating:

public static void maxtest()
{
    int res = 0;
    for( int idx = 0; --idx != 0; )
        // res = ( res > idx ) ? res : idx;
        res = Math.max( res, idx );
    System.out.println( "res: " + res );
}

This runs on my machine 6 seconds with Math.max() and 3.2 seconds with ?: on the latest 1.6.1 x64 server Sun JVM. So ?: is actually faster. Contrary to all the hopes we like to put in the JITs that have really become amazing by the time they still don't catch everything.

EDIT: Out of curiosity I also tried this code with the 32 bit client JVM 1.6.1 on the same machine and with this both versions run in 7 seconds! So it's probably not the method invocation that doesn't get inlined but the server JIT seems to be able to do some additional optimizations for this particular test case that it can't detect when there is a method call involved.

x4u
That is a difference of less than one cycle per loop iteration. Probably not significant.
Tom Hawtin - tackline
Oh, and of course `Math.max` is defined slightly differently to your alternative, and you almost always follow the same path (may cause rare deoptimisation when you don't)
Tom Hawtin - tackline
I ran it with `>=` and `>` in the condition and the execution time remained the same.
x4u
+1 for measuring
stacker
+3  A: 

I've been on the receiving end of this type of question and they are usually more about how you answer the question than what the 'correct' answer is.

Matthew
+1  A: 

If I had asked such a question in an interview, I would have expected the candidate to tell me that the two expressions may not give the same result for all possible types of a and b.

jarnbjo
What? I don't see how that is the case. Comparison operators only work on primitives, so the behavior is well defined (unless I'm missing something). Please explain.
trinithis
You are missing double, float, Double.NaN and Float.NaN.
Mark Thornton
And the difference between positive and negative zero.
jarnbjo
+1  A: 

The original question doesn't specify the type of the arguments. This matters because the definition of max (and min) for floating point arguments is more complex. For floating point (double or float) the Math.max method is likely to be slower, but it also may return a different result if one of the arguments is NaN.

Mark Thornton