Fibonacci sequence using BigInteger Does not yield an answer - java

Im to find 100th element of a Fibonacci Sequence, I initially tried to store the value of numbers using an int but it overflowed and switched to negative values just like long.Then I came across BigInteger I did get the solution using a simple for loop and an array to store the results, and access the previous elements. Now as Im trying to do the same problem using recursion The program does not seem to be terminating. Am I missing something here? Or are BigInteger's not suggested to used with recursion? Here is the code:
import java.math.BigInteger;
class Test {
public static void main(String[] args) {
BigInteger n = BigInteger.valueOf(100);
System.out.println(fib(n));
}
public static BigInteger fib(BigInteger n) {
if (n.compareTo(BigInteger.valueOf(1)) == 0 || n.compareTo(BigInteger.valueOf(1)) == -1)
return n;
return fib(n.subtract(BigInteger.valueOf(1))).add(fib(n.subtract(BigInteger.valueOf(2))));
}
}

In the comments, you mentioned that your assumption that the program doesn't terminate is based on the fact that it ran for over 5 minutes. That is not how you prove non-termination.
If you observe the program terminating within a certain amount of time, then you can conclude that it does, indeed, terminate. However, if you don't observe it terminating within a certain amount of time, then you can say precisely nothing about whether it terminates or not. It may terminate if you wait a little bit longer, it may terminate if you wait a lot longer, it may even theoretically terminate but take longer than the heat death of the universe.
In your specific case, the algorithm is perfectly correct, and it always terminates. It is simply not a very efficient algorithm: for computing fib(n), fib gets called fib(n) times, because you compute the same numbers over and over and over and over again.
If we assume that you can execute fib once per clock cycle (which is an optimistic assumption since a single call to fib performs one condition, two subtractions, one addition, and two calls to fib in most cases, and a single addition may already take multiple clock cycles depending on the CPU), and we further assume that you have a 100 core CPU and your code is actually executed in parallel, and you have 100 CPUs, and each CPU is clocked at 100 GHz, and you have a cluster of 100 computers, then it will still take you about an hour.
Under some more realistic assumptions, the time it takes your program to finish is more on the order of tens of thousands of years.
Since your code is not parallelized, in order for your code to finish in 5 minutes on a more realistic 4 GHz CPU, it would need to execute fib almost 300 million times per clock cycle.
It often helps to do some very rough guesstimates of the expected performance of your code. As you can see, you don't need to be an expert in Java or JVM or compilers or optimization or computer organization or CPU design or performance engineering. You don't need to know what, exactly, your code gets compiled down to. You don't need to know how many clock cycles an integer ADD takes. Because even when you make some totally over-the-top ridiculous assumptions, you can still easily see that your code cannot possibly finish in minutes or even hours.

Related

How can I measure the searching time in linkedlists java

