Java Algorithm on Eclipse - java

Public class AlgorithmC{
Public class AlgorithmC{
public static void main(String[] args) {
System.out.println("Table of n and the execution time with the Algorithm c:");
for (long n = 1; n <= 10000000;n=n*10) {
long startTime = System.currentTimeMillis();
long sum = n*(n+1)/2;
long endTime = System.currentTimeMillis();
long elapsedTime = endTime - startTime;
System.out.println(n + " " + elapsedTime);
}
}
}
This outputs
Table of n and the execution time with the Algorithm c:
1 0
10 0
100 0
1000 0
10000 0
100000 0
1000000 0
10000000 0
Why is the execution time zero for all the values of n?
I don't know what I'm doing wrong exactly.

Well, the time it takes to execute n*(n+1)/2 is very low. You may try using System.nanoTime(); instead. If your only purpose is to measure the execution time of some math function, then maybe you can experiment with Math.pow();But even then the time will be quite low.

You are measuring time taken to calculate
long sum = n*(n+1)/2;
On your machine it is taking less than a milli-second

Related

Setting a variable back to zero

I'm teaching myself Java using one of the ebooks on Amazon. I was doing one of the lessons which does a "benchmark" of the computer. It does this by looping for a minute and calculating the results.
It basically doesn't show you anything for a minute until it's done. So my was making a small modification to show a dot as a progress bar of sorts every few seconds. Normally this is a trivial thing, but something's not right, and I don't know what.
What happens is miniIndex will reach the threshold I specified, and print the value of miniIndex and a period. Its then supposed to set miniIndex to zero so that counter can restart. But it doesn't reset, and never increments again. It's very odd behavior.
Here is the code in its entirety:
class Benchmark {
public static void main(String[] arguments) {
long startTime = System.currentTimeMillis();
long endTime = startTime + 60000;
long index = 0;
// My inner index
int miniIndex = 0;
//
while (true) {
double x = Math.sqrt(index);
long now = System.currentTimeMillis();
if (now > endTime){
break;
}
index++;
// my modification
miniIndex++;
if (miniIndex >= 5000) {
System.out.print(miniIndex + ".");
miniIndex = 0;
}
// end of my modification
}
System.out.println(index + " loops in one minute.");
}
}
I think you misunderstand what your miniIndex++ operation is doing, as it is not counting milliseconds but instead is counting the number of loop iterations which are not equal to each other. I have modified your code to execute the if statement inside every 5 seconds, according to what you wanted to happen:
public static void main(String[] arguments) {
long startTime = System.currentTimeMillis();
long miniTime = startTime; //Declare miniTime equal to startTime
long endTime = startTime + 60000;
long index = 0;
while (true) {
double x = Math.sqrt(index);
long now = System.currentTimeMillis();
if (now > endTime){
break;
}
index++;
// my modification
//Current time minus last time the if executed and check if 5 seconds passed
if ((now - miniTime) >= 5000) {
miniTime = System.currentTimeMillis();
System.out.println("5 seconds have passed.");
//if you want to print the actual time elapsed every 5 seconds use this print
//System.out.println((now - startTime)/1000 + " seconds have passed.");
}
// end of my modification
}
System.out.println(index + " loops in one minute.");
}
Notice how I now compare current time of now and subtract the miniTime to check to see if it is higher than or equal 5000 milliseconds. To use time you must relate it to time somehow, in this case System.currentTimeMillis() and the results. Numbers themselves such as counting the loop will never be time consistent.
A loop may execute millions of times, but only take 3 seconds.
Example Output:
5 seconds have passed.
5 seconds have passed.
5 seconds have passed.
5 seconds have passed.
5 seconds have passed.
5 seconds have passed.
5 seconds have passed.
5 seconds have passed.
5 seconds have passed.
5 seconds have passed.
5 seconds have passed.
16319642816 loops in one minute.
Note: 5 seconds have passed. prints 11 times because at the 60 second mark the loop is broken so the final pass is not printed. (And 11 * 5 is 55 for the first 55 seconds).
Your code is working fine; it's your expectations that are flawed.
Your code prints a dot every 5,000 iterations. Which is going to basically spew values. Remember, your CPU is running at something > 2 billion operations a second. You can probably do a few million of those loops per second. Call it a million loops per second, divided by 5000 is 200 dots per second, more or less, anyway.
If you still want to use it in that type of output you can make it easier using StringBuilder. It's coded like that:
StringBuilder stringBuilder = new StringBuilder();
and incide the loop like that:
if (miniIndex >= 5000) {
stringBuilder.append(miniIndex).append(".");
miniIndex = 0;
}
if (stringBuilder.length() >= 200) {
System.out.println(stringBuilder);
stringBuilder.setLength(0);
}
You're probably overwhelming your output or something, such that it doesn't print anything at all. Your loop waits until 60000 milliseconds (1 minute). When I ran it, here was the end part of my output. Since your loop iterates very very fast (as fast as the computer can print, because that is the bottleneck here), NOT one iteration per second/millisecond, your counter miniIndex goes up many many times per second. However, your code does work - it just doesn't do what you think it does.
If you try something like the following, you may get a slightly more precise output:
class Benchmark {
public static void main(String[] arguments) {
long startTime = System.currentTimeMillis();
long endTime = startTime + 60000;
long index = 0;
// My inner index
int miniIndex = 0;
//
while (true) {
double x = Math.sqrt(index);
long now = System.currentTimeMillis();
if (now > endTime){
break;
}
index++;
// my modification
miniIndex++;
if (miniIndex >= 5000) {
System.out.print(miniIndex + ".");
miniIndex = 0;
}
// end of my modification
try {
Thread.sleep(1);
}
catch(Exception e)
{
e.printStackTrace();
}
}
System.out.println(index + " loops in one minute.");
}
}
Output:
..........50976 loops in one minute.
Notice that you may not get 60,000 loops a minute, as Thread.sleep(1) can sleep for slightly over 1 millisecond.
To see why it didn't work, you need to print the variable "now" while looping. You will notice that "now" stays the same for a certain amount while in the loop and eventually it will increment by one. So when you have one thousand of those increments it equates to a period of 1 sec. What the variable "miniIndex" is doing is counting up to 5000 loops and then resets, nowadays computers can perform thousands and thousands of loops in a second. Which is why it seemed like it wasn't resetting.
You can change the wait variable in the code to show different dot progress like you wanted.
class Main {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
long endTime = startTime + 60000;
long index = 0;
long wait = 5000; //secs 5000 == 5sec
long secondsPassed = startTime + wait;
System.out.print("counting");
while (true) {
double x = Math.sqrt(index);
long now = System.currentTimeMillis();
if (now > endTime){
break;
}
index++;
if (now >= secondsPassed) {
System.out.print(".");
secondsPassed = secondsPassed + wait;
}
}
System.out.println("");
System.out.println(index + " loops in one minute.");
}
}

