I'm supposed to be comparing a Recursive and a Non-Recursive function to see which one is quicker for a class project. The professor also wants us to time the iterations in milliseconds when the iterator is equal to 10,100,1000, etc. I got it all to work but was having loads of trouble in C++ getting the timer, so I switched to Java as it's much much easier to get millisecond output.
But now when I try to use any number over 8,000 I get a big fat stack overflow error from the Recursive algorithm. Can anyone give me any insight?
Bonus: I also can't figure out how to do the timer in the Recursive function like I did in the Non-Recursive. How would I approach this?
public class comparingTimes {
public static void main(String[] args) {
double num = 10000;
double result;
nonRec(num);
result = rec(num);
System.out.printf("Rec %.0f",(result));
}
public static void nonRec(double num)
{
double resultNum = 1;
double total = 0;
long startTime = System.currentTimeMillis();
long endTime;
for (double i = 1; i < num; i++)
{
total += i * (i+1);
if (i == resultNum)
{
endTime = System.currentTimeMillis();
System.out.printf("Total execution time: %f seconds - num = %.0f%n", (endTime - startTime)/1000.0, i);
resultNum *= 10;
}
}
System.out.printf("NonRec: %.0f%n", total);
}
public static double rec(double num)
{
if (num == 0)
return 0;
else
return num * (num-1) + rec(num-1);
}
}
The ideal use case for recursion is when you reduce the "search space" massively on each recursion level. For example, consider a binary search where each recursion level halves the remaining search space.
Your particular problem is that you're trying to do 8000 levels of recursion since each level simply decrements the value. That's going to require a fairly large chunk of stack space.
You can look into increasing the stack size for your JVM with the -ss or -oss options (depending on implementation, of course). But that will only buy you so much.
In terms of timing the whole recursive operation, I would simply store the time before the top-level call in main(), then compare that to the time after that top-level call returns, something like:
long startTime = System.currentTimeMillis();
result = rec(num);
long endTime = System.currentTimeMillis();
// Now calculate the elapsed time.
There's no need to try and do it within the recursive call itself.
If you want to do it at certain points within the recursive call, you can initialise a "global" counter variable (one outside the recursion itself, such as a class-level static variable) to 0 and have the recursive function increment it for every recursion level.
Then have it output the time deltas at the points you're interested in, such as when the variable is set to 10, 100, 1000 and so on.
Try increasing the stack size.
As for measuring time
public static void main(String[] args) {
double num = 10000;
double result;
long start = System.currentTimeMillis();
nonRec(num);
long finish = System.currentTimeMillis();
System.out.println("Time taken (non-recursive): " + (finish -start));
start = System.currentTimeMillis();
result = rec(num);
finish = System.currentTimeMillis();
System.out.println("Time taken (recursive): " + (finish -start));
System.out.printf("Rec %.0f",(result));
}
Related
I have a java project to do and the requirements are:
create a loop that repeats the following experiment 10 times. After all 10 iterations are complete, print the average time for one iteration of the experiment:
Select a random number r from 0 to n.
Using the System class, note the start time of the experiment
Repeatedly multiply two 9-digit values in a loop for r iterations. You need not preserve
the result of this multiplication.
note the end time of the experiment
This is what I have so far:
package lee_lab02;
import java.util.Random;
import java.util.Scanner;
public class Benchmark {
public Benchmark() {
}
public static void main(String[] args) {
System.out.println("Please enter a value for n:");
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
long start = System.currentTimeMillis();
for(int i=1; i<=10; i++)
{
Random rand = new Random();
double r = rand.nextInt(n);
for(int z=1;z<r;z++)
{
long num1 = 145893123;
long num2 = 901234278;
long num3 = num1 * num2;
}
}
long end = System.currentTimeMillis();
long totTime = end - start;
long avg = totTime/10;
System.out.println(avg);
}
}
The output of this prompts me with "Please enter a value for n:" but the time is not recorded. What am I doing wrong here?
There's nothing wrong with your program. It is just that you are performing trivial operations in your for loop that don't take much time at all. All the iterations are completed in less than 1 millisecond. Just add Thread.sleep(500); in your for loop and you will see the average getting printed as you expect it.
Also, use double for avg. (double avg = totTime/10.0;).
To perform this kind of benchmarl test, you better need to use nanoTime() (remember that 1 000 000ns = 1ms (currentTimeMillis)), except if your programm takes more than 10sec in that case get the time in ms is sufficient (but still possible to use nanoTime()) :
long start = System.nanoTime();
int nbRound = 10;
for (int i = 1; i <= nbRound; i++) {
//...
}
long end = System.nanoTime();
long totTime = end - start;
long avg = totTime / nbRound;
System.out.println(avg);
I'va also added a variable nbRound because it's very quick to make a mistake and write different values in the loop and in the computation of the average, so better use variable when you can
And because you program does small things you need to set n to a high value, my test :
n=100 ==> 105 673ns
n=100000 ==> 1 720 963ns (1.7ms)
The scan.nextInt() method is a blocking method. So your current thread blocks and the code never moves ahead to execute the remaining lines of code.
You need to change your design a bit to handle this blocking of nextInt() method. You can call the nextInt() method in another thread and remaining logic in another and can control their processing so your average time calculation logic runs.
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.
This is what I have so far. I have to write a for loop that prints the first 1000 perfect squares and also determines the time of execution. the timer is working but I don't really know how to show the 1000 perfect squares.
public class WhileLoop {
public static void main(String[] args) {
long time_start, time_finish;
time_start = time();
int i;
for( i =0; i< 1000; i++){
{
System.out.print("");
}
System.out.println(i);
}
time_finish = time();
System.out.println(time_finish - time_start + " milli seconds");
}
public static long time(){
Calendar cal = Calendar.getInstance();
return cal.getTimeInMillis();
}
}
You got to break down the problem 1 by 1. Long story short. You should do the following:
Get Start Time
Print 1*1
Print 2*2
Print 3*3 ... to first 1000 squares
Print Total Execution Time
Here are the code snippets you will need to get this to work:
Then using the tools that Java provides. You can:
Retrieve Current Time (Store this into a startTime variable)
Loop through 1000 elements and print results
Retrieve Current Time (Compare this with the startTime to get total RunTime)
I don't want to give away too much. So, hopefully this will provide a good push in the right direction.
I'm writing a fairly simple 2D multiplayer-over-network game. Right now, I find it nearly impossible for myself to create a stable loop. By stable I mean such kind of loop inside which certain calculations are done and which is repeated over strict periods of time (let's say, every 25 ms, that's what I'm fighting for right now). I haven't faced many severe hindrances this far except for this one.
In this game, several threads are running, both in server and client applications, assigned to various tasks. Let's take for example engine thread in my server application. In this thread, I try to create game loop using Thread.sleep, trying to take in account time taken by game calculations. Here's my loop, placed within run() method. Tick() function is payload of the loop. It simply contains ordered calls to other methods doing constant game updating.
long engFPS = 40;
long frameDur = 1000 / engFPS;
long lastFrameTime;
long nextFrame;
<...>
while(true)
{
lastFrameTime = System.currentTimeMillis();
nextFrame = lastFrameTime + frameDur;
Tick();
if(nextFrame - System.currentTimeMillis() > 0)
{
try
{
Thread.sleep(nextFrame - System.currentTimeMillis());
}
catch(Exception e)
{
System.err.println("TSEngine :: run :: " + e);
}
}
}
The major problem is that Thread.sleep just loves to betray your expectations about how much it will sleep. It can easily put thread to rest for much longer or much shorter time, especially on some machines with Windows XP (I've tested it myself, WinXP gives really nasty results compared to Win7 and other OS). I've poked around internets quite a lot, and result was disappointing. It seems to be fault of the thread scheduler of the OS we're running on, and its so-called granularity. As far as I understood, this scheduler constantly, over certain amount of time, checks demands of every thread in system, in particular, puts/awakes them from sleep. When re-checking time is low, like 1ms, things may seem smooth. Although, it is said that WinXP has granularity as high as 10 or 15 ms. I've also read that not only Java programmers, but those using other languages face this problem as well.
Knowing this, it seems almost impossible to make a stable, sturdy, reliable game engine. Nevertheless, they're everywhere.
I'm highly wondering by which means this problem can be fought or circumvented. Could someone more experienced give me a hint on this?
Don't rely on the OS or any timer mechanism to wake your thread or invoke some callback at a precise point in time or after a precise delay. It's just not going to happen.
The way to deal with this is instead of setting a sleep/callback/poll interval and then assuming that the interval is kept with a high degree of precision, keep track of the amount of time that has elapsed since the previous iteration and use that to determine what the current state should be. Pass this amount through to anything that updates state based upon the current "frame" (really you should design your engine in a way that the internal components don't know or care about anything as concrete as a frame; so that instead there is just state that moves fluidly through time, and when a new frame needs to be sent for rendering a snapshot of this state is used).
So for example, you might do:
long maxWorkingTimePerFrame = 1000 / FRAMES_PER_SECOND; //this is optional
lastStartTime = System.currentTimeMillis();
while(true)
{
long elapsedTime = System.currentTimeMillis() - lastStartTime;
lastStartTime = System.currentTimeMillis();
Tick(elapsedTime);
//enforcing a maximum framerate here is optional...you don't need to sleep the thread
long processingTimeForCurrentFrame = System.currentTimeMillis() - lastStartTime;
if(processingTimeForCurrentFrame < maxWorkingTimePerFrame)
{
try
{
Thread.sleep(maxWorkingTimePerFrame - processingTimeForCurrentFrame);
}
catch(Exception e)
{
System.err.println("TSEngine :: run :: " + e);
}
}
}
Also note that you can get greater timer granularity by using System.nanoTime() in place of System.currentTimeMillis().
You may getter better results with
LockSupport.parkNanos(long nanos)
altho it complicates the code a bit compared to sleep()
maybe this helps you.
its from david brackeen's bock developing games in java
and calculates average granularity to fake a more fluent framerate:
link
public class TimeSmoothie {
/**
How often to recalc the frame rate
*/
protected static final long FRAME_RATE_RECALC_PERIOD = 500;
/**
Don't allow the elapsed time between frames to be more than 100 ms
*/
protected static final long MAX_ELAPSED_TIME = 100;
/**
Take the average of the last few samples during the last 100ms
*/
protected static final long AVERAGE_PERIOD = 100;
protected static final int NUM_SAMPLES_BITS = 6; // 64 samples
protected static final int NUM_SAMPLES = 1 << NUM_SAMPLES_BITS;
protected static final int NUM_SAMPLES_MASK = NUM_SAMPLES - 1;
protected long[] samples;
protected int numSamples = 0;
protected int firstIndex = 0;
// for calculating frame rate
protected int numFrames = 0;
protected long startTime;
protected float frameRate;
public TimeSmoothie() {
samples = new long[NUM_SAMPLES];
}
/**
Adds the specified time sample and returns the average
of all the recorded time samples.
*/
public long getTime(long elapsedTime) {
addSample(elapsedTime);
return getAverage();
}
/**
Adds a time sample.
*/
public void addSample(long elapsedTime) {
numFrames++;
// cap the time
elapsedTime = Math.min(elapsedTime, MAX_ELAPSED_TIME);
// add the sample to the list
samples[(firstIndex + numSamples) & NUM_SAMPLES_MASK] =
elapsedTime;
if (numSamples == samples.length) {
firstIndex = (firstIndex + 1) & NUM_SAMPLES_MASK;
}
else {
numSamples++;
}
}
/**
Gets the average of the recorded time samples.
*/
public long getAverage() {
long sum = 0;
for (int i=numSamples-1; i>=0; i--) {
sum+=samples[(firstIndex + i) & NUM_SAMPLES_MASK];
// if the average period is already reached, go ahead and return
// the average.
if (sum >= AVERAGE_PERIOD) {
Math.round((double)sum / (numSamples-i));
}
}
return Math.round((double)sum / numSamples);
}
/**
Gets the frame rate (number of calls to getTime() or
addSample() in real time). The frame rate is recalculated
every 500ms.
*/
public float getFrameRate() {
long currTime = System.currentTimeMillis();
// calculate the frame rate every 500 milliseconds
if (currTime > startTime + FRAME_RATE_RECALC_PERIOD) {
frameRate = (float)numFrames * 1000 /
(currTime - startTime);
startTime = currTime;
numFrames = 0;
}
return frameRate;
}
}
what is the correct code to calculating time in Java with
public static int getGcd( int a, int b, int temp) format?
A simple solution:
First, Grab and store the time before you start the piece of code you want the run time for:
long start =System.currentTimeMillis();
After the code that you are tracking grab the current time and subtract it from your starting point to get the total time elapsed:
System.out.println(System.currentTimeMillis() - start);
If it runs relatively fast and you're trying to get an average time by running it on a bunch of random inputs, use:
long totalTime = 0;
long start = System.nanoTime();
for(int i=0;i<n;i++){
//Generate a and b
getGcd(a, b);
}
long end = System.nanoTime();
totalTime = end - start;
start = System.nanoTime();
for (int i=0;i<n;i++){
//Generate a and b
}
end = System.nanoTime();
totalTime -= end - start;
return totalTime / n;
This gives you your average time in nanoseconds.
Finding the average running time of GCD is a very interesting and complex problem. In the worst case, the inputs have a ratio which is close to the golden mean (such as consecutive Fibonacci numbers) and then the running time is O(log n). But it's still possible to have extremely large inputs and end up with essentially constant time. I'd be curious to know your results.