I need to measure the searching time for LinkedLists for different values. My solution is not logical, so i don't know if i'm in the right path or not.
This is my solution;
LinkedList<Integer> myList = new LinkedList<>();
for (int i = 1; i <= 1000; i++)
myList.add(i);
Collections.shuffle(myList);
Random rand = new Random();
myList.contains(rand.nextInt(myList.size()));
System.out.println(System.nanoTime());
LinkedList<Integer> myList2 = new LinkedList<>();
for (int i = 1; i <= 2000; i++)
myList2.add(i);
Collections.shuffle(myList2);
myList.contains(rand.nextInt(myList2.size()));
System.out.println(System.nanoTime());
These are my outputs
38565758048600
38565759163200
You can't measure performance like this. Computers are not reliable; not today, and haven't been for decades. OSes pre-empt. the JVM JITs. CPUs have cores. Cores have pipelines and tiered caches. You're hopelessly out of luck; the nanotime between a single contains says absolutely not a thing - it's like trying to measure the effect of someone in honolulu peeing in the water by checking the height of the ocean lapping at the pier in Amsterdam. About a billion other factors that are far more impressive in magnitude are involved.
The normal principle for measuring performance is to mark the time, do the thing, and then mark time again. The difference in time? That's how long it took. But you have to run the operation not once; but many many times (and then take the average), and don't actually take the timing seriously until it's run a few times to ensure cache lines and JIT processes have stabilized out. You also need to ensure that the VM hotspot engine won't optimize your entire code away, so you must also actually use the result (you are throwing away the boolean that contains returns; this may lead the hotspot engine to realize that it can just eliminate the entire call, as it couldn't possibly change the list.
This is, in a word, completely and utterly impossible for any java newbie; even a grizzled old veteran is extremely likely to do it wrong, and as it is about timing, it's very hard to 'test' that your timing framework actually works.
Fortunately, you don't have to write it. It already exists: JMH. You either use that, or a direct competitor of that, or you are getting almost certainly complete lies and fabrications out of your timing code.
Note that the involvement of Random is a very bad idea for timing; you want the code you are timing to be as reliable as possible. Thus, do not shuffle the list, and do not ask for a random number. Ask for a specific number every time, or a host of numbers, or duplicate the list, shuffle that, then search for every number - this means that all numbers in the input list are searched for exactly once, but in an arbitrary order.

'Rule of a thumb' for cost of printing

I've noticed that
int i=10000000;
boolean isPrime= false;
while(!isPrime){
i++;
System.out.println(item); //this kills performance
isPrime = checkIfPrime(i);
}
}
Printing the current value of a variable kills performance. I want to print it once in a while, but keep the cost of this operation low.
How to compare the cost of printing to screen to computation? Are there any tricks to minimize this cost [Should I print one out of 10 records, or will this cost just as much because of conditional check]?
Why do I need this? Well, I am doing fun stuff with Java (such as "find a counterexample for Euler's conjuncture... 27^5 + 84^5 + 110^5 + 133^5 = 144^5 (Lander & Parkin, 1966),"). I want to write a program that is both correct and fast (this counterexample was discovered in 60s, so I should be able to do it in reasonable time). While debugging I want to have as much info and possible and I want to find the counterexample asap. What is my best way to proceed? Print each case? - Too slow. Let it run overnight? What if I missed some i++?
How to compare the cost of printing to screen to computation?
It is not possible. The cost (i.e elapsed time) of printing depends on where the "printed" characters go. I can trivially construct an example where the cost tends to infinity.
$ java YourClass | ( sleep 10000000000 )
After a few lines of output, the pipeline buffers will fill, and the print calls in your application will block.
Are there any tricks to minimize this cost [Should I print one out of 10 records, or will this cost just as much because of conditional check]?
There is nothing that won't introduce another overhead; e.g. the overhead of testing whether or not to print.
The only way to entirely eliminate the print overhead is to not print at all while you are trying to measure performance.
What is my best way to proceed? Print each case? - Too slow. Let it run overnight? What if I missed some i++?
First run the program with the print statements to check that you are getting the right answers.
Then remove the print statements and run again to get your performance measures.
However:
Beware of the various traps in writing Java micro-benchmarks.
Trawling through pages and pages of trace prints is not a good way to check for (possible) faults in your program.
Yes printing is expensive. A processor can do millions of operations in the time span it takes to print to the terminal/IDE. If you are using eclipse or terminal it it very much time consuming. If you are using a terminal You need to redirect it to a file using >> or > or write it to a file using nio or io library. Print anything only if its inevitable, else i feel you should never print if performance is an issue.
Following is the fastest that you can do to compute the next prime and print as well all those numbers that you tested in the process (provided the next prime does not cause overflow of int):
int i = 10000000;
boolean isPrime = false;
while (!isPrime) {
i++;
// System.out.println(item); //this kills performance
isPrime = checkIfPrime(i);
}
for (int j = 10000001; j <= i; j++) sysout(j);
If you need to benchmark your code performance, you cant have print statements. For few iterations you have to print, do your debugging and remove the print statements once u know that your code is working correctly. And then do time measure of your code.
Else if you want to have print statements always in your code, its upto you to decide how much delay you can accept. For example, a Xeon processor can give you 28-35 Gflops/IOPS (operations per second), that means the processor can do 35*10^9 increment operations per second(it can do i++ for 35*10^9 times/sec). and as per this (https://stackoverflow.com/a/20683422/3409405) answer System.out.println() takes around 1 ms. so that means if you do print for every 10^6 i++ your time consumed will be doubled.
How to compare the cost of printing to screen to computation?
By measuring it: Implement both approaches (print every line, print every x lines) and see which one is faster, and keep tuning x for a reasonable trade off between frequent status updates and throughput.
It is important to note that the cost of printing is strongly affected by what you are printing to. Is the stream buffered or does it flush every number? Does it write to memory, to an SSD, an ordinary harddisk, or some drive attached to a slow usb 1 port? That can change write performance by a factor of 1000, which is why you should be measuring your particular use case.
One approach to this could be the following:
Perform your task in a thread, which updates a common buffer (string? Instance of an information class?) with stuff you want to output, but don't perform the actual output in this thread. Mind locking that buffer so you can access this information safely from different threads.
Then, let a timer/other thread access this common buffer to print out that information. That way you decouple the calculation from the output. The drawback is that you won't see every output, but while the output is generated, the computation continues.
Short answer is: it really depends. Printing text is costly. Hundred "print i" is much more expensive than building string with a stringbuilder and firing "print" once.

Time space trade-off

I was asked on a quiz the following question and had NO idea what to ask my self when prompted to design a more efficient segment of code. I mean I know if-else are time consuming, I was thinking maybe a for loop? I was curious if someone could A. tell me if there is only 1 answer and B. walk me through why what ever the solution may be runs so much faster.
It says: Suppose the following segment of code is very time consuming, write a segment that shaves at least 2 minutes of the run time.
if (f(n)%==0)
key = 3*f(n)+4*f(n)+7;
else
key = 6*f(n)*f(n)-33;
"I mean I know if-else are time consuming, I was thinking maybe a for loop" this is not correct. Consider what's happening here that's actually time consuming. Hint: f(n) could be doing many things. But if the code takes a long time to process, your only best bet is that f(n) is the culprit. The only other thing happening here is an if-statement which is fast, and some arithmetic (which computers are pretty darn fast at).
Luckily, you are calculating f(n) for a fixed input n multiple times! Save yourself the trouble by saving the output of this method in a variable then just using the variable. I don't know where you or your teacher got "2 minutes" from, that's arbitrary nonsense in my opinion.
The thing to note is that f(n) gets called 3 times in all cases. If we are assuming that is the bottleneck, then we want to minimize the number of times we call that function.
Note, too, that the result of f(n) is a constant (assuming no external factors). Therefore, you only need to calculate it once.
According to the quiz, the optimized code segment will shave at least two minutes of time as a result. You can deduce that the given code segment takes at least two minutes to calculate.
Regardless to the results of the conditional, if statement, you are calling f(n) 3 times in the given code segment.
By calculating f(n) once at the beginning and assigning the value to a variable to be used in subsequent calculations...
Something like this:
result = f(n)
if (result%==0)
key = 3*result+4*result+7;
else
key = 6*result*result-33;
... you will reduce the time of execution by (2 x execution time of f(n) call) - (execution time of declaring a variable and assigning a value to it + ( 2 x execution time of reading value from that variabl). The execution time of declaring and assigning a value, reading the value from that variable, and the other statements in the given code (like the if statement and logical expression operations) is insignificant (probably less than 1 millisecond).
In accordance to the expected result, you can deduce that each call to f(n) is taking at least 1 min to execute; to re-iterate, the difference in time between the given code segement execution yield, and the now optimized code segment execution yeild, as a result, is 2 minutes.
If your professor says that you need to shave two minutes from the code, then you can say that the code takes at least two minutes to calculate. You are calculating f(n) 3 times in the code, then it is a safe bet to say that each f(n) calculation takes around 40 seconds, assuming no cache. Then, by calculating f(n) once at the beginning and saving the result to use it in the other four calls will save you 40*2 seconds.
Something like this:
result = f(n)
if (result%==0)
key = 3*result+4*result+7;
else
key = 6*result*result-33;

Oracle JDK8: unrolled loop converted to NOOP by JVM?

I've got a little program that is a fairly pointless exercise in simple number crunching that has thrown me for a loop.
The program spawns a bunch of worker threads that do simple mathematical operations. Recently I changed the inner loop of one variant of worker from:
do
{
int3 = int1 + int2;
int3 = int1 * int2;
int1++;
int2++;
i++;
}
while (i < 128);
to something akin to:
int3 = tempint4[0] + tempint5[0];
int3 = tempint4[0] * tempint5[0];
int3 = tempint4[1] + tempint5[1];
int3 = tempint4[1] * tempint5[1];
int3 = tempint4[2] + tempint5[2];
int3 = tempint4[2] * tempint5[2];
int3 = tempint4[3] + tempint5[3];
int3 = tempint4[3] * tempint5[3];
...
int3 = tempint4[127] + tempint5[127];
int3 = tempint4[127] * tempint5[127];
The arrays are populated by random integers no higher than 1025 in value, and the array values do not change.
The end result was that the program ran much faster, though closer examination seems to indicate that the CPU isn't actually doing anything when running the newer version of the code. It seems that the JVM has figured out that it can safely ignore the code that replaced the inner loop after one iteration of the outer loop since it is only redoing the same calculations on the same set of data over and over again.
To illustrate my point, the old code took maybe ~27000 ms to run and noticeably increased the operating temperature of the CPU (it also showed 100% utilization for all cores). The new code takes maybe 5 ms to run (sometimes less) and causes nary a spike in CPU utilization or temperature. Increasing the number of outer loop iterations does nothing to change the behavior of the new code, even when the number of iterations increases by a hundred times or more.
I have another version of the worker that is identical to the one above except that it has a division operation along with the addition and multiplication operations. In its new unrolled form, the division-enabled version is also much faster than it's previous form, but it actually takes a little while (~300 ms on the first run and ~200 ms on subsequent runs, despite warmup, which is a little odd) and produces a profound spike in CPU temperature for its brief run. Increasing the number of outer loop iterations seems to cause the temperature phenomenon to mostly cease after a certain amount of time has passed while running the program, though utilization still shows 100% for all cores. My guess is the JVM is taking much longer to figure out which operations it can safely ignore when handling division operations, and that it is not ignoring all of them.
Short of adding division operations to all my code (which isn't really a fix anyway beyond a certain number of outer loop iterations), is there any way I can get the JVM to stop reducing my code to apparent NOOPs? I've tried several solutions to the problem, such as generating new random values per iteration of the outer loop, going back to simple integer variables with incrementation, and some other nonsense, but none of those solutions have produced desirable results. Either it continues to ignore the series of instructions, or the performance hit from modifications is bad enough that my division-heavy variant actually performs better than the code without division operations.
edit: to provide some context:
i: this variable is an integer that is used for a loop counter in a do/while loop. It is defined in the class file containing the worker code. It's initial value is 0. It is no longer used in the newer version of the worker.
int1/int2: These are integers defined in the class file containing the worker code. Their initial values are both 0. They were used in the old version of the code to provide changing values for each iteration of the internal loop. All I had to do was increment them upward by one per loop iteration, and the JVM would be forced to carry out every operation faithfully. Unfortunately, this loop apparently prevented the use of SIMD. Each time the outer loop iterated, int1 and int2 had their values reset to prevent overflow of int1, int2, or int3 (I have discovered that integer overflow can slow down the code unnecessarily, as can allowing a float to reach Infinity).
tempint4/tempint5: These are references to a pair of integer arrays defined in the main class file for the program (Mathtester. Yes, unimaginative, I know). When the program first starts, there is a short do/while loop that fills each array with random integers randing from 1-1025. The arrays are 128 integers in size. Each array is static, though the reference variables are not. In truth there is no particular reason for me to use the reference variables. They are leftovers from when I was trying to do an array reference swap so that, after each iteration of the outer loop, tempint4 and tempint5 would be referred to the opposite array. It was my hope that the JVM would stop ignoring my code block. For the division-enabled version of the code, this seems to have worked (sort of), since it fundamentally changes the values to be calculated. Swapping tempint4 for tempint5 and vice versa does not change the results of the addition and multiplication operations, so the JVM can still ignore those.
edit: Making tempint4 and tempint5 (since they are only reference variables, I am actually referring to the main arrays, Mathtester.int4 and Mathtester.int5) volatile worked without notably reducing the amount of CPU activity or level or CPU temperature. It did slow down the code a bit, but that is a probable indicator that the JVM was NOOPing more than I knew.
Is there any way I can get the JVM to stop reducing my code to apparent NOOPs?
Yes, by making int3 volatile.
One of the first things when dealing with Java performance that you have to learn by heart is this:
"A single line of Java code means nothing at all in isolation".
Modern JVMs are very complex beasts, and do all kinds of optimization. If you try to measure some small piece of code, the chances are that you will not be measuring what you think you are - it is really complicated to do it correctly without very, very detailed knowledge of what the JVM is doing.
In this case, yes, it's entirely likely that the JVM is optimizing away the loop. There's no simple way to prevent it from doing this, and almost all techniques are fragile and JVM-version specific (because new & cleverer optimizations are developed & added to the JVM all the time).
So, let me turn the question around: "What are you really trying to achieve here? Why do you want to prevent the JVM from optimizing?"

BigO running time on some methods

Ok, these are all pretty simple methods, and there are a few of them, so I didnt want to just create multiple questions when they are all the same thing. BigO is my weakness. I just cant figure out how they come up with these answers. Is there anyway you can give me some insight into your thinking for analyzing running times of some of these methods? How do you break it down? How should I think when I see something like these? (specifically the second one, I dont get how thats O(1))
function f1:
loop 3 times
loop n times
Therefore O(3*n) which is effectively O(n).
function f2:
loop 50 times
O(50) is effectively O(1).
We know it will loop 50 times because it will go until n = n - (n / 50) is 0. For this to be true, it must iterate 50 times (n - (n / 50)*50 = 0).
function f3:
loop n times
loop n times
Therefore O(n^2).
function f4:
recurse n times
You know this because worst case is that n = high - low + 1. Disregard the +1.
That means that n = high - low.
To terminate,
arr[hi] * arr[low] > 10
Assume that this doesn't occur until low is incremented to the highest it can go (high).
This means n = high - 0 and we must recurse up to n times.
function 5:
loops ceil(log_2(n)) times
We know this because of the m/=2.
For example, let n=10. log_2(10) = 3.3, the ceiling of which is 4.
10 / 2 =
5 / 2 =
2.5 / 2 =
1.25 / 2 =
0.75
In total, there are 4 iterations.
You get an n^2 analysis when performing a loop within a loop, such as the third method.
However, the first method doesn't a n^2 timing analysis because the first loop is defined as running three times. This makes the timing for the first one 3n, but we don't care about numbers for Big-O.
The second one, introduces an interesting paradigm, where despite the fact that you have a single loop, the timing analysis is still O(1). This is because if you were to chart the timing it takes to perform this method, it wouldn't behave as O(n) for smaller numbers. For larger numbers it becomes obvious.
For the fourth method, you have an O(n) timing because you're recursive function call is passing lo + 1. This is similar to if you were using a for loop and incrementing with lo++/++lo.
The last one has a O(log n) timing because your dividing your variable by two. Just remember than anything that reminds you of a binary search will have a log n timing.
There is also another trick to timing analysis. Say you had a loop within a loop, and within each of the two loops you were reading lines from a file or popping of elements from a stack. This actually would only be a O(n) method, because a file only has a certain number of lines you can read, and a stack only has a certain number of elements you can pop off.
The general idea of big-O notation is this: it gives a rough answer to the question "If you're given a set of N items, and you have to perform some operation repeatedly on these items, how many times will you need to perform this operation?" I say a rough answer, because it (most of the time) doesn't give a precise answer of "5*N+35", but just "N". It's like a ballpark. You don't really care about the precise answer, you just want to know how bad it will get when N gets large. So answers like O(N), O(N*N), O(logN) and O(N!) are typical, because they each represent sort of a "class" of answers, which you can compare to each other. An algorithm with O(N) will perform way better than an algorithm with O(N*N) when N gets large enough, it doesn't matter how lengthy the operation is itself.
So I break it down thus: First identify what the N will be. In the examples above it's pretty obvious - it's the size of the input array, because that determines how many times we will loop. Sometimes it's not so obvious, and sometimes you have multiple input data, so instead of just N you also get M and other letters (and then the answer is something like O(N*M*M)).
Then, when I have my N figured out, I try to identify the loop which depends on N. Actually, these two things often get identified together, as they are pretty much tied together.
And, lastly of course, I have to figure out how many iterations the program will make depending on N. And to make it easier, I don't really try to count them, just try to recognize the typical answers - O(1), O(N), O(N*N), O(logN), O(N!) or perhaps some other power of N. The O(N!) is actually pretty rare, because it's so inefficient, that implementing it would be pointless.
If you get an answer of something like N*N+N+1, then just discard the smaller ones, because, again, when N gets large, the others don't matter anymore. And ignore if the operation is repeated some fixed number of times. O(5*N) is the same as O(N), because it's the ballpark we're looking for.
Added: As asked in the comments, here are the analysis of the first two methods:
The first one is easy. There are only two loops, the inner one is O(N), and the outer one just repeats that 3 times. So it's still O(N). (Remember - O(3N) = O(N)).
The second one is tricky. I'm not really sure about it. After looking at it for a while I understood why it loops at most only 50 times. Since this is not dependant on N at all, it counts as O(1). However, if you were to pass it, say, an array of only 10 items, all positive, it would go into an infinite loop. That's O(∞), I guess. So which one is it? I don't know...
I don't think there's a formal way of determining the big-O number for an algorithm. It's like the halting problem. In fact, come to think of it, if you could universally determine the big-O for a piece of code, you could also determine if it ever halts or not, thus contradicting the halting problem. But that's just my musings.
Typically I just go by... dunno, sort of a "gut feeling". Once you "get" what the Big-O represents, it becomes pretty intuitive. But for complicated algorithms it's not always possible to determine. Take Quicksort for example. On average it's O(N*logN), but depending on the data it can degrade to O(N*N). The questions you'll get on the test though should have clear answers.
The second one is 50 because big O is a function of the length of the input. That is if the input size changes from 1 million to 1 billion, the runtime should increase by 1000 if the function is O(N) and 1 million if it's O(n^2). However the second function runs in time 50 regardless of the input length, so it's O(1). Technically it would be O(50) but constants don't matter for big O.

Categories