Any ideas to make my code efficient for looping 10 000 000 000 times

I've made a simple code to count the occurrences of the digit '14' from a given number. I've successfully print out the counter if the given number is 10 000 000 and it took less than 1 second. When i increase the number to
10 000 000 000 it took 459 seconds. Any ideas on how to make it runs faster?
long startTime = System.nanoTime();
long counter = 0L;
for (long i = 14; i <= 10000000000L; i++)
{
String s = Long.toString(i);//i.ToString();
if (s.contains("14"))
{
counter += 1;
}
}
long endTime = System.nanoTime();
long totalTime = endTime - startTime;
long convert = TimeUnit.SECONDS.convert(totalTime, TimeUnit.NANOSECONDS);
System.out.println(convert + " seconds");
System.out.println(counter);
time taken : 459 seconds
number of 14 appears : 872348501
The most obvious optimization: don't construct strings.
Just check the last two digits of the number, and then divide by 10 until you find a 14:
boolean matches = false;
for (long num = i; num >= 14 && !matches; num /= 10) {
matches = (num % 100) == 14;
}
if (matches) {
counter += 1;
}
But, you would likely just be able to calculate the number of cases, using the inclusion/exclusion principle.
You can improve performance by combining the solution proposed by Andy Turner and java8 parallel streams:
private boolean twoDigitExist(long x, long d)
{
while (x >= d)
{
if (x % 100 == d)
return true;
x /= 10;
}
return false;
}
And the loop could be parallelized as:
long counter = LongStream.range(14, 10000000000L).parallel().filter(l->twoDigitExist(l, 14)).count();

Java Strange Float Behavior

