Get Time
forums   
Search | Watch Thread  |  My Post History  |  My Watches  |  User Settings
View: Flat (newest first)  | Threaded  | Tree
Previous Thread  |  Next Thread
[ 1 2 ]    NEXT >
Math.abs() is slow?!? | Reply
I was very surprised to find that

a>0?a:-a;

is slightly faster than Math.abs(a) (if both are implemented in different methods). Can someone please explain why this is so.
Re: Math.abs() is slow?!? (response to post by dimkadimon) | Reply
Well, depending on the compiler, you could get a method call overhead from using Math.abs() instead of the expression you show. Also, if you're only using Math.abs() on integers, Java would have to first convert the integers to doubles before passing it on to Math.abs(). Also, depending on the details of Math.abs() implementation, it might require special handling to handle values like positive infinity, negative infinity, NaNs, denormalized values, etc.
Re: Math.abs() is slow?!? (response to post by (Lx.xx)(Lx.xx)) | Reply
Oh nevermind, I didn't see the part where you says you're putting the ?: expression inside its own method. In that case I guess there would be no method call overhead, nor would there be a type conversion overhead if the parameter is declared as double. And now that I think of it, the ?: expression should work just fine with special double values.

So I guess I don't know why either. But how thoroughly did you test the speed difference? How many times did you run the call? For all I know it could be things like memory hierarchy that's causing the speed difference.
Re: Math.abs() is slow?!? (response to post by dimkadimon) | Reply
It really depends on how you do it. If you put the abs method in the same class as the main method, it will be faster (by a lot) becuase you don't have to go find another class in memory each time. Also, the order in which you do the tests seems to matter (perhaps due to the JIT compiler).

An interesting, and related phenomena can be seen with the following code:

public class Test{
public static void main(String[] a){
long time;
int n;
int m = -3;
time = System.currentTimeMillis();
for(int i = 0; i<1900000000; i++){
n= abs(m);
}
for(int i = 0; i<100000000; i++){
n= abs(m);
}
System.out.println(System.currentTimeMillis()-time);
}
public static int abs(int n){
return n>0?n:-n;
}
}

Run that, and then switch the order of the two loops (i.e. do the one with fewer iterations first). You'll notice that it takes about 50% longer one way that the other. As you can see, it's a bit tricky to benchmark Java due to all sorts of things going on with HotSpot. However, in my tests, it was clear that writing your own abs method in the same class was almost 10 times faster than calling Math.abs() or MyMath.abs().
Re: Math.abs() is slow?!? (response to post by lars2520) | Reply
Does C (or C++) have something like Maths.abs()? If so, someone should test it against the ?: method. It seems that C is much easier to benchmark and should give more reliable answers.
Re: Math.abs() is slow?!? (response to post by dimkadimon) | Reply
I benched this using MSVC++'s compiler with /O2. Abs takes significantly longer to execute.

int main() {
clock_t start, finish;
volatile int n, i, j;

start = clock();
for(i = -200000000; i < 200000000; i++) {
n = abs(i);
}
finish = clock();

printf("%d\n", finish - start);

return 0;
}

int main() {
clock_t start, finish;
volatile int n, i, j;

start = clock();
for(i = -200000000; i < 200000000; i++) {
(n >0) ? (n = i) : (n = -i);
}
finish = clock();

printf("%d\n", finish - start);

return 0;
}

For abs:
3344
3424
3334
3324
3344

Not abs:
1802
1812
1802
1822
1842

MSVC actually inlines the abs code, so it isn't due to function call overhead. The series of instructions generated by the non-abs program simply executes faster than the instructions generated by the abs function, at least on my P4. Which is strange, because the second program contains a jump, which usually wreaks havoc on the P4 pipeline.
Re: Math.abs() is slow?!? (response to post by armadillo) | Reply

int main() {
clock_t start, finish;
volatile int n, i, j;

start = clock();
for(i = -200000000; i < 200000000; i++) {
(n > 0) ? (n = i) : (n = -i); // This line
}
finish = clock();

printf("%d\n", finish - start);

return 0;
}


//////////////////////////////////////////

Shouldn't the line that I marked have (i > 0) instead of (n > 0)? Don't know if this will make any difference to the running time, but at least then we'll actually get the absolute value correct.
Re: Math.abs() is slow?!? (response to post by lars2520) | Reply
In addition to what lars2520 has said - the other reason that Math.abs() is slower than your own is because the class has been defined as strictfp. I'll let the 'in the know' guys explain what that means exactly but I'm pretty sure it imposes additional overhead (to ensure it returns the same results across platforms) in the way things are evaluated within the class. When you roll your own - you are foregoing the platform independence but gaining less overhead.
Re: Math.abs() is slow?!? (response to post by Pops) | Reply
I agree, I actually think strictfp is the biggest factor.

