Assume i have the following code, there are three for loop to do something. Would it run fast if i change the most outer for loop to while loop? thanks~~
int length = 200;
int test = 0;
int[] input = new int[10];
for(int i = 1; i <= length; i++) {
for (int j = 0; j <=length - i; j++) {
for (int k = 0; k < length - 1; k++) {
test = test + input[j + k];
}
}
}
No, changing the type of loop wouldn't matter.
The only thing that can make it faster would be to have less nesting of loops, and looping over less values.
The only difference between a for loop and a while loop is the syntax for defining them. There is no performance difference at all.
int i = 0;
while (i < 20){
// do stuff
i++;
}
Is the same as:
for (int i = 0; i < 20; i++){
// do Stuff
}
(Actually the for-loop is a little better because the i will be out of scope after the loop while the i will stick around in the while loop case.)
A for loop is just a syntactically prettier way of looping.
This kind of micro-optimization is pointless.
A while-loop won’t be faster.
The loop structure is not your bottleneck.
Optimize your algorithm first.
Better yet, don’t optimize first. Only optimize after you have found out that you really have a bottleneck in your algorithm that is not I/O-dependant.
Someone suggested to test while vs for loops, so I created some code to test whether while loops or for loops were faster; on average, over 100,000 tests, while loop was faster ~95% of the time. I may have coded it incorrectly, I'm quite new to coding, also considering if I only ran 10,000 loops they ended up being quite even in run duration.
edit I didn't shift all the array values when I went to test for more trials. Fixed it so that it's easier to change how many trials you run.
import java.util.Arrays;
class WhilevsForLoops {
public static void main(String[] args) {
final int trials = 100; //change number of trials
final int trialsrun = trials - 1;
boolean[] fscount = new boolean[trials]; //faster / slower boolean
int p = 0; // while counter variable for for/while timers
while (p <= trialsrun) {
long[] forloop = new long[trials];
long[] whileloop = new long[trials];
long systimeaverage;
long systimenow = System.nanoTime();
long systimethen = System.nanoTime();
System.out.println("For loop time array : ");
for (int counter=0;counter <= trialsrun; counter++) {
systimenow = System.nanoTime();
System.out.print(" #" + counter + " #");
systimethen = System.nanoTime();
systimeaverage = (systimethen - systimenow);
System.out.print( systimeaverage + "ns |");
forloop[counter] = systimeaverage;
}
int count = 0;
System.out.println(" ");
System.out.println("While loop time array: ");
while (count <= trialsrun) {
systimenow = System.nanoTime();
System.out.print(" #" + count + " #");
systimethen = System.nanoTime();
systimeaverage = (systimethen - systimenow);
System.out.print( systimeaverage + "ns |");
whileloop[count] = systimeaverage;
count++;
}
System.out.println("===============================================");
int sum = 0;
for (int i = 0; i <= trialsrun; i++) {
sum += forloop[i];
}
System.out.println("for loop time average: " + (sum / trials) + "ns");
int sum1 = 0;
for (int i = 0; i <= trialsrun; i++) {
sum1 += whileloop[i];
}
System.out.println("while loop time average: " + (sum1 / trials) + "ns");
int longer = 0;
int shorter = 0;
int gap = 0;
sum = sum / trials;
sum1 = sum1 / trials;
if (sum1 > sum) {
longer = sum1;
shorter = sum;
}
else {
longer = sum;
shorter = sum1;
}
String longa;
if (sum1 > sum) {
longa = "~while loop~";
}
else {
longa = "~for loop~";
}
gap = longer - shorter;
System.out.println("The " + longa + " is the slower loop by: " + gap + "ns");
if (sum1 > sum) {
fscount[p] = true; }
else {
fscount[p] = false;
}
p++;
}
int forloopfc=0;
int whileloopfc=0;
System.out.println(Arrays.toString(fscount));
for(int k=0; k <= trialsrun; k++) {
if (fscount[k] == true) {
forloopfc++; }
else {
whileloopfc++;}
}
System.out.println("--------------------------------------------------");
System.out.println("The FOR loop was faster: " + forloopfc + " times.");
System.out.println("The WHILE loop was faster: " + whileloopfc + " times.");
}
}
you cant optimize it by changing it to while.
you can just increment speed very very very very little by changing the line
for (int k = 0; k < length - 1; k++) {
by
for (int k = 0; k < lengthMinusOne; k++) {
where lengthMinusOne is calculated before
this subtraction is just calculating almost (200x201/2) x (200-1) times and it is very little number for computer :)
here's a helpful link to an article on the matter
according to it, the While and For are almost twice as faster but both are the same.
BUT this article was written in 2009 and so i tried it on my machine and here are the results:
using java 1.7: the Iterator was about 20%-30% faster than For and While (which were still the same)
using java 1.6: the Iterator was about 5% faster than For and While (which were still the same)
so i guess the best thing is to just time it on your own version and machine and conclude from that
Even if the hypothesis of the while loop being faster than the for loop were true (and it's not), the loops you'd had to change/optimize wouldn't be the outer ones but the inner ones, because those are executed more times.
The difference between for and while is semantic :
In a while loop, you will loop as long as the condition is true, which can vary a lot, because you might, in your loop, modify variables using in evluating the while condition.
Usually, in a for loop, you loop N time. This N can be variable, but doesn't move until the end of your N loop, as usually developpers doesn't modify variables evaluated in the loop condition.
It is a way to help other to understand your code. You are not obliged not to modify for loop variables, but it is a common (and good) practice.
No, you're still looping the exact same number of times. Wouldn't matter at all.
Look at your algorithm! Do you know beforehand which values from your array are added more than one time?
If you know that you could reduce the number of loops and that would result in better performance.
There would be no performance difference. Try it out!
The JVM and further, the compiler, would make both loops into something like
label:
;code inside your for loop.
LOOP label
It would only matter if you are using multi-thread or multiple processor programming. Then it would also depends on how you assign the loops to the various processors/threads.
No, it's not going to make a big difference, the only thing is that if your nesting loops you might want to consider switching up for example for organizational purposes, you may want to use while loop in the outer and have for statements inside it. This wouldn't affect the performance but it would just make your code look cleaner/organized
You can calculate it yourself.
int length = 200;
int test = 0;
int[] input = new int[10];
long startTime = new Date().getTime();
for(int i = 1; i <= length; i++) {
for (int j = 0; j <=length - i; j++) {
for (int k = 0; k < length - 1; k++) {
test = test + input[j + k];
}
}
}
long endTime = new Date().getTime();
long difference = endTime - startTime;
System.out.println("For - Elapsed time in milliseconds: " + difference);
test = 0;
input = new int[10];
int i = 0, j = 0, k = 0;
startTime = new Date().getTime();
while(i < length) {
while(j <= length - i ) {
while(k < length - 1) {
test = test + input[j + k];
k++;
}
j++;
}
i++;
}
endTime = new Date().getTime();
difference = endTime - startTime;
System.out.println("While - Elapsed time in milliseconds: " + difference);
The for loop and while loop both are iteration statements, but both have their distinct feature.
Syntax
While Loop
//setup counter variable
int counter = 0;
while ( condition) {
//instructions
//update counter variable
counter++; //--> counter = counter + 1;
}
For Loop
for (initialization; condition; iteration){
//body of for loop
}
The for loop does have all its declaration (initialization, condition, iteration) at the top of the body of the loop. Adversely, in a while loop only initialization and condition are at the top of the body of the loop and iteration may be written anywhere in the body of the loop.
Key Differences Between for and while loop
In the for loop, initialization, condition checking, and increment or decrement of iteration variable are done explicitly in the syntax of a loop only. As against, in the While loop, we can only initialize and check conditions in the syntax of the loop.
When we are aware of the number of iterations that have to occur in the execution of a loop, then we use for loop. On the other hand, if we are not aware of the number of iteration that has to occur in a loop, then we use a while loop.
If you fail to put the condition statement in the for loop, it will lead to an infinite iteration of a loop. In contrast, if you fail to put a condition statement in the while loop it will lead to a compilation error.
The initialization statement in the syntax of the for loop executes only once at the start of the loop. Conversely, if the while loop is carrying an initialization statement in its syntax, then the initialization statement in the while loop will execute each time the loop iterates.
The iteration statement in the for loop will execute after the body for loop executes. On the contrary, the iteration statement can be written anywhere in the body of the while loop so, there can be some statements that execute after the execution of the iteration statement in the body of the `while loop.
Based on this: https://jsperf.com/loops-analyze (not created by me) the while loop is 22% slower than a for loop in general. At least in Javascript it is.
Related
In the process of learning algorithms, I have written code to compare 2 algorithms performance in terms of running time. The task of these algorithms is to find all the pairs of numbers in an array that add up to a specific number.
First approach - Brute force.
2 for loops to find the pairs of numbers that add up to the given number. Basically time complexity is O(n*n).
Second approach - Efficient
First sort the array, then have start and end as index to the beginning and end of array, and depending on the sum of these elements in the positions, move left or right to find pairs of numbers.
My question is -
I am printing the running time of each algorithm approach. But it seems like the running time of the Brute force approach is faster than the Efficient one. Why is this happening?
See the code here -
public class MainRunner {
final private static int numberRange = 100000;
public static void generateRandomNumbers(int[] array, int[] dupArray) {
System.out.println("Generated Array: ");
Random random = new Random();
for (int i = 0; i < array.length; i++) {
int generatedRandomInt = random.nextInt(array.length) + 1;
array[i] = dupArray[i] = generatedRandomInt;
}
}
public static void main(String[] args) {
int[] array = new int[numberRange];
int[] dupArray = new int[numberRange];
generateRandomNumbers(array, dupArray);
Random random = new Random();
int sumToFind = random.nextInt(numberRange) + 1;
System.out.println("\n\nSum to find: " + sumToFind);
// Starting Sort and Find Pairs
final long startTimeSortAndFindPairs = System.currentTimeMillis();
new SortAndFindPairs().sortAndFindPairsOfNumbers(sumToFind, array);
final long durationSortAndFind = System.currentTimeMillis() - startTimeSortAndFindPairs;
// Starting Find Pairs
final long startTimeFindPairs = System.currentTimeMillis();
new FindPairs().findPairs(sumToFind, dupArray);
final long durationFindPairs = System.currentTimeMillis() - startTimeFindPairs;
System.out.println("Sort and Find Pairs: " + durationSortAndFind);
System.out.println("Find Pairs: " + durationFindPairs);
}
}
SortAndFindPairs.java
public class SortAndFindPairs {
public void sortAndFindPairsOfNumbers(int argNumberToFind, int[] array) {
Arrays.sort(array);
System.out.println("\n\nResults of Sort and Find Pairs: \n");
int startIndex = 0;
int endIndex = array.length - 1;
while (startIndex < endIndex) {
int sum = array[startIndex] + array[endIndex];
if (argNumberToFind == sum) {
//System.out.println(array[startIndex] + ", " + array[endIndex]);
startIndex++;
endIndex--;
} else if (argNumberToFind > sum) {
startIndex++;
} else {
endIndex--;
}
}
}
And the FindPairs.java
public class FindPairs {
public void findPairs(int argNumberToFind, int[] array) {
System.out.println("\nResults of Find Pairs: \n");
int randomInt1 = 0;
int randomInt2 = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = i + 1; j < array.length; j++) {
int sum = array[i] + array[j];
if (argNumberToFind == sum) {
//System.out.println(array[i] + ", " + array[j]);
//randomInt1++;
//randomInt2--;
}
}
}
}}
Only on adding the two variables randomInt1 and randomInt2 in the FindPairs.java, the running time difference is seen. Or else, the running time of FindPairs.java is much less than SortAndFindPairs.java. So why does adding just 2 variable operations increase time by so much? According to conventions, simple operations should consume negligible time. Am I missing out something here?
Results for numberRange = 1000000
Results of Find Pairs:
Sort and Find Pairs: 641
Find Pairs: 57
I think the problem is your compiler optimization playing tricks to you. I tried different permutations of your code, and noticed that the double for loop in FindPairs is doing almost nothing. So the compiler may be stripping some of the code.
I got this numbers with the exact copy of your code:
Sort and Find Pairs: 43
Find Pairs: 13
Consistently (I ran it several times to double check) Sort and find was slower, everytime.
But then I changed the inner loop for to do nothing:
for (int j = i + 1; j < array.length; j++) {
//int sum = array[i] + array[j];
//if (argNumberToFind == sum) {
//System.out.println(array[i] + ", " + array[j]);
//randomInt1++;
//randomInt2--;
//}
And guess what? I got:
Sort and Find Pairs: 20
Find Pairs: 11
Tried several times and the numbers were pretty similar. By removing both loops the runtime for find pairs went to 1. So My guess, maybe the optimization step of the compiler is assuming that the code inside the inner loop doesn't have any effect and thus removes it. The code in Sort and find is a little smarter and so it gets kept.
Now, I tried a different thing, I commented out the increment of randomInt1, but left the sum and if commented,
for (int j = i + 1; j < array.length; j++) {
//int sum = array[i] + array[j];
//if (argNumberToFind == sum) {
//System.out.println(array[i] + ", " + array[j]);
randomInt1++;
//randomInt2--;
//}
and then I got:
Sort and Find Pairs: 42
Find Pairs: 5
Wow, suddenly it got faster! (maybe the compiler replaced the for for the arithmetic calculation of randomInt1 by using the loop bounds?)
My last attempt. You can noticed that this is not a fair comparison, the sort and find have a lot of logic involved, while the find doesn't. It actually does nothing when it find a pair. So to make it apples to apples we want to be sure find pairs actually do something, and lets make sure sort and find do the same extra amount (like adding the same number on both sides of the equation). So I changed the methods to calculate the count of matching pairs instead. Like this:
System.out.println("\nResults of Find Pairs: \n");
long randomInt1 = 0;
int randomInt2 = 0;
int count = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = i + 1; j < array.length; j++) {
int sum = array[i] + array[j];
if (argNumberToFind == sum) {
count++;
}
}
}
System.out.println("\nPairs found: " + count + "\n");
and
public void sortAndFindPairsOfNumbers(int argNumberToFind, int[] array) {
Arrays.sort(array);
System.out.println("\n\nResults of Sort and Find Pairs: \n");
int startIndex = 0;
int endIndex = array.length - 1;
int count = 0;
while (startIndex < endIndex) {
int sum = array[startIndex] + array[endIndex];
if (argNumberToFind == sum) {
//System.out.println(array[startIndex] + ", " + array[endIndex]);
startIndex++;
endIndex--;
count++;
} else if (argNumberToFind > sum) {
startIndex++;
} else {
endIndex--;
}
}
System.out.println("\nPairs found: " + count + "\n");
}
And then got:
Sort and Find Pairs: 38
Find Pairs: 4405
The time for find pairs blowed up! And the sort and find kept in line with what we were seeing before.
So the most likely answer to your problem is that the compiler is optimizing something, and an almost empty for loop is something that the compiler can definitely use to optimize. whilst for the sort and find, the complex logic may cause the optimizer to step back. Your algorithm lessons are find. Here java is playing you a trick.
One more thing you can try is use different languages. I'm pretty sure you will find interesting stuff by doing so!
As stated by LIuxed, sort operation takes some time. If you invest time in sorting, why do you then not take advantage of the fact that list items are sorted?
If list elements are sorted, you could use a binary search algorithm... start in the middle of the array, and check if you go 1/2 up, or 1/2 down. As a result, you can get faster performance with sorted array for seeking a value. Such an algorithm is already implemented in the Arrays.binarySearch methods.
See https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#binarySearch(int[],%20int)
You will notice the difference when you sort just once, but seek many times.
Calling the Array.sort(MyArray) method, takes long time because it uses a selection algorithm; this means, the Sort method go through all the array x times ( x= array.lenght) searching for the smallest/biggest value, and set it on top of the array, and so on.
Thats why, using this method takes a long time, depending on the array size.
I removed everything from your sortAndFindPairsOfNumbers method, just kept
Arrays.sort(array);
But still time difference is much more.
This means most of the time taken is by sort method.
So your thinking that second approach is Efficient one is not correct. Its all about input size.
If you keep numberRange, lets say, 1000, then SortAndFindPairs will be faster.
I am doing a task in my Java class and I am stuck on one part for a week now. I have had all possible errors and infinite loops.
I am trying to display numbers in sequence of 4 and display only 500 numbers.
The code below shows what I have tried:
int add4 = 1;
int count500 = 1;
while (count500 <= 500)
{
if (count500 == 101)
{
System.out.print(add4);
}
else
{
System.out.print(add4 + "," + "");
}
add4 = add4 + 4;
}
Also I am stuck on the lucas sequence numbers.I dont even know where to start with that. I would appreciate your help with those questions.
The simplest way to print the sequence you want would be a for loop and print a function of the loop variable
System.out.print(1);
for (int i = 1; i < 500; ++i) {
System.out.print("," + (4*i+1));
}
This will also avoid trailing commas
Shortest way will be:
for(int i = 1, j = 1; i <= 500; i += 1, j += 4)
System.out.print("i = " + i + " j = " + j);
Refactor to while (count500++ <= 500). Then the loop will terminate correctly.
That said, I'd prefer something on the lines of
for (int i = 0; i < /*ToDo - limit*/; ++i){
System.out.print(i * 4); // ToDo - all your special whitespace.
}
since then you're operating on the iterating variable which will reduce the potential for bugs, such as the one that you have.
If you are not incrementing the value of count500 then how it will reach 500 ?
Add count500++ at the end of the loop
Your stuck in the loop because your precondition is count500 <= 500
The problem is you never change the value of count500.
I see two ways for you to get out of this infinte loop:
1.- Increment it in in your loop:
int add4 = 1;
int count500 = 1;
while (count500 <= 500)
{
if (count500 ==101)
{
System.out.print(add4);
}
else
{
System.out.print (add4 +"," +"");
}
add4 =add4 + 4;
count500++;
}
2.- Do it right in your while:
while (count500++ <= 500)
In bove cases he will run the loop 500 times.
Here ya go:
int add4 = 0;
for (int i = 0; i > 500; i += 1) {
System.out.println(add4);
add4 += 4;
}
Let's break that down.
First, we're initialising the variable add4 at zero, which later, in the for loop, increases by 4 directly after being printed.
Then, since you only want to print add4 out 500 times, you declare a for loop, which initialises integer i at zero (int i = 0), then tells the loop to continue while i is less than 500 (i > 500), and finally tells i to increase by one each time you go through the loop (i += 1).
Within the loop, add4 is being printed out, then being incremented by four. The last value printed out should be 2000, but the value of add4 at the end should actually be 2004.
Hope that helps.
I'm not exactly sure what you are trying to do but try this:
public class TestSequence {
static final int AMOUNT_NEEDED = 500;
static final int INCREMENT = 4;
static final int UPPER_LIMIT = AMOUNT_NEEDED * INCREMENT;
public static void main(String[] args) {
for( int numberMod4 =0; numberMod4< UPPER_LIMIT; numberMod4+=INCREMENT)
System.out.println(numberMod4);}
}
In my java program I have a for-loop looking roughly like this:
ArrayList<MyObject> myList = new ArrayList<MyObject>();
putThingsInList(myList);
for (int i = 0; i < myList.size(); i++) {
doWhatsoever();
}
Since the size of the list isn't changing, I tried to accelerate the loop by replacing the termination expression of the loop with a variable.
My idea was: Since the size of an ArrayList can possibly change while iterating it, the termination expression has to be executed each loop cycle. If I know (but the JVM doesn't), that its size will stay constant, the usage of a variable might speed things up.
ArrayList<MyObject> myList = new ArrayList<MyObject>();
putThingsInList(myList);
int myListSize = myList.size();
for (int i = 0; i < myListSize; i++) {
doWhatsoever();
}
However, this solution is slower, way slower; also making myListSize final doesn't change anything to that! I mean I could understand, if the speed didn't change at all; because maybe JVM just found out, that the size doesn't change and optimized the code. But why is it slower?
However, I rewrote the program; now the size of the list changes with each cycle: if i%2==0, I remove the last element of the list, else I add one element to the end of the list. So now the myList.size() operation has to be called within each iteration, I guessed.
I don't know if that's actually correct, but still the myList.size() termination expression is faster than using just a variable that remains constant all the time as termination expression...
Any ideas why?
Edit (I'm new here, I hope this is the way, how to do it)
My whole test program looks like this:
ArrayList<Integer> myList = new ArrayList<Integer>();
for (int i = 0; i < 1000000; i++)
{
myList.add(i);
}
final long myListSize = myList.size();
long sum = 0;
long timeStarted = System.nanoTime();
for (int i = 0; i < 500; i++)
{
for (int j = 0; j < myList.size(); j++)
{
sum += j;
if (j%2==0)
{
myList.add(999999);
}
else
{
myList.remove(999999);
}
}
}
long timeNeeded = (System.nanoTime() - timeStarted)/1000000;
System.out.println(timeNeeded);
System.out.println(sum);
Performance of the posted code (average of 10 executions):
4102ms for myList.size()
4230ms for myListSize
Without the if-then-else statements (so with constant myList size)
172ms for myList.size()
329ms for myListSize
So the speed different of both versions is still there. In the version with the if-then-else parts the percentaged differences are of course smaller because a lot of the time is invested for the add and remove operations of the list.
The problem is with this line:
final long myListSize = myList.size();
Change this to an int and lo and behold, running times will be identical. Why? Because comparing an int to a long for every iteration requires a widening conversion of the int, and that takes time.
Note that the difference also largely (but probably not completely) disappears when the code is compiled and optimised, as can be seen from the following JMH benchmark results:
# JMH 1.11.2 (released 7 days ago)
# VM version: JDK 1.8.0_51, VM 25.51-b03
# VM options: <none>
# Warmup: 20 iterations, 1 s each
# Measurement: 20 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
...
# Run complete. Total time: 00:02:01
Benchmark Mode Cnt Score Error Units
MyBenchmark.testIntLocalVariable thrpt 20 81892.018 ± 734.621 ops/s
MyBenchmark.testLongLocalVariable thrpt 20 74180.774 ± 1289.338 ops/s
MyBenchmark.testMethodInvocation thrpt 20 82732.317 ± 749.430 ops/s
And here's the benchmark code for it:
public class MyBenchmark {
#State( Scope.Benchmark)
public static class Values {
private final ArrayList<Double> values;
public Values() {
this.values = new ArrayList<Double>(10000);
for (int i = 0; i < 10000; i++) {
this.values.add(Math.random());
}
}
}
#Benchmark
public double testMethodInvocation(Values v) {
double sum = 0;
for (int i = 0; i < v.values.size(); i++) {
sum += v.values.get(i);
}
return sum;
}
#Benchmark
public double testIntLocalVariable(Values v) {
double sum = 0;
int max = v.values.size();
for (int i = 0; i < max; i++) {
sum += v.values.get(i);
}
return sum;
}
#Benchmark
public double testLongLocalVariable(Values v) {
double sum = 0;
long max = v.values.size();
for (int i = 0; i < max; i++) {
sum += v.values.get(i);
}
return sum;
}
}
P.s.:
My idea was: Since the size of an ArrayList can possibly change while
iterating it, the termination expression has to be executed each loop
cycle. If I know (but the JVM doesn't), that its size will stay
constant, the usage of a variable might speed things up.
Your assumption is wrong for two reasons: first of all, the VM can easily determine via escape analysis that the list stored in myList doesn't escape the method (so it's free to allocate it on the stack for example).
More importantly, even if the list was shared between multiple threads, and therefore could potentially be modified from the outside while we run our loop, in the absence of any synchronization it is perfectly valid for the thread running our loop to pretend those changes haven't happened at all.
As always, things are not always what they seem...
First things first, ArrayList.size() doesn't get recomputed on every invocation, only when the proper mutator is invoked. So calling it frequently is quite cheap.
Which of these loops is the fastest?
// array1 and array2 are the same size.
int sum;
for (int i = 0; i < array1.length; i++) {
sum += array1[i];
}
for (int i = 0; i < array2.length; i++) {
sum += array2[i];
}
or
int sum;
for (int i = 0; i < array1.length; i++) {
sum += array1[i];
sum += array2[i];
}
Instinctively, you would say that the second loop is the fastest since it doesn't iterate twice. However, some optimizations actually cause the first loop to be the fastest depending, for instance, on memory walking strides that cause a lot of memory cache misses.
Side-note: this compiler optimization technique is called loop
jamming.
This loop:
int sum;
for (int i = 0; i < 1000000; i++) {
sum += list.get(i);
}
is not the same as:
// Assume that list.size() == 1000000
int sum;
for (int i = 0; i < list.size(); i++) {
sum += list.get(i);
}
In the first case, the compile absolutely knows that it must iterate a million times and puts the constant in the Constant Pool, so certain optimizations can take place.
A closer equivalent would be:
int sum;
final int listSize = list.size();
for (int i = 0; i < listSize; i++) {
sum += list.get(i);
}
but only after the JVM has figured out what the value of listSize is. The final keyword gives the compiler/run-time certain guarantees that can be exploited. If the loop runs long enough, JIT-compiling will kick in, making execution faster.
Because this sparked interest in me I decided to do a quick test:
public class fortest {
public static void main(String[] args) {
long mean = 0;
for (int cnt = 0; cnt < 100000; cnt++) {
if (mean > 0)
mean /= 2;
ArrayList<String> myList = new ArrayList<String>();
putThingsInList(myList);
long start = System.nanoTime();
int myListSize = myList.size();
for (int i = 0; i < myListSize; i++) doWhatsoever(i, myList);
long end = System.nanoTime();
mean += end - start;
}
System.out.println("Mean exec: " + mean/2);
}
private static void doWhatsoever(int i, ArrayList<String> myList) {
if (i % 2 == 0)
myList.set(i, "0");
}
private static void putThingsInList(ArrayList<String> myList) {
for (int i = 0; i < 1000; i++) myList.add(String.valueOf(i));
}
}
I do not see the kind of behavior you are seeing.
2500ns mean execution time over 100000 iterations with myList.size()
1800ns mean execution time over 100000 iterations with myListSize
I therefore suspect that it's your code that is executed by the functions that is at fault. In the above example you can sometimes see faster execution if you only fill the ArrayList once, because doWhatsoever() will only do something on the first loop. I suspect the rest is being optimized away and significantly drops execution time therefore. You might have a similar case, but without seeing your code it might be close to impossible to figure that one out.
There is another way to speed up the code using for each loop
ArrayList<MyObject> myList = new ArrayList<MyObject>();
putThingsInList(myList);
for (MyObject ob: myList) {
doWhatsoever();
}
But I agree with #showp1984 that some other part is slowing the code.
Why second loop is faster than first here.
public class Test2 {
public static void main(String s[]) {
long start, end;
int[] a = new int[2500000];
int length = a.length;
start = System.nanoTime();
for (int i = 0; i < length; i++) {
a[i] += i;
}
end = System.nanoTime();
System.out.println(end - start + " nano with i < a.length ");
int[] b = new int[2500000];
start = System.nanoTime();
for (int i = b.length - 1; i >= 0; i--) {
b[i] += i;
}
end = System.nanoTime();
System.out.println(end - start + " nano with i > = 0");
}
}
Output is
6776766 nano with i < a.length
5525033 nano with i > = 0
update - I have update the question according to the suggestion but I still see the difference in time. first loop is taking more time then second loop.
Most likely it's because you're fetching the value of a.length each iteration in the first case, as opposite to once in the second case.
try doing something like
int len = a.length;
and using len as the termination border for the loop.
this could potentially reduce the time of the first loop.
If I modified your first for loop slightly, you'll get a similar time:
int alength = a.length; // pre-compute a.length
start = System.currentTimeMillis();
for (int i = 0; i < alength; i++) {
a[i] += i;
}
$ java Test
8 millis with i<a.length
6 millis with i>=0
The main reason for the difference in times is -
"... Never use System.currentTimeMillis() unless you are OK with + or - 15 ms accuracy, which is typical on most OS + JVM combinations. Use System.nanoTime() instead." – Scott Carey Found Here
Update:
I believe someone mentioned in the comments section of your question that you should also warm up the kernel your testing on, before testing micro benchmarks.
Rule 1: Always include a warmup phase which runs your test kernel all the way through, enough to trigger all initializations and compilations before timing phase(s). (Fewer iterations is OK on the warmup phase. The rule of thumb is several tens of thousands of inner loop iterations.)
I have this bubblesort code that i'm performing a runtime analysis on recording the time it takes to sort the array. I was wondering if there is any way i could increment the size of the array using a loop? Because at the moment i am incrementing it 100 at a time manually and i need to reach an array size of 5000.
public class BubbleSortworking{
public static void main (String[] args) {
Random rand = new Random();
int myArray[] = new int[100]; //How to increment this using a loop
int count, count2;
count2 = 2; //amount of times to run the loop
//repeats the bubble sort, while also producing new arrays each time
for (count = 0; count < count2; count++){
for (int i = 0; i < myArray.length; i++){
myArray[i] = rand.nextInt(100) + 1; //produce numbers between 1 - ?
//System.out.print(myArray[i] + ", "); //displays unsorted array
}
bubble(myArray);
// uncomment below 2 lines to prove each new sorted array cycle is unique
//for (int i = 0; i < myArray.length; i++)
// System.out.print(myArray[i] + ", ");
}
}
public static void bubble(int myArray[]){
int temp;
long start = System.nanoTime();
//System.out.println("start " + start);
//for (count = 0; count < count2; count++){
for (int i=0; i < myArray.length - 1; i++) {
for(int j=myArray.length - 1; j > i; j--) {
if (myArray[j] < myArray[j-1]){
temp = myArray[j];
myArray[j] = myArray[j-1];
myArray[j-1] = temp;
}
}
}
long end = System.nanoTime();
System.out.println(end - start);
//System.out.println("elapsed time " + (end - start));
}
}
No you can't change the size of an array once created. You either have to allocate it bigger than you think you'll need or accept the overhead of having to reallocate it needs to grow in size. When it does you'll have to allocate a new one and copy the data from the old to the new.
You either need to use an ArrayList, which will do this for you but with extra overheads.
Or, you can allocate the array as size 5000 before you start, and record up to how many elements you have used so far in a variable (rather than relying on array.length)
Or, you can resize the array by making a new array which is bigger and copying all the elements to it (System.arrayCopy(..)), as well as putting the new ones in.
The answer by rizon is correct, you cannot change the size of an array. BTW, nowhere are you re-creating the array, nor do I see where you are processing 5000 elements. If you are concerned about processing time, you would not want to recreate/resize an array, as that would be very inefficient. You would want a different solution.
This may help you
int[] intA = new int[100];
int sizeToIncrement = 100;
for(int i=0;i<5000;i++) {
if(i== intA.length ) {
intA = Arrays.copyOf(intA, intA.length + sizeToIncrement);
}
intA[i] = i;
}