I am doing a project where I need to implement bubblesort, shellsort and quicksort algorithms in an array of 999 random doubles.
I need to measure the time it takes every algorithm to run.
I am using System.nanoTime() to measure this execution time for each algorithm. I have 3 buttons, one for each algorithm. Upon clicking a button, the timer starts, the function is called, the end timer is then called and the duration is calculated by having endtime-starttime. The duration is then printed on a label on top of the button.
public double[] randomArray = SortAlg.getArray();
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
long startTimeBubble = System.nanoTime();
SortAlg.bubble(randomArray);
long endTimeBubble = System.nanoTime();
long durationBubble = (endTimeBubble - startTimeBubble) / 1000000;
bubbleTiempo.setText("bubble took " + durationBubble + " ms");
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
long startTimeShellSort = System.nanoTime();
SortAlg.shellSort(randomArray);
long endTimeShellSort = System.nanoTime();
long durationShellSort = (endTimeShellSort - startTimeShellSort) / 1000000;
shellSortTime.setText("ShellSort took " + durationShellSort + " ms");
}
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
long startTimeQuickSort = System.nanoTime();
SortAlg.quickSort(randomArray, 0, randomArray.length - 1);
long endTimeQuickSort = System.nanoTime();
long durationQuickSort = (endTimeQuickSort - startTimeQuickSort) / 1000000;
quickSortTime.setText("Quicksort took " + durationQuickSort + " ms");
}
General clarifications:
1-getArray() generates a random array of 999 real (double) numbers between 0 and 2000.
2-None of the algorithm methods return an array, so this randomArray is NOT being saved as sorted, therefore, every time the button is clicked, the random array that is passed into the function is unsorted.
3-Every button has a unique label to display the results.
4-What you're seeing there is from the GUI class I created with Netbeans GUI editor, the buttons portion. Main simply creates a new GUI frame and sets it as visible, and the SortAlg contains the logic for the algorithms, which I already tested to be working.
But I have 2 issues here: If I click the button more than 1 time, the time decreases further for every click, until it's eventually 0, which makes no sense.
Also, I initially had a calculation error and I was dividing the time taken by 100000 rather than 1000000, but oddly enough, this was never giving me any errors. When I divide it by 1000000 though (which should be the correct operation for converting ns to ms) I sometimes get 0 MS execution time, which again makes no sense.
Lastly, and I know that this might be difficult to determine, but I was under the impression that quickSort had to be the fastest algorithm? But their execution times greatly vary within builds. Sometimes each one is 5 ms, other times its 30, other times its 68. I am concerned because it seems that, the first clicked is always the fastest one and the other ones end up being slower. I am not confident about these results at all.
When I divide it by 1000000 though (which should be the correct operation for converting ns to ms) I sometimes get 0 MS execution time, which again makes no sense.
Because you are using integer division:
long durationBubble = (endTimeBubble - startTimeBubble) / 1000000;
^^^^^^^
Just replace it with double to include the fraction:
double durationBubble = (endTimeBubble - startTimeBubble) / 1_000_000.0;
See:
Int division: Why is the result of 1/3 == 0?
Related
I use a while loop to repeat my codes in my program. I want to repeat a code 1000 times per second. How can I do this?
For the fixed-delay execution of some code, it might be a better approach to use a timer object, such as java.util.Timer or javax.swing.Timer, or even AnimationTimer, depending on what you're trying to accomplish. This being said, it's not possible to guarantee a frequency and a frequency of 1000/s (or period of 1ms) is quite fast, and java.util.Timer and javax.swing.Timer won't be able to keep up.
See also:
How to use swing timers
How to use Java.Util.Timer
High Resolution Timer in Java 5
I will show you an example of this using System.nanoTime() to determine how much time has passed, and will explain why your premise typically does not make much sense and you probably should not do this.
First off here is code that will execute a block of code 1000 times and will take 1 second to finish every time, as long as that code can be executed that quickly.
long startTime = System.nanoTime();
long currentTime = startTime;
int counter = 0;
while (((currentTime - startTime) < 1_000_000_000) || counter < 1000) { //Executes until 1 second has passed AND it has iterated 1000 times
counter++;
currentTime = System.nanoTime();
if (counter < 1000) {
//The code you want to execute 1000 times
System.out.println(counter);
}
}
System.out.println((currentTime - startTime)/1_000_000 + " milliseconds have passed.");
Now the problem with this code is you will obviously hit the 1000 executions before you hit 1 second, so it will sit in the loop doing nothing after the 1000 executions are completed to ensure the total time of the loop takes 1 second.
However what happens if that block of code takes so long that you cannot complete that code 1000 times within a second? It is impossible to go the other direction and add extra time to complete the 1000 executions, the 1000 executions will no longer take 1 second and it is impossible to fix this. The only way this can be done, is if you know that 1000 executions will be completed under 1 second and wait for the remaining time.
However, this does not seem like a good way to do things in general and you should not program in a way that depends on time AND loop iteration count, it just does not really make sense and there are likely better ways to do what your actual goal is.
Note: This code will only execute the block of code 1000 times, a single time. Surround all of this code by another loop if you want to do this multiple times.
EDIT:
Just to make it more clear I made an example that will take longer to execute than 1 second.
public static void main(String[] args){
long startTime = System.nanoTime();
long currentTime = startTime;
int counter = 0;
while (((currentTime - startTime) < 1_000_000_000) || counter < 1000) {
counter++;
currentTime = System.nanoTime();
if (counter < 1000) {
//The code you want to execute 1000 times
int count2 = 0;
while (count2 < 1000) { //1000 blank lines per loop to take a long time
count2++;
System.out.println();
}
System.out.println(counter);
}
}
System.out.println((currentTime - startTime)/1_000_000 + " milliseconds have passed.");
}
This will print blank lines just to ensure it takes a long time. For my system this outputted:
2831 milliseconds have passed.
The code took 2.8 seconds because time was no longer the restrictive condition, but 1000 iterations was, and there is no way to make this exact code run 1000 times per second, it is impossible.
TLDR: You can force something to take a minimum amount of a time, but you cannot force it to take a maximum amount of time.
Try to use a thread and use Thread.sleep() or System.currentTimeMillis() / 1000, this will give you the time in seconds.
I'm working on a game and I want my enemies to spawn with a delay between 1-5 seconds. My code for that part looks like this:
#Override
public void run() {
try {
while (true) {
Random r = new Random();
int cooldownTime = r.nextInt((5000 - 1000) + 1) + 1000;
long lastSpawn = 0;
long time = System.currentTimeMillis();
if (time > lastSpawn + cooldownTime) {
System.out.println(cooldownTime);
addEnemies();
lastSpawn = time;
}
If I understand nextInt correctly this should spawn enemies 1000-5000 ms apart every time, but my results are really weird and I can't quite figure out why. This is an example of what it would look like if I print cooldownTime.
2523
1190
1095
1061
1168
1119
1052
1159
1071
1076
1000
1394
1249
1070
And so on... It seems that the first enemy is truly spawned randomly and the others are always in the low 1000's. This happens every time. Does anyone know why it's like that? I'm quite lost.
Calling Random r = new Random(); repeatedly is extremely pathological and ruins the statistical properties of the generator. (The results you get are most likely a strong function of your system clock time.)
Do that step once and your results will be far better. (There are also more efficient ways to implement a delay than this - consider sleep - Java compilers are not yet optimising out burn loops.)
Note also that your observations are further complicated by the fact that you are not printing every number drawn.
Not sure if this your exact issue, but you had some problems with the logic of System.currentTimeMillis() and were just looking at the total current time and not the difference between the time.
Additionally you only want to look for a new random value once the if actually executes so you do not generate a Random number each loop iteration, but rather each time an enemy spawns you generate a new one for the next enemy.
Here is the modified code that takes all of this into account:
Random r = new Random();
long time = System.currentTimeMillis();
int cooldownTime = r.nextInt((5000 - 1000) + 1) + 1000;
while (true) {
long timeDifference = System.currentTimeMillis() - time;
if (timeDifference > cooldownTime) {
//addEnemies();
System.out.println(timeDifference); //Prints the time taken for enemy to spawn
cooldownTime = r.nextInt((5000 - 1000) + 1) + 1000;
time = System.currentTimeMillis(); //set the initial time again
}
}
This will generate a random number between 1000 and 5000 and execute the if block each time after the delay, resetting the values in the if to do it forever.
However, there are most likely better ways to add a delay to your logic like some comments pointed out(sleep), but this is the corrected logic for your method.
Well, first of all, several of your variables are being created INSIDE the loop. You need to move the creation of the Random object, as well as the lastSpawn and cooldown variables outside the loop. This is because the lastSpawn variable is being overwritten each time the loop executes with 0, meaning you're always checking if the current time is greater than 0. You need to store it outside the loop so that it will retain the last value you assigned to it. For the same reason, cooldown needs to be outside the loop because you're generating a new cooldown every loop, and System.currentTimeMillis() is ALWAYS going to be larger than it because System.currentTimeMillis() gets you the system time offset from January 1, 1970. Finally, as System.currentTimeMillis() is represented by a long, you'll want any time-related variables to be long as well, otherwise you could end up overflowing your variable if the current time in milliseconds is too high for an integer to store.
Here is a better way to achieve what you're looking to do:
import java.util.Random;
public class RandomCooldown {
public static void main(String [] args) {
Random rand = new Random();
long start = System.currentTimeMillis();
long lastSpawn = start;
long cooldown = getCooldown(rand);
while(true) {
long time = System.currentTimeMillis();
long elapsed = (time - lastSpawn);
if(elapsed >= cooldown) {
System.out.println("Adding enemies!");
cooldown = getCooldown(rand); // only generate a new cooldown once the old cooldown has been surpassed
lastSpawn = time;
}
}
}
public static long getCooldown(Random rand) {
return (long)((rand.nextInt(4000) + 1) + 1000);
}
}
Hope this helps!
Here is a suggestion that works as I think you like. I has not one but two loops. The outer loop generates new enemies and the inner loop makes updates (not sure how much of that this enemy generating thread needs to update but included it just in case).
public void run() {
Random r = new Random();
// setup
while (true) {
int wait = r.nextInt((5000 - 1000) + 1) + 1000;
long time = System.currentTimeMillis();
System.out.println("Adding enemies at " + time
+ ", next add roughly in " + wait + " ms.");
while (wait + time > System.currentTimeMillis()) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
// update
}
}
}
The Random object is reused and the call Thread.sleep(30) makes the thread hand over control for 30 ms, a time during which the CPU can do more useful things than busy wait. (30 is BTW not a magic number that must be used but just a number I chose. You need to experiment and find what number works best in your game.)
The print out shows what happens.
Adding enemies at 1565096018610, next add roughly in 2890 ms.
Adding enemies at 1565096021530, next add roughly in 2301 ms.
Adding enemies at 1565096023863, next add roughly in 4944 ms.
Adding enemies at 1565096028813, next add roughly in 3042 ms.
Adding enemies at 1565096031879, next add roughly in 2661 ms.
... and so on. The actual numbers will not be the same of course when you run this code but similar.
Hope this helps and good luck with your game!
It looks fine to me. You should probably use the same Random() instance for each iteration. And remember: humans have no ability to perceive randomness. Alternatively, you could try seeding the Random-Generator (using the Random(long seed) constructor), just in case there's some weird stuff happening with your seed.
This is just a hypothetical question, but could be a way to get around an issue I have been having.
Imagine you want to be able to time a calculation function based not on the answer, but on the time it takes to calculating. So instead of finding out what a + b is, you wish to continue perform some calculation while time < x seconds.
Look at this pseudo code:
public static void performCalculationsForTime(int seconds)
{
// Get start time
int millisStart = System.currentTimeMillis();
// Perform calculation to find the 1000th digit of PI
// Check if the given amount of seconds have passed since millisStart
// If number of seconds have not passed, redo the 1000th PI digit calculation
// At this point the time has passed, return the function.
}
Now I know that I am horrible, despicable person for using precious CPU cycles to simple get time to pass, but what I am wondering is:
A) Is this possible and would JVM start complaining about non-responsiveness?
B) If it is possible, what calculations would be best to try to perform?
Update - Answer:
Based on the answers and comments, the answer seems to be that "Yes, this is possible. But only if it is not done in Android main UI thread, because the user's GUI will be become unresponsive and will throw an ANR after 5 seconds."
A) Is this possible and would JVM start complaining about non-responsiveness?
It is possible, and if you run it in the background, neither JVM nor Dalvik will complain.
B) If it is possible, what calculations would be best to try to perform?
If the objective is to just run any calculation for x seconds, just keep adding 1 to a sum until the required time has reached. Off the top of my head, something like:
public static void performCalculationsForTime(int seconds)
{
// Get start time
int secondsStart = System.currentTimeMillis()/1000;
int requiredEndTime = millisStart + seconds;
float sum = 0;
while(secondsStart != requiredEndTime) {
sum = sum + 0.1;
secondsStart = System.currentTimeMillis()/1000;
}
}
You can and JVM won't complain if your code is not part of some complex system that actually tracks thread execution time.
long startTime = System.currentTimeMillis();
while(System.currentTimeMillis() - startTime < 100000) {
// do something
}
Or even a for loop that checks time only every 1000 cycles.
for (int i = 0; ;i++) {
if (i % 1000 == 0 && System.currentTimeMillis() - startTime < 100000)
break;
// do something
}
As for your second question, the answer is probably calculating some value that can always be improved upon, like your PI digits example.
I would like to compare the speed performance (if there were any) from the two readDataMethod() as I illustrate below.
private void readDataMethod1(List<Integer> numbers) {
final long startTime = System.nanoTime();
for (int i = 0; i < numbers.size(); i++) {
numbers.get(i);
}
final long endTime = System.nanoTime();
System.out.println("method 1 : " + (endTime - startTime));
}
private void readDataMethod2(List<Integer> numbers) {
final long startTime = System.nanoTime();
int i = numbers.size();
while (i-- > 0) {
numbers.get(i);
}
final long endTime = System.nanoTime();
System.out.println("method 2 : " + (endTime - startTime));
}
Most of the time the result I get shows that method 2 has "lower" value.
Run readDataMethod1 readDataMethod2
1 636331 468876
2 638256 479269
3 637485 515455
4 716786 420756
Does this test prove that the readDataMethod2 is faster than the earlier one ?
Does this test prove that the readDataMethod2 is faster than the earlier one ?
You are on the right track in that you're measuring comparative performance, rather than making assumptions.
However, there are lots of potential issues to be aware of when writing micro-benchmarks in Java. I would recommend that you read
How do I write a correct micro-benchmark in Java?
In the first one, you are calling numbers.size() for each iteration.
Try storing it in a variable, and check again.
The reason because of which the second version runs faster is because you are calling numbers.size() on each iteration. Replacing it by storing in a number would make it almost the same as the first one.
Does this test prove that the readDataMethod2 is faster than the earlier one ?
As #aix says, you are on the right track. However, there are a couple of specific issues with your methodology:
It doesn't look like you are "warming up" the JVM. Therefore it is conceivable that your figures could be distorted by startup effects (JIT compilation) or that none of the code has been JIT compiled.
I'd also argue that your runs are doing too little work. A 500000 nanoseconds, is 0.0005 seconds, and that's not much work. The risk is that "other things" external to your application could be introducing noise into the measurements. I'd have more confidence in runs that take tens of seconds.
I've made a class that controls the speed at which my program runs, kind of like a vertical sync, and it passes some necessary information to the program at each frame. I have the entire thing working, but I've tried using the more accurate Thread.sleep(long millis, int nanos), something I'm fairly inexperienced using. Based upon the descriptions I've seen, it simply adds the milliseconds provided to the nanoseconds, then pauses the thread. But, about 90% of the frames throw an odd exception, which I really cannot decipher.
java.lang.IllegalArgumentException: nanosecond timeout value out of range
The following is most of the code I used, that interacts in any way with the variable I use to delay the thread.
long startTime = System.nanoTime();
while (! this.stop)
{
try
{
// Run Frame
long endTime, deltaTime, deltaRemainder;
endTime = System.nanoTime();
deltaTime = endTime - startTime;
deltaRemainder = this.rate - (deltaTime % this.rate);
System.out.println("Frame Completed with "
+ (double)(deltaRemainder * .000000001) + " seconds left!");
if (deltaRemainder > 0)
Thread.sleep(0, (int)(deltaRemainder));
startTime = System.nanoTime();
}
catch (Exception e)
{
e.printStackTrace();
}
}
rate is the variable which is equal to the length of a frame in nanoseconds, stop is really unimportant, and apparent. start/endTime are the times at the start and end of a frame. deltaTime is the length of time the frame took to finish. And finally, deltaRemainder is the amount of extra time the frame should have taken to finish(if it takes longer than it should, it jumps up to end at the next possible frame).
Could anyone explain why this exception is thrown? I would really prefer to use the accuracy this function provides.
It seems that your deltaRemainder is outside of the allowed ranged between 0 and 999999.
From Thread.sleep documentation:
millis - the length of time to sleep in milliseconds.
nanos - 0-999999 additional nanoseconds to sleep.
So you should check if it is greater than 999999 and if so, put the value that is above 999999 into milliseconds, e.g.
int milliseconds = 0;
if ( deltaRemainder > 999999 ) {
milliseconds = deltaRemainder / 1000000;
deltaRemainder = deltaRemainder % 1000000;
}
if ( milliseocnds > 0 || deltaRemainder > 0) {
Thread.sleep(milliseconds, deltaRemainder);
}
Edit: My sample code is to be treated as "late night code", there are bugs in it ;).
Only a guess:
ints have 32bits so ints go from -2^31 to 2^31-1
If the deltaRemainder is too big it can overflow and the resulting int will be negative.
Can your deltaRemainder go over 2^31? (2GB which is aprox 2.000.000.000, it is: 2 secs?)
Other guess is:
deltaRemainder is > 0 but < 1. So the int'ed value is 0.