Here's the summary of strictftp:
http://java.sun.com/developer/JDCTechTips/2001/tt0410.html#using

In the case of Intel chips, my guess is that strictfp forces the JVM to execute code that goes out of its way to not use the Pentium's normal 80-bit floating-point registers, as they have too much precision.

In the case of abs, of course, strictfp doesn't make any difference that I can imagine, so the custom implementation is faster. Though, it makes me wonder if there is some good reason why Sun declared the whole class strictfp instead of doing it method-by-method.


Also, in this whole debate, consider whether the simple "a < 0 ? -a : a" implementation really behaves the same as Math.abs() in corner cases like negative zero, infinity, NaN.


Hmm... is there a component idea here? Making a faster, non-strictfp version of abs, min, max, maybe others? Seems way too small by itself but maybe more can be added.


If anyone is benchmarking things and is interested in the effect of HotSpot, check out the "-XX:+PrintCompilation" option, which prints info on what HotSpot is compiling.
Re: Math.abs() is slow?!? (response to post by Pops) | Reply
I don't think that this is the case. Based on my testing, adding strictfp makes for almost no difference when running abs. I can see how it would make a difference in some cases, but absolution value of floating point numbers is flipping a single bit, so it shouldn't really be any different. Furthermore, my tests before were mostly run using ints, and if I put the abs method in a separate class, and make it static, it performs comparably. The only time you see a big performance difference is when you put the abs method in the same class, or simply inline it.

As for the implementation of abs with doubles, it should be no more complex than a>0?a:-a. NaN will still be NaN, and the infinities should work too. Even -(-0.0) works out to 0.0.
Re: Math.abs() is slow?!? (response to post by lars2520) | Reply
But +0.0 becomes -0.0...
Re: Math.abs() is slow?!? (response to post by SnapDragon) | Reply
good point...
I guess if you do a>0?a:0-a it will work out. Those pesky negative zeros.
Re: Math.abs() is slow?!? (response to post by lars2520) | Reply
Yeah, you're right, I think I was misled by my own micro-benchmarks. Changing the tests around a few times, I also concluded that strictfp doesn't make much, if any, difference.

Well it was a good theory...
Re: Math.abs() is slow?!? (response to post by lars2520) | Reply
BTW lars2520 - you're falling for a classic microbenchmarking mistake when dealing with JVM. Try this one instead:

public class Stuff{
public static void main(String[] a){
Stuff s = new Stuff();
s.doIt();
s.doIt();
}
public Stuff() {}
public void doIt() {
long time;
int n;
int m = -3;
time = System.currentTimeMillis();
for(int i = 0; i<100000000; i++){
n= abs(m);
}
for(int i = 0; i<1900000000; i++){
n= abs(m);
}
System.out.println(System.currentTimeMillis()-time);
}
public static int abs(int n){
return n>0?n:-n;
}
}


There are two issues with yours:
1) Running it out of the main method - this prevents the hotspot compiler from compiling your code properly and makes it 'depend' on how it recognizes a hotspot. Apparently switching the loops around cause it to recognize it quicker.
2) You need to 'warm' up the JVM by allowing it to compile your microbenchmarks results first. This then evens the playing field for your real benchmarking.

If you do the above with switching the loops around - you'll see the execution of the first loop around what you observed (ie about a 3 second difference) but the second one will be very close to each other.

Now - the real interesting point - because it now properly compiles the code - you see NO difference between Math.abs() and your abs() function (because it has all been properly inlined most likely).

So - what's the bottom line - the Math.abs() call probably is longer because it takes hotspot longer to recognize the pattern - introducing overhead. Because TC's JVM isn't 'warm' when running our contest code - it's better to roll your own (hotspot recognizes it faster for some reason).

That atleast is my take on things...
Re: Math.abs() is slow?!? (response to post by aussie) | Reply
Indeed it should be. Copy/paste is evil. Didn't change the running time though.

I realized that Math.abs() in Java handles floating point numbers, so I benchmarked fabs() in C as well:

Fabs:
961
961
1001
971
961

Its much faster than abs, and also faster than (i > 0) ? (n = i) : (n = -i). fabs() translates to a single machine instruction (namely, fabs) which I suppose Java doesn't do.
[ 1 2 ]    NEXT >

RSS