For Loops Code Optimization - java

I had a challenge to print out multiples of 7 (non-negative) to the 50th multiple in the simplest way humanly possible using for loops.
I came up with this (Ignoring the data types)
for(int i = 0; i <= 350; i += 7)
{System.out.println(i);}
The other guy came up with this
for(int i=0;i <=50; i++)
{
System.out.println(7*i);
}
However, I feel the two code snippets could be further optimized. If it actually can please tell. And what are the advantages/disadvantages of one over the other?

If you really want to optimize it, do this:
System.out.print("0\n7\n14\n21\n28\n35\n42\n49\n56\n63\n70\n77\n84\n91\n98\n105\n112\n119\n126\n133\n140\n147\n154\n161\n168\n175\n182\n189\n196\n203\n210\n217\n224\n231\n238\n245\n252\n259\n266\n273\n280\n287\n294\n301\n308\n315\n322\n329\n336\n343\n350");
and it's O(1) :)

The first one technically performs less operations (no multiplication).
The second one is slightly more readable (50 multiples of 7 vs. multiples of 7 up to 350).
Probably can't be optimized any further.
Unless you're willing to optimize away multiple println calls by doing:
StringBuilder s = new StringBuilder();
for(int i = 0; i <= 350; i += 7) s.append(i).append(", ");
System.out.println(s.toString());
(IIRC printlns are relatively expensive.)
This is getting to the point where you gain a tiny bit of optimization at the expense of simplicity.

In theory, your code is faster since it does not need one less multiplication instruction per loop.
However, the multiple calls to System.out.println (and the integer-to-string conversion) will dwarf the runtime the multiplication takes. To optimize, aggregate the Strings with a StringBuilder and output the whole result (or output the result when memory becomes a problem).
However, in real-world code, this is extremely unlikely to be the bottleneck. Profile, then optimize.

The second function is the best you would get:
O(n)

Related

