I am running a very simple program which simulate tower of hanoi.
I print the time taken to move n number (20 to 30) disks.
I see a strange pattern . It takes roughly the same amount of time to move n(even number) and n+1 disks. And to move n+2 disk it takes 4 times of n disks .
I have put the program below. I guess there is some optimization being done in vm when we have multiple recursion calls.
Can anyone put more light on this?
public class Hanoi {
public static void move(int n) {
if(n > 0) {
move(n-1);
move(n-1);
}
}
public static void main(String[] args) {
int N = 28;
move(12);
for(int n=18; n <= N; n++) {
long start = System.currentTimeMillis();
move(n);
long end = System.currentTimeMillis();
System.out.printf("n=%d t=%d i=%d\n",n, (end-start) , 10);
}
}
}
This "problem"? :-)
If you add IO or some decent computations to the move method, you will see that this behavior disappears. Also, if you just do one move recursive call, the program finishes immediately. Both of these timing anomalies are due to compiler and JIT optimization as Gunner mentioned. This version of your move method for example has much more expected timing:
static int[] pieces = new int[100];
public static void move(int n) {
if (n > 0) {
// random memory operations
pieces[n - 1] = pieces[n];
pieces[n] = pieces[n + 1];
pieces[n + 1] = pieces[n + 2];
move(n - 1);
move(n - 1);
}
}
Here's an interesting piece by IBM about tail recursion. Here's another blog posting about the topic.
Related
This question already has answers here:
How do I write a correct micro-benchmark in Java?
(11 answers)
Closed last month.
Here is my code - it is just a basic introduction to parallel computing that was done in class. There was supposed to be a speedup of around 2 for numbers being added up in a random array. All but about four people were getting the correct results. To note, I am using a 2020 MacBook Air with a 1.2Ghz Quad-Core I7.
import java.util.Arrays;
public class TestProgram
{
public static double addSequential(double\[\] values) //method that adds numbers in an array.
{
double sum = 0;
for(int i=0; i\<values.length; i++)
sum += values\[i\];
return sum;
}
public static double addParallel(double[] values) //method that adds code to potentially do parallel computing.
{
int mid = values.length / 2; //calculates a mid point.
SumArrayTask left = new SumArrayTask(0, mid, values);
SumArrayTask right = new SumArrayTask(mid, values.length, values);
left.fork();
right.compute();
left.join();
return left.getResult() + right.getResult();
}
public static void main(String[] args)
{
double[] arr = new double[10];
for(int i = 0; i<arr.length; i++) //create an array with 10 RANDOM values 0-100
arr[i] = Math.floor(100*Math.random()); //Math.random picks a random # between 0-1, so we multiply by 100.
System.out.println(Arrays.toString(arr));
long start, sequentialTime, parallelTime;
start = System.nanoTime();
System.out.println("Result (sequential): " + addSequential(arr)); //Prints out all elements of array added up.
System.out.println("Time: " + (sequentialTime = System.nanoTime() - start) + " ns"); //Prints how many nanoseconds the processing takes.
start = System.nanoTime();
System.out.println("Result (parallel): " + addParallel(arr)); //Prints out all elements of array added up with parallel
System.out.println("Time: " + (parallelTime = System.nanoTime() - start) + " ns"); //Prints how many nanoseconds the parallel processing takes.
System.out.println("Speedup: " + sequentialTime / parallelTime);
}
}
import java.util.concurrent.RecursiveAction;
public class SumArrayTask extends RecursiveAction
{
private int start;
private int end;
private double[] data;
private double result;
public SumArrayTask(int startIndex, int endIndex, double[] arr)
{
start = startIndex;
end = endIndex;
data = arr;
}
public double getResult() //getter method for result
{
return result;
}
protected void compute()
{
double sum = 0;
for(int i = start; i<end; i++)
sum += data[i];
result = sum;
}
}
My result:
I was expecting a speedup of around 2. I've had others try and they get a completely different result with their pc's. I am completely unsure if it may have something to do with my setup or the code itself. I appreciate any help.
First of all, your way of "benchmarking" will always give misleading results:
You do I/O (System.out()) within the benchmarked code. This alone will take much longer than adding ten numbers.
You do not execute the code multiple times. The first executions in Java will always be slower than later ones, due to the "learning phase" of the Hotspot compiler.
Seeing that a simple "add ten doubles" task seemingly takes more than 100,000 clock cycles could already have alarmed you that your measuring must be wrong. Ten additions should not take more than maybe 100 cycles or so.
Now let's talk about parallel execution. There is a cost to creating and managing a thread (or letting the java.util.concurrent package do it for you), and this can be quite high. So, although each parallel task will probably (*) consume less time than the full loop, the management time for the threads will outweigh that by far in your case.
So, in general, only think about parallel execution for code that takes seconds, not microseconds.
(*) It's not even as clear that the half-array loops will take less time than the full-array loop, as there are more variables involved, making it harder for the Hotspot compiler to do aggressive optimizations like e.g. loop unfolding.
I wrote a small program to find the first 5 Taxicab numbers (so far only 6 are known) by checking each integer from 2 to 5E+15. The definition of Taxicab numbers is here.
However, my program took 8 minutes just to reach 3E+7. Since Taxicab(3) is in the order of 8E+7, I hesitate to let it run any further without optimizing it first.
I'm using NetBeans 8 on Ubuntu 16.10 on a HP 8560w, i7 2600qm quad core, 16GB RAM. However, Java only uses 1 core, to a maximum of 25% total CPU power, even when given Very High Priority. How do I fix this?
public class Ramanujan
{
public static void main(String[] args)
{
long limit;
//limit = 20;
limit = 500000000000000000L;
int order = 1;
for (long testCase = 2; testCase < limit; testCase++)
{
if (isTaxicab(testCase, order))
{
System.out.printf("Taxicab(%d) = %d*****************************\n",
order, testCase);
order++;
}
else
{
if (testCase%0x186a0 ==0) //Prints very 100000 iterations to track progress
{
//To track progress
System.out.printf("%d \n", testCase);
}
}
}
}
public static boolean isTaxicab(long testCase, int order)
{
int way = 0; //Number of ways that testCase can be expressed as sum of 2 cube numbers.
long i = 1;
long iUpperBound = (long) (1+Math.cbrt(testCase/2));
//If testCase = i*i*i + j*j*j AND i<=j
//then i*i*i cant be > testCase/2
//No need to test beyond that
while (i < iUpperBound)
{
if ( isSumOfTwoCubes(testCase, i) )
{
way++;
}
i++;
}
return (way >= order);
}
public static boolean isSumOfTwoCubes(long testCase,long i)
{
boolean isSum = false;
long jLowerBound = (long) Math.cbrt(testCase -i*i*i);
for (long j = jLowerBound; j < jLowerBound+2; j++)
{
long sumCubes = i*i*i + j*j*j;
if (sumCubes == testCase)
{
isSum = true;
break;
}
}
return isSum;
}
}
The program itself will only ever use one core until you parallelize it.
You need to learn how to use Threads.
Your problem is embarrassingly parallel. Parallelizing too much (i.e. creating too many threads) will be detrimental because each thread creates an overhead, so you need to be careful regarding exactly how you parallelize.
If it was up to me, I would initialize a list of worker threads where each thread effectively performs isTaxicab() and simply assign a single testCase to each worker as it becomes available.
You would want to code such that you can easily experiment with the number of workers.
Hey guys so in my interview question I was given something like this below. By the way this is my code to solve fib. I want to improve this my code to eliminate repetition of fibonacci sequence that might end up being repeated at the process. For example if fib(1) and fib(1) are repeated twice, how to do I avoid this from happening so the program can advance to unique sequence being processed.
I really want to know how to improve this code. My solution is below but when I debug it, I feel like I get lost understanding what is really happening.
Thanks.
public class Fib {
public static void main(String[] args) {
System.out.print(fibonacci(14));
}
private static int fibonacci(int n) {
int fibArray[] = new int[n];
if (n <= 0) {
return 1;
} else if (n == 1) {
return 1;
} else {
fibArray[0] = fibonacci(n - 1);
fibArray[1] = fibonacci(n - 2);
if (fibArray[0] == fibonacci(n - 1)) {
return fibonacci(n - 1) + fibonacci(n - 2);
} else if (fibArray[1] != fibonacci(n - 2)) {
return fibonacci(n - 1) + fibonacci(n - 2);
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
}
}
To solve the nth Fibonacci number, basic recursion like your answer is not the best way.
There is a complicated matrix method to solve Fibonacci that uses O(log(n)) runtime and O(log(n)) memory.
If you want performance and simplicity in your Fibonacci solution, this is a neat formula (though this is memorization and defeats the problem solving part of the interview):
Here is a Java method implementation:
public Long fibonacci(int n)
{
double sqrt5 = Math.sqrt(5);
int tmp1 = (int)(1+sqrt5)/2;
int tmp2 = (int)(1-sqrt5)/2;
return (long) Math.ceil((Math.pow(tmp1, n) - Math.pow(tmp2, n))/sqrt5);
}
This method looks O(1) but it's not quite as the Math.pow() is O(log(n)). It uses O(1) memory.
As #PavelS mentioned. Should be something similar to this where n is your parameter:
int a = 0;
int b = 1;
// In N steps compute Fibonacci sequence iteratively.
for (int i = 0; i < n; i++)
{
int temp = a;
a = b;
b = temp + b;
}
return a;
You need to store the value once computed. If value is present, dont compute again, just use it, else calculate and store:
public class Fib {
static int fibo[]=new int[100];
public static void main(String[] args) {
Arrays.fill(fibo, 0);
System.out.print(fibonacci(24));
}
private static int fibonacci(int n) {
if (n <= 0)
fibo[n]=0;
else if (n == 1)
fibo[n]= 1;
else if(fibo[n]==0)
fibo[n]=fibonacci(n-1)+fibonacci(n-2);
return fibo[n];
}
}
Lets generalize this a little.
There are many techniques that can be used to optimize a recursive function. Here are some of them:
Memoization: you may be able to reduce the cost of repeated calls to an (expensive) function f(n) with the same argument. This can be done by creating a map n -> f(n) and doing a map lookup before making the expensive call.
Converting recursion into iteration. A compiler for a functional programming language will typically do this automatically for simple cases (tail calls). The Java compiler won't (for technical reasons which are off track) ... but you can do the same optimization at the source code level.
Converting call-stack recursion into iteration with a stack-like data structure. This is something you might do in Java to avoid StackOverflowError exceptions in deeply recursive problems that are no amenable to other optimizations.
The solution might be to solve a recurrence relation rather than trying to compute it.
Obviously, not all techniques will work for any given problem.
The other answers give examples of most of approaches.
Approach #1 - #Dip
Approach #2 - #FirstStep
Approach #4 - #PhotometricStereo
I was writing a recursive algorithm to calculate Fibonacci numbers in Java as part of a programming 101 course. This is the code:
public class Fib {
public static void main(String[] args) {
Fib fib = new Fib();
}
public Fib() {
int end = 9;
long[] nums = new long[2];
printFib(0, end, nums);
}
private void printFib(int i, int end, long[] nums) {
while(i < end) {
if(i == 0 || i == 1) {
nums[i] = 1;
System.out.println("1");
} else {
long fib;
fib = 0;
fib += (nums[0] + nums[1]);
nums[0] = nums[1];
nums[1] = fib;
System.out.println(fib);
}
i++;
printFib(i, end, nums);
}
}
}
As I was stepping through the program it was working as intended until i became equal to end, the variable telling the printFib method how many Fibonacci numbers it should print out. When ì was equal to end while(i < 1) returns false as expected and the program go to the last }, now you'd(me)
expect the program to return the constructor from which I initially called the function and the program should exit, this not the case. The program goes back to the while statement and somehow evaluates to false again. Then it does the same thing again except the second time it decreases i by 1(what?!) and then proceeds to the else clause when it reaches the if statement. It then does the same thing over and over alternating the amount it subtracts from i between 1 and 2. I've asked my teacher about this and he was unable to explain it.
The program works fully like I intended if I replace the while with an if so maybe there is something about while that I don't know.
Edit
So I realize now that each time the method is called i has a different value which is stored and when the method exits and i = end the program goes back to the previous calls where i had a different value.
You implemented an iterative algorithm to calculate Fibonacci series. That's what the while loop does. There is no point in making the recursive call - printFib(i, end, nums) - at the end.
If you intended a recursive implementation, the entire while loop is not needed.
This code doesn't look right to me.
I would recommend that you not print from your method. Return a value to the main and let it print.
Your recursive method should not have a while loop in it. That's iteration - exactly what you're trying to avoid here.
Your method should have a stopping condition and a call to itself. That's not what you're doing.
Think about it like this:
/**
* Recursive Fibonnaci
* User: mduffy
* Date: 2/11/2015
* Time: 8:50 AM
* #link http://stackoverflow.com/questions/28455798/strange-behavior-in-recursive-algorithm/28455863#28455863
*/
public class Math {
private static Map<Integer, Integer> memo = new ConcurrentHashMap<Integer, Integer>();
public static void main(String [] args) {
for (String arg : args) {
int n = Integer.valueOf(arg);
System.out.println(String.format("n: %d fib(n): %d", n, fibonnaci(n)));
}
}
public static int fibonnaci(int n) {
if (n < 0) throw new IllegalArgumentException("index cannot be negative");
int value = 0;
if (memo.containsKey(n)) {
value = memo.get(n);
} else {
if (n <= 1) {
value = n;
} else {
value = fibonnaci(n-1)+fibonnaci(n-2);
}
memo.put(n, value);
}
return value;
}
}
Basicly this is happening because i would guess that you are thinking of i as an reference which will influence the basic callings of the Fibunacci method calling the sub Fibunacci method. This will finally lead way to many calls of the fibunacci method.
in my eyes the loop doesn´t make sense in your recursive way of solving it.
Hi
I have a question that this is my class which for each "n" will get the average time for it.
also the method that I want to take its performance has T(n)= O(nlogn)
my code :
public class NewClass1 {
public static void main(String[] args) {
List<Point> randList = new ArrayList<Point>();
for (int n = 100; n <= 500; n+=200) {
Random rand = new Random();
for (int i = 1; i <= n; i++) {
Point point = new Point(rand.nextInt(10), rand.nextInt(10));
randList.add(point);
}
get(randList);
}
}
public static void get(List<Point> list) {
long time = 0;
for(int i=1;i<10;i++) {
long t = System.currentTimeMillis();
GrahamVersion.grahamScan(list);
long t0 = System.currentTimeMillis();
time = time+t0-t;
}
System.out.println((double)time/10);
}
}
and it will print:
1.5
1.6
0.0
the average time is OK? because for n = 500 will have 0.0 and for n = 300 will have 1.6
A number of things that are / may be causing "strange" results.
First, your benchmarking is not taking account of the need to "warm up" the JVM. You should put a big loop around the benchmark code and run it a number of times until the numbers seem to stabilize. For example:
public static void main(String[] args) {
while (true) {
List<Point> randList = new ArrayList<Point>();
for (int n = 100; n <= 500; n+=200) {
...
}
}
}
(By running the benchmark in a loop like this, you give the JVM a chance to load and compile the code classes to native code, so that your results are not distorted by the overheads of class loading, JIT compilation and so on.)
Second, you should be printing the results with greater precision.
Third, you should be looking at more than just 3 datapoints.
Finally, you may have fallen into the trap of assuming that big O allows you to predict behavior with small values of N. This is not correct. It only tells you what happens as N tends to infinity. And even then, it only tells you the upper bound performance.
You need to run the test for at least 2 seconds before you will get reproduceable results. Your test runs so fast that your can't measure it with currentTimeMillis, I suggest using System.nanoTime(), after you have run the test for 2 secs.