if i have a long logical Expression does it matter to split it in many if-statements or to use the long logical Expression?
Example:
if((A||B)&&(B||C)&&(C||D)&&.....(N||N+1))
System.out.println("Hello World");
or is this faster
if(A||B)
if(B||C)
if(C||D)
...
if(N||N+1)
System.out.println("Hello World");
I think the long Expression is faster but many ifs could be better to read. But i´m not sure whether ,many if-statements are practicable or not?
EDIT: THIS IS WRONG, SEE MY EDIT BELOW
In my test case nested ifs are faster. I don't know why. I expected the contrary. Maybe I am testing it wrong.
Test case
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
public class Test {
private static final int RUN_TIMES = 100000000;
private static final int HEATUP_TIMES = 100000;
private static final int RESET_EVERY = 1000;
public static void main(String[] args) {
Test instance = new Test();
instance.doTest();
}
private long a;
private long b;
private long c;
private long d;
private long e;
private long f;
private AtomicLong n;
private void doTest() {
Runnable t1 = new Runnable() {
public void run() {
if (
(a > b || a > c)
&& (a > d || b > d)
&& (c > e || e > f)
&& (f > a || f > b)
&& (f > e || f > a)
&& (a > f || f > d)
&& (d > e || e > d)
&& (f > e || f > a)
&& (f > b || f > a)) {
n.incrementAndGet();
}
}
public String toString() {
return "task1";
}
};
Runnable t2 = new Runnable() {
public void run() {
if (a > b || a > c)
if (a > d || b > d)
if (c > e || e > f)
if (f > a || f > b)
if ((f > e || f > a))
if ((a > f || f > d))
if ((d > e || e > d))
if ((f > e || f > a))
n.incrementAndGet();
}
public String toString() {
return "task2";
}
};
List<Runnable> tasks = Arrays.asList(t1, t2, t1, t2, t1, t2, t1, t2, t1, t2);
for (Runnable r: tasks) {
benchmark(r);
}
}
private void reset() {
java.util.Random rnd = new java.util.Random();
this.a = rnd.nextLong();
this.b = rnd.nextLong();
this.c = rnd.nextLong();
this.d = rnd.nextLong();
this.e = rnd.nextLong();
this.f = rnd.nextLong();
}
private void benchmark(Runnable t) {
n = new AtomicLong();
reset();
for (int i = 0; i < HEATUP_TIMES; i++) {
t.run();
}
long t0 = System.nanoTime();
int r = 0;
for (int i = 0; i < RUN_TIMES; i++) {
if (r == 0) {
reset();
r = RESET_EVERY + 1;
}
r--;
t.run();
}
long t1 = System.nanoTime();
System.out.println(String.format("Task %s was run %d times in %.3f ms",
t, RUN_TIMES, (t1 - t0) / 1000000d));
System.out.println("n = " + n);
}
}
Results
Task task1 was run 100000000 times in 753,292 ms
n = 12666654
Task task2 was run 100000000 times in 491,695 ms
n = 12359347
Task task1 was run 100000000 times in 663,144 ms
n = 12530518
Task task2 was run 100000000 times in 499,428 ms
n = 12567555
Task task1 was run 100000000 times in 740,334 ms
n = 12504492
Task task2 was run 100000000 times in 424,854 ms
n = 12379367
Task task1 was run 100000000 times in 721,993 ms
n = 12541529
Task task2 was run 100000000 times in 430,007 ms
n = 12647635
Task task1 was run 100000000 times in 719,680 ms
n = 12598586
Task task2 was run 100000000 times in 432,019 ms
n = 12581569
The atomic long n
is to test I am not mistaking a condition and to have something to do when the conditions are satisfied.
EDIT AFTER ACCEPT
As TheOtherDude pointed the second test had a missing condition. Fixing that the results are totally different. Now both test take the same time.
Task task1 was run 100000000 times in 907,538 ms
n = 12401389
Task task2 was run 100000000 times in 941,928 ms
n = 12325413
Task task1 was run 100000000 times in 850,497 ms
n = 12417405
Task task2 was run 100000000 times in 873,328 ms
n = 12571559
Task task1 was run 100000000 times in 840,028 ms
n = 12538526
Task task2 was run 100000000 times in 865,157 ms
n = 12461449
Task task1 was run 100000000 times in 860,125 ms
n = 12252240
Task task2 was run 100000000 times in 862,829 ms
n = 12350338
Task task1 was run 100000000 times in 866,317 ms
n = 12597585
Task task2 was run 100000000 times in 866,483 ms
n = 12538526
Ok, this question is old, but still worth answering, I think.
Task 2 is missing a single condition, task 1 is executing.It is the last one:
&& (f > b || f > a)) {
This might contribute to the speed advantage of task 2. You should correct that and measure again.
And It would be interesting to see the speed of the third option given by OldCurmudgeon.
Another thing. You see a random distribution of the execution times. It would be wise to check, if the difference in execution times is statistically significant.
TheOtherDude
You should only ever sacrifice simplicity for run-time performance when there is a measurable and significant benefit. There is clearly no measurable benefit here or you wouldn't be asking the question.
When all else fails - try simple.
Neither of your options are simple - try something else.
public boolean goodToGo(boolean... flags) {
boolean good = true;
for ( int i = 0; i < flags.length - 1 && good; i++ ) {
good &= flags[i] || flags[i+1];
}
return good;
}
public void test() {
if ( goodToGo(true, true, false, true, false, false)) {
System.out.println("Hello");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With