Why is for (int i = 0; i + 9 < s.length(); i++) much faster than for (int i = 0; i < s.length()-9; i++) { [duplicate]

This question already has answers here:
How do I write a correct micro-benchmark in Java?
(11 answers)
Closed 2 years ago.
s is a string with a length of up to 100000 characters.
When I run the first loop:
for (int i = 0; i + 9 < s.length(); i++)
I get a runtime of 14ms for a test set.
When I run the second loop instead of the first:
for (int i = 0; i < s.length() - 9; i++)
it consistently takes about 2 times more (28ms) than the first loop for the same test set.
Does the structure of the first loop allow for some kind of optimization?
First of all, there is a strong possibility that what you think you are seeing is actually due to a badly written benchmark. I strongly advise you to carefully read following Q&A and follow the advice therein:
How do I write a correct micro-benchmark in Java?
Secondly, what you are saying doesn't correspond to my intuition. However, if the effect is real, one would need to do an in-depth analysis of the native code produced by the JIT compiler to understand the reason for the difference.
Finally, this smells of "premature optimization". As a general rule, the JIT compiler can do a better (more consistent, more reliable) job of optimizing than a human can. If there are simple optimizations like the one that you are trying, the JIT compiler will find them. Micro-optimization like this is generally a waste of (your) time.
So if you are going to try optimize, then you need to do it Scientifically.
Get the application / library working first.
Write a realistic benchmark for the code. One that matches how the code is likely to be used for real.
Set yourself some measurable performance goals. ("As fast as possible" is not measurable).
Run the benchmark to see if you already meet the goals. If yes, don't waste any further time on optimizing.
Now run the benchmark using a performance profiler to identify the performance hot spots; i.e. the methods, etc that the application spends most of its time executing.
Pick one hotspot, and look for possible ways to make it faster. Implement on possible optimization ... and run the benchmarks again to see if it improved things.
Repeat steps 4 through 6 until you either meet the performance goal or run out of hotspots that can be optimized.
I do not think that the preformance problem with this for...loop definition. To check it, you have to provide the full compilable code; to check every aspects.
But you can easily check the answer moving all calculatio to the beginning:
for (int = 0, total = s.length() - 9; i < total; i++) {
// ...
}
P.S. for (A; B; C) where A is calculated only once at the beginning of the loop; B and C are calculated on each loop iteration.

break is slowing down my loop?

I have a nested loop which iterates over all combinations of two elements from an array. However, if the sum of the two values is too large, I want to skip to the next x.
Here's the Java code snippet:
/* Let array be an array of integers
* and size be equal to its length.
*/
for (int a = 0; a < size; a++)
{
int x = array[a];
for (int b = 0; b < size(); b++)
{
int y = array[b];
if ((x + y) < MAX)
{
// do stuff with x and y
}
else
{
// x + y is too big; skip to next x
break;
}
}
}
This works exactly as expected.
However, if I replace the break statement with b = size;, it surprisingly runs about 20% faster. Note that by setting b = size;, the inner for conditional becomes false and execution continues to the next iteration of the outer a loop.
Why would this happen? It seems like break should be faster, as I would have thought it saves an assignment, jump, and compare. Though clearly it does not.
Why would this happen? It seems like break should be faster ...
IMO, the most likely explanation is some kind of JVM warmup effect, especial since the overall times (120ms versus 74ms) are so small. If you wrapped that loop in another one, so that you could perform the time measurements repeatedly in the same run, this anomaly is likely to go away.
(Just increasing the array sizes isn't necessarily going to help. The best way to be sure that you have accounted for JVM warmup anomalies it to use a benchmarking framework; e.g. Caliper. But, failing that, put the "snippet" into a method and call it repeatedly.)
... as I would have thought it saves an assignment, jump, and compare. Though clearly it does not.
It is not clear at all. Your Java code gets compiled to bytecodes by javac (or your IDE). When you run the code, it starts out interpreting the bytecodes, and then after a bit they are compiled to native code by the JIT compiler:
The JIT compilation takes time that is (probably) included in your time measurements ... and one source of warmup anomalies.
The code produced by the JIT compiler is influenced by statistics gathered while interpreting. One of the things that is typically measured is whether branches (e.g. if tests) go one way or the other. This is used to make branch predictions ... which if correct make the test-and-branch instruction sequences a lot faster.

How to speed up array intersection in Java?

Arrays below are sorted without duplicates (contain unique positive integers) of small size (less than 5000) and intersection (see below) is called billion of times so any micro-optimization does matter. This article nicely describes how to speed up the below code in C language.
int i = 0, j = 0, c = 0, la = a.length, lb = b.length;
intersection = new int[Math.min(la, lb)];
while (i < la && j < lb) {
if (a[i] < b[j]) i++;
else if (a[i] > b[j]) j++;
else {
intersection[c] = a[i];
i++; j++; c++;
}
}
int[] intersectionZip = new int[c];
System.arraycopy(intersection, 0, intersectionZip, 0, c);
In Java I guess it is impossible to call those low-level instructions. But they mention that "it is possible to improve this approach using branchless implementation". How one would do it? Using switch? Or maybe substitute a[i] < b[j], a[i] > b[j] or a[i] == b[i] comparisons with binary operations on integer operands?
Binary search approach (with complexity O(la log(lb))) is not the case because la is not << than lb. Interesting how to change the if statements.
I don't think there's much you could do to improve that performance of that Java code. However, I would note that it is not doing the same thing as the C version. The C version is putting the intersection into an array that was preallocated by the caller. The Java version allocates the array itself ... and then reallocates and copies to a smaller array when it is finished.
I guess, you could change the Java version to make two passes over the input arrays, with the first one working out how big the input array needs to be ... but whether it helps or hinders will depend on the inputs.
There might be other special cases you could optimize for; e.g. if there were likely to be long runs of numbers in one array with nothing in that range in the other array you might be able to "optimistically" try to skip multiple numbers in one go; i.e. increment i or j by a larger number than 1.
But they mention that "it is possible to improve this approach using branchless implementation". How one would do it? Using switch?
Not a Java switch ... or a conditional expression because they both involve branches when translated to the native code.
I think he is referring to something like this: Branchless code that maps zero, negative, and positive to 0, 1, 2
FWIW it is a bad idea to try to do this kind of thing in Java. The problem is that the performance of tricky code sequences like that is dependent on details of the hardware architecture, instruction set, clock counts, etc that vary from one platform to the next. The Java JIT compiler's optimizer can do a pretty good job of optimizing your code ... but if you include tricky sequences:
it is not at all obvious or predictable how they will be translated to native code, and
you may well find that the trickiness actually inhibits useful optimizations that the JIT compiler might otherwise be able to do.
Having said that, it is not impossible that some future release of Java might include a superoptimizer ... along the lines of the one mentioned on the linked Q&A above ... that would be able to generate branchless sequences automatically. But bear in mind that superoptimization is very expensive to perform.
Maybe using ? : operator:
(a[i] < b[j]) ? i++ : ((a[i] > b[j]) ? j++ : ....

checking a value for reset value before resetting it - performance impact?

I have a variable that gets read and updated thousands of times a second. It needs to be reset regularly. But "half" the time, the value is already the reset value. Is it a good idea to check the value first (to see if it needs resetting) before resetting (a write operaion), or I should just reset it regardless? The main goal is to optimize the code for performance.
To illustrate:
Random r = new Random();
int val = Integer.MAX_VALUE;
for (int i=0; i<100000000; i++) {
if (i % 2 == 0)
val = Integer.MAX_VALUE;
else
val = r.nextInt();
if (val != Integer.MAX_VALUE) //skip check?
val = Integer.MAX_VALUE;
}
I tried to use the above program to test the 2 scenarios (by un/commenting the 2nd "if" line), but any difference is masked by the natural variance of the run duration time.
Thanks.
Don't check it.
It's more execution steps = more cycles = more time.
As an aside, you are breaking one of the basic software golden rules: "Don't optimise early". Unless you have hard evidence that this piece if code is a performance problem, you shouldn't be looking at it. (Note that doesn't mean you code without performance in mind, you still follow normal best practice, but you don't add any special code whose only purpose is "performance related")
The check has no actual performance impact. We'd be talking about a single clock cycle or something, which is usually not relevant in a Java program (as hard-core number crunching usually isn't done in Java).
Instead, base the decision on readability. Think of the maintainer who's going to change this piece of code five years on.
In the case of your example, using my rationale, I would skip the check.
Most likely the JIT will optimise the code away because it doesn't do anything.
Rather than worrying about performance, it is usually better to worry about what it
simpler to understand
cleaner to implement
In both cases, you might remove the code as it doesn't do anything useful and it could make the code faster as well.
Even if it did make the code a little slower it would be very small compared to the cost of calling r.nextInt() which is not cheap.

What's more efficient/ cheaper, casting or a method call?

I have a Double that I want to knock the extra digits after the decimal place off of (I'm not too concerned about accuracy but feel free to mention it in your answer) prior to conversion into a String.
I was wondering whether it would be better to cast to an int or to use a DecimalFormat and call format(..) . Also, is it then more efficient to specify String.valueOf() or leave it as it is and let the compiler figure it out?
Sorry if I sound a bit ignorant, I'm genuinely curious to learn more of the technical details.
For reference, i'm drawing text to and android canvas:
c.drawText("FPS: " + String.valueOf((int)lastFps), xPos, yPos, paint);
Casting will probably be more efficient. This is implemented as native code while using a method will have to go through the java code. Also it's much more readable.
For the string.valueof, I expect the performance to be strictly the same. I find it more readable to just do "string" + intValue than "string" + String.valueof(intValue)
I made a program that used System.nanoTime() to calculate the execution time of these two methods:
public static void cast() {
for (int i=0; i<1000000; i++) {
int x= (int)Math.random();
}
}
public static void format() {
for (int i=0; i< 1000000; i++) {
DecimalFormat df = new DecimalFormat("#");
df.format(Math.random());
}
}
Here are the respective results:
80984944
6048075593
Granted my tests probably aren't perfect examples. I'm just using math.random(), which generates a number that will always cast to 0, which might affect results. However, these results do make sense - casting should be cheap, since it likely doesn't operate on the bits at all - the JVM just treats the bits differently.
Edit: If I pull out the instantiation of the formatter for the second example, the program runs in 3155165182ns. If I multiply the random numbers by Integer.MAX_VALUE in both cases (with the instantiation pulled out), the results are: 82100170 and 4174558079. Looks like casting is the way to go.
This is a job for Math.floor().
Generally speaking, function/method calls come at the cost of performance overhead. My vote is that typecasting would be faster, but as #Zefiryn suggested, the best way is to create a loop and do each action a multitude of times and measure the performance with a timer.
I'm not sure about the efficiency of either, but here's a third option that could be interesting to compare:
String.valueOf(doubleValue).substring(0, endInt)
which would give a set number of characters rather than decimals/numbers, and would skip the typecasting but make two function calls instead.
EDIT: Was too curious so I tried running each option:
integerNumberFormat.format(number)
String.valueOf(doubleValue).substring(0, endInt)
String.valueOf((int)doubleValue)
10^6 cycles with the results being ~800 ms, ~300 ms and ~40 ms, respectively. I guess my results won't be immediately translatable to your situation but they could give a hint that the last one is indeed, as the previous posters suggested, the fastest one.

Categories

Resources