Here is what my code looks like stripped down as much as possible:
float delay = (float)5000;
long startTime = System.nanoTime();
int elapsed = 0;
for (int i = 0; i < 20; i++) {
elapsed = (int) ((System.nanoTime() - startTime) / 1000000);
// System.out.println("Elapsed: " + elapsed);
float range = delay * 0.4f;
float randomNum = (float)(Math.random() * range - (delay * 0.2f));
if (elapsed > (delay + randomNum)) {
System.out.println("Random Num: " + randomNum);
startTime = System.nanoTime();
} else {
i--;
continue;
}
}
As you can see I'm looping 20 times and printing out a random number after 5 seconds (5000 milliseconds). This is what the output looks like:
As you can see, all of the outputs are VERY close to -1000. I'm trying to generate a random float from -1000 to 1000, but they all seem to be around -1000. So, I checked to make sure the actual random number generator is working, using this code:
float delay = (float)5000;
long startTime = System.nanoTime();
int elapsed = 0;
for (int i = 0; i < 20; i++) {
elapsed = (int) ((System.nanoTime() - startTime) / 1000000);
// System.out.println("Elapsed: " + elapsed);
float range = delay * 0.4f;
float randomNum = (float)(Math.random() * range - (delay * 0.2f));
System.out.println("Random Num: " + randomNum);
startTime = System.nanoTime();
}
Basically I took elapsed out of the equation and just printed the random numbers without the if statement. This is the output I got:
In this example, I got very random output, exactly like you would expect. However, once you add elapsed back into the equation like in the first set of code, the output turns back to -999 with some random decimal places.
Even more interesting is that if you put a print statement right above the if statement and right after randomNum is assigned a value, you get these outputs:
Once again, the numbers are random. It seems like for some reason in the first example code with the elapsed part of the code put in, the randomNum variable changes right after the if statement is called. Why does this happen?
The problem is that, although you're generating random numbers in your desired range, you're systematically discarding all the ones over -999.
Consider code like this:
while (true) {
// generate a random number in the range [-1000, 1000):
final double randomNum = 2000 * Math.random() - 1000;
// print it if it's in the range [-1000, -999):
if (randomNum < -999) {
System.out.println("Random Num: " + randomNum);
}
}
The above code will print out a bunch of random numbers in the range [−1000, −999); do you see why?
Your code is more complicated, of course, but it's effectively doing the same thing.
To see why, let's take a look at your code:
float delay = (float)5000;
long startTime = System.nanoTime();
int elapsed = 0;
for (int i = 0; i < 20; i++) {
elapsed = (int) ((System.nanoTime() - startTime) / 1000000);
// System.out.println("Elapsed: " + elapsed);
float range = delay * 0.4f;
float randomNum = (float)(Math.random() * range - (delay * 0.2f));
if (elapsed > (delay + randomNum)) {
System.out.println("Random Num: " + randomNum);
startTime = System.nanoTime();
} else {
i--;
continue;
}
}
Let's simplify/trim it a bit so it's easier to read — remove the commented-out line, clean up the whitespace, remove the casts to int and float (it's OK to use long and double), inline the various values, change the for-loop-that-contains-code-that-mutates-its-index-variable into a more-explicit while-loop, change the System.nanoTime()-but-then-dividing-the-result-by-a-million to System.currentTimeMillis(), rename some variables for clarity, etc.:
long prevTimeMillis = System.currentTimeMillis();
int i = 0;
while (i < 20) {
final long elapsedMillis = System.currentTimeMillis() - prevTimeMillis;
final double randomNum = 2000 * Math.random() - 1000;
if (elapsedMillis > 5000 + randomNum) {
System.out.println("Random Num: " + randomNum);
prevTimeMillis = System.currentTimeMillis();
i++;
}
}
Even with that simpler code in hand, we still need two key insights:
elapsedMillis > 5000 + randomNum is just another way of writing randomNum < elapsedMillis - 5000.
Initially, elapsedMillis == 0; and after each time we successfully print out a number, elapsedMillis == 0 again. In between, there are some loop iterations where elapsedMillis increases by 1, but in most loop iterations it doesn't change at all.
This is because this loop is very very quick, with a very large number of iterations per millisecond. (That's not necessarily obvious from first principles, but it's the only way to explain the output you're getting.)
So this code will loop quickly, generating one random number after another and discarding every single one, until elapsedMillis == 4001, at which point every random number will be discarded except random numbers less than -999. Since you're performing a huge number of loop iterations per millisecond, and generating a huge number of random numbers per millisecond, it's overwhelmingly likely that you manage to generate a random number less than -999 while elapsedMillis == 4001. And then elapsedMillis gets reset back to zero. So random numbers greater than -999 never have a chance to compete: elapsedMillis is never greater than 4001, so such numbers are always discarded.
To fix this, you need to pre-select a single random number "How long should I delay?" before you start looping, and then loop until your elapsedMillis exceeds that one pre-selected random number.
In addition, assuming that your real goal here is to delay for some amount of time in the range [4sec,6sec), you should probably use Thread.sleep() rather than this polling/busy-waiting mechanism. That way, instead of just burning CPU, you can gracefully yield this processor for use by other threads and processes until you're ready to proceed. To do that, you can write:
for (int i = 0; i < 20; i++) {
final long millisToDelay = (long) (2000 * Math.random() - 1000);
System.out.println("Millis To Delay: " + millisToDelay);
Thread.sleep(millisToDelay);
}
I believe you actually have the answer to your problem located on the second line of code you have provided to us. Notice how you cast to float: (float)?
Do the same thing on the line that contains:
float number = delay + randomNum;
so that it looks like:
float number = (float) delay + randomNum;
delay is not a float data type. I think that should do it.

Java Thread getting elapsed time :: how to get small change

Here is my run for method for thread
public void run() {
float timeElapsed =0;
while(running){
time += timeElapsed; // recording time.
if(timeElapsed != 0 )Log.d(id, "pressed time " + time + " "+ timeElapsed);
/**fromhere :: just how I get fps ratio.
oneSec += timeElapsed;
fpsCompound++;
if(oneSec > 1){
fpsCompound = 0;
oneSec = 0;
}
**/endhere
timeBefore = System.nanoTime();
loopCall(timeElapsed);
timeElapsed =(System.nanoTime()-timeBefore)/1000000000;
//sometimes my timeElapsed is 0, my guess is because the loopCall does nothing in some cases
while(timeElapsed < .005){
timeElapsed =(System.nanoTime()-timeBefore)/1000000000;
}
}
}
I want to get rid of that while loop that delays the loop if timeElapsed is less than .005.
However if I skip that delay portion, I sometimes get my timeElapsed as 0 even though there has to be a tiny portion of seconds passed.
Accumulated result of these zero elapsed time results in unexpected time error. So I delay my thread if each loop is too fast to record the time.
This unnecessary delay seems pretty stupid. There must be a correct way to calculate the time.
EDIT:
It seems that dividing timeElapsed by 1000000000 returns value that's too small for my float to contain. Is there a way to contain such a small number?
I think you should keep nanoseconds as long and not convert it into float seconds.
then you'll have code like this:
timeElapsed is defined as long:
long timeElapsed = 0;
End of your loop will look like this:
timeBefore = System.nanoTime();
loopCall(timeElapsed);
timeElapsed =(System.nanoTime()-timeBefore);
while(timeElapsed < 5000000){
timeElapsed = (System.nanoTime()-timeBefore);
}
I hope that's what you're looking for.
Also I'd recommend to do waiting with Thread.sleep(long, int); You'll lose some precision (it sleeps for milliseconds) but will save some CPU time
/*while(timeElapsed < 5000000){
timeElapsed = (System.nanoTime()-timeBefore);
}*/
long leftToSleep = 5000000 - timeElapsed;
if(leftToSleep > 0) {
//dont forget to surround it with try catch
Thread.sleep(leftToSleep / 1000000, (int) leftToSleep % 1000000);
}

Java - Big result difference when benchmarking an algorithm in ms and ns

I was performing some test performance on an algorithm and noticed something weird. Maybe I am missing something here.
I first measure the time in milliseconde:
long startTime = System.currentTimeMillis();
x.sort(sortStringInput);
long endTime = System.currentTimeMillis();
and then in nanoseconde:
long startTime = System.nanoTime();
x.sort(sortStringInput);
long endTime = System.nanoTime();
The results are 437ms qnd 26366ns.
I am calling the same method so how can it be possible to get a result in ns which is way smaller than the one in ms. I know that 1 ms is 1 000 000 ns so 26366 is even smaller than 1 ms...
Thanks,
Are you sorting the same list twice? The second call will be extremely fast if the list is already sorted.
Depending on what platform you're on, System.nanoTime() itself can be very slow. You're better off running your benchmark multiple times and measuring the overall duration in miliseconds.
I suggest you run the test for at least 2 seconds before counting any result and run the test for at least 2 seconds and take the average. The following code prints.
Average sort time 116 ms.
Average sort time 117100526 ns.
Average sort time 116 ms.
Average sort time 116530255 ns.
Average sort time 117 ms.
Average sort time 116905977 ns.
Code
public static void main(String... args) throws IOException {
String[] strings = new String[100 * 1000];
for (int i = 0; i < strings.length; i++)
strings[i] = "" + Math.random();
int runTimeMS = 2000;
for (int i = 0; i <= 3; i++) {
{
long start = System.currentTimeMillis();
int count = 0;
do {
Arrays.sort(strings.clone());
count++;
} while (System.currentTimeMillis() - start < runTimeMS);
long time = System.currentTimeMillis() - start;
if (i>0) System.out.println("Average sort time " + time / count + " ms.");
}
{
long start = System.nanoTime();
int count = 0;
do {
Arrays.sort(strings.clone());
count++;
} while (System.nanoTime() - start < runTimeMS * 1000L * 1000L);
long time = System.nanoTime() - start;
if (i>0) System.out.println("Average sort time " + time / count + " ns.");
}
}
}

Categories

Resources