how to keep value constant for every run? - java

Using java I want to generate some random values in one program and then use these values in some other program everytime the 2nd program is executed.
Purpose of this is to generate random values once and then hold and keep them constant for every run of the program later. Is it possible in some way? Thanks

When you exit a program, anything you don't store in a file is lost.
I suspect you don't need to worry about IO as much as you think. You should be able to read millions of values in a few milli-seconds. In fact you should be able to generate millions of random numbers in a fraction of a second.
Random random = new Random(1);
long start = System.nanoTime();
int values = 1000000;
for (int i = 0; i < values; i++)
random.nextInt();
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to generate %,d values%n",
time / 1e9, values);
prints
Took 0.015 seconds to generate 1,000,000 values
Generating and writing
int values = 1000000;
ByteBuffer buffer = ByteBuffer.allocateDirect(4 * values).order(ByteOrder.nativeOrder());
Random random = new Random(1);
long start = System.nanoTime();
for (int i = 0; i < values; i++)
buffer.putInt(random.nextInt());
buffer.flip();
FileOutputStream fos = new FileOutputStream("/tmp/random.ints");
fos.getChannel().write(buffer);
fos.close();
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to generate&write %,d values%n", time / 1e9, values);
prints
Took 0.021 seconds to generate&write 1,000,000 values
Reading the same file.
long start2 = System.nanoTime();
FileInputStream fis = new FileInputStream("/tmp/random.ints");
MappedByteBuffer buffer2 = fis.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, values * 4).order(ByteOrder.nativeOrder());
for (int i = 0; i < values; i++)
buffer2.getInt();
fis.close();
long time2 = System.nanoTime() - start2;
System.out.printf("Took %.3f seconds to read %,d values%n", time2 / 1e9, values);
prints
Took 0.011 seconds to read 1,000,000 values
Reading the same file repeatedly
long sum = 0;
int repeats = 1000;
for (int j = 0; j < repeats; j++) {
buffer2.position(0);
for (int i = 0; i < values; i++)
sum += buffer2.getInt();
}
fis.close();
long time2 = System.nanoTime() - start2;
System.out.printf("Took %.3f seconds to read %,d values%n", time2 / 1e9, repeats * values);
prints
Took 1.833 seconds to read 1,000,000,000 values

a couple of ways you may consider to go
1 using the same seed to generate random number
2 generate the random and save them in a file. your program two reads the file to get values.

The fastest way is to run the program once, note down the random numbers generated, and then hardcode the random numbers in an array in your program! Then, the next time onwards, your program can read these same values from the array.
So suppose you program generates random numbers as follows -
0.34, 0.15, 0.28, 0.45, ...
You can then define an array and store these values in it.
randomValues[0] = 0.34;
randomValues[1] = 0.15;
randomValues[2] = 0.28;
randomValues[3] = 0.45;
.
.
.
Then each time, simply use an index to get the random number you want.
index = 0;
randomNumber = randomValues[index];
index++; // so the next time, you can get the next random number in sequence.

Generate them once, then save them into a file...
afterthat, everytime you want to run your program, you have to load these values again.

Related

Java timer displaying incorrect times

I've been working on a 3-way merge sort algorithm, and the professor wants me to average how much time it takes to merge sort an array of 1000, 10000, 100000, 1000000 and 10000000 randomized integers over 10 trials each. However, I've been facing a problem while trying to calculate the run time; for example, when I calculate the run time for 1 million elements it displays that it took around 300ms while in reality it's taking around 40 seconds. I'm going to leave the code of my main function, I also tried putting startTime at the start and it would display the same running time.
public static void main(String args[]) {
Random r = new Random();
int[] arr = new int[1000000];
for (int i = 0; i < arr.length; i++)
arr[i] = r.nextInt();
long startTime = System.currentTimeMillis();
MergeSort test = new MergeSort();
test.sort(arr, 0, arr.length);
long endTime = System.currentTimeMillis();
long timeElapsed = endTime - startTime;
print(arr);
System.out.println("Execution time in milliseconds: " + timeElapsed);
}

Timing bubble sorting in different scenarios

I am trying determine the running times of bubble sort algorithm in three different kinds of input:
1) randomly selected numbers
2) already sorted numbers
3) sorted in reverse order numbers
My expectation about their running time was:
Reverse ordered numbers would take longer than other two.
Already sorted numbers would have the fastest running time.
Randomly selected numbers would lie between these two.
I've tested the algorithm with inputs containing more than 100.000 numbers. The results wasn't like I expected. Already sorted numbers had the fastest running time but randomly selected numbers took almost twice as much time to execute compared to reverse ordered numbers. I was wondering why this is happening?
Here is how I test the inputs
int[] random = fillRandom();
int[] sorted = fillSorted();
int[] reverse = fillReverse();
int[] temp;
long time, totalTime = 0;
for (int i = 0; i < 100; i++) {
temp = random.clone();
time = System.currentTimeMillis();
BubbleSort.sort(temp);
time = System.currentTimeMillis() - time;
totalTime += time;
}
System.out.println("random - average time: " + totalTime/100.0 + " ms");
totalTime = 0;
for (int i = 0; i < 100; i++) {
temp = sorted.clone();
time = System.currentTimeMillis();
BubbleSort.sort(temp);
time = System.currentTimeMillis() - time;
totalTime += time;
}
System.out.println("sorted - average time: " + totalTime/100.0 + " ms");
totalTime = 0;
for (int i = 0; i < 100; i++) {
temp = reverse.clone();
time = System.currentTimeMillis();
BubbleSort.sort(temp);
time = System.currentTimeMillis() - time;
totalTime += time;
}
System.out.println("reverse - average time: " + totalTime/100.0 + " ms");
Benchmarks for java code are not easy, as JVM might apply a lot of optimizations to your code at runtime. It can optimize out a loop if computation result is not used, it can inline some code, JIT can compile some code into native and many other things. As a result, benchmark output is very unstable.
There are tools like jmh that simplify benchmarking a lot.
I recommend you to check this article, it has an example of benchmark for sorting algorithm.

Time to loop using long and double

Following piece of code is take different timing with long and double, not able to understand why there is the difference in the timing?
public static void main(String[] args) {
long j = 1000000000;
double k = 1000000000;
long t1 = System.currentTimeMillis();
for (int index = 0; index < j; index++) {
}
long t2 = System.currentTimeMillis();
for (int index = 0; index < k; index++) {
}
long t3 = System.currentTimeMillis();
long longTime = t2 - t1;
long doubleTime = t3 - t2;
System.out.println("Time to loop long :: " + longTime);
System.out.println("Time to loop double :: " + doubleTime);
}
Output:
Time to loop long :: 2322
Time to loop double :: 1510
long is taking longer time than double, I have 64 bit window operating system and 64 bit Java.
When I modified my code and add casting long and double to int like
public static void main(String[] args) {
long j = 1000000000;
double k = 1000000000;
long t1 = System.currentTimeMillis();
for (int index = 0; index < (int)j; index++) {
}
long t2 = System.currentTimeMillis();
for (int index = 0; index < (int)k; index++) {
}
long t3 = System.currentTimeMillis();
long longTime = t2 - t1;
long doubleTime = t3 - t2;
System.out.println("Time to loop long :: " + longTime);
System.out.println("Time to loop double :: " + doubleTime);
}
The time got reduced but still there is the difference in the timing, but this time double is taking more time than long(opposite of first case)
Output:
Time to loop long :: 760
Time to loop double :: 1030
Firstly, a long is a 64-bit integer and a double is a 64-bit floating point number. The timing difference will likely be due to the difference in optimisation between integer arithmetic and floating point arithmetic in your CPU's ALU.
Secondly, the second time you run your application, in each for loop, the loop evaluates the stop condition every time, so you're casting from a long and double to an integer respectively on every iteration. If you precast the value to an integer value before the loop's condition then you should get more consistent times:
int j_int = (int) j;
for(int index = 0; index < j_int; index++) { /* Body */ }
int k_int = (int) k;
for(int index = 0; index < k_int; index++) { /* Body */ }
In general, casting from long to int is simpler than from double to int.
The reason is that long and int are both whole numbers and represented in memory simply by their binary representation (and possibly one bit for the sign).
Casting from one to another is quite straightforward by just "cropping" or "extending" the memory area (and handling signs correctly).
However, double are floating point numbers and their binary representation a bit more complicated, using sign, mantissa and exponent.
Casting from here to whole numbers thus is more complicated, as it requires conversion from one binary format to the other first.

how to get more signficant digits to print from a long value?

I am trying to print a long value held by elapsed, can someone help me with the format of how to do it?
This prints 0.0
but i know it has more significant digits (maybe like .0005324 or something)
System.out.println("It took " + (double)elapsed + " milliseconds to complete SELECTION_SORT algorithm.");
'
System.currentTimeMillis();
long start = System.currentTimeMillis();
int sortedArr[] = selectionSort(arr1);
long elapsed = System.currentTimeMillis() - start;
System.out.println("\n///////////SELECTIONSort//////////////");
System.out.println("\nSelection sort implemented below prints a sorted list:");
print(sortedArr);
System.out.printf("It took %.7f ms....", elapsed);
//System.out.println("It took " + (double)elapsed + " milliseconds to complete SELECTION_SORT algorithm.");'
'
private static int[] selectionSort(int[] arr) {
int minIndex, tmp;
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
minIndex = i;
for (int j = i + 1; j < n; j++)
if (arr[j] < arr[minIndex])
minIndex = j;
if (minIndex != i) {
tmp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = tmp;
}
}
return arr;
}'
Changing the format won't give you more resolution which is what your real problem is hee if you print 1 ms with 7 digits you just get 1.0000000 every time. This doesn't help you at all.
What you need is a high resolution timer
long start = System.nanoTime();
int sortedArr[] = selectionSort(arr1);
long elapsed = System.nanoTime() - start;
System.out.println("\n///////////SELECTIONSort//////////////");
System.out.println("\nSelection sort implemented below prints a sorted list:");
print(sortedArr);
System.out.printf("It took %.3f ms....", elapsed / 1e6);
However, if you do this once you are fooling yourself because Java compiles code dynamically and gets fast the more you run it. It can get 100x faster or more making the first number you see pretty useless.
Normally I suggest you run loops many times and ignore the first 10,000+ times. This will change the results so much that you will see that the first digit was completely wrong. I suggest you try this
for(int iter = 1; iter<=100000; iter *= 10) {
long start = System.nanoTime();
int[] sortedArr = null
for(int i=0;i<iter;i++)
sortedArr = selectionSort(arr1);
long elapsed = System.nanoTime() - start;
System.out.println("\n///////////SELECTIONSort//////////////");
System.out.println("\nSelection sort implemented below prints a sorted list:");
print(sortedArr);
System.out.printf("It took %.3f ms on average....", elapsed / 1e6 / iter);
}
You will see you results improve 10x maybe even 100x just by running the code for longer.
You can use print formatting. For a double or float, to get 7 places after the decimal place, you would do:
System.out.printf("It took %.7f ms....", elapsed);
EDIT:
You are actually using a long, not a double, so you cannot have significant digits, because long only takes on integer values.
A long is an integer value and does not have decimal places.
To get an approximation of the runtime, run the same sort in a loop, say 1000 times and then divide the measured time by 1000.
For example:
System.out.println("It took " + ((double)elapsed) / NUMBER_OF_ITERATONS);
Try this:
String.format("%.7f",longvalue);
by using above line you can format your long or any floating point numbers. Here 7 is referred how many digits you want after '.' .

Approximating Pi

Following is the code I wrote for approximating the value of 103993/33102. The user inputs the precision.
Here k is the precision inputted by the user and asd is the value in the form of a string
int tot = 4687;
int divisor = 33102;
StringBuffer fraction=new StringBuffer();
int tmp = tot;
for(long i=1;i<=k;i++)
{
tmp = tmp*10;
int res = tmp/divisor;
fraction.append(res);
tmp = tmp - res*divisor;
}
asd="3."+fraction.toString();
However when the user inputs a precision of 10^6 it takes enormous amount of time. The time limit is given 1 sec. Help!
Your algorithm looks fine. StringBuffer is thread safe and therefore quite slow because it acquires a lock for each call to append. Use StringBuilder, and construct it with the capacity you know you'll need, i.e. k. This prevents multiple copies of the data as the buffer inside StringBuilder is expanded to accomodate the growing string.
This is clear if you read the StringBuffer docs:
As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.
Since you know the exact size of the output in advance, you can also use an array of bytes to hold the digits. Still final conversion to a string of length 10^6 and output are expensive. When I run the code below, it takes only 0.016 seconds to create the byte array, 0.06 to convert to a string, and over 1 second to print. To make progress, you will have to do some research on how to do fast i/o in Java. If you swith to C or another language closer to the hardware, the normal i/o routines may be fast enough.
public void run() {
int k = 1000000;
long start = System.currentTimeMillis();
int tot = 4687;
int divisor = 33102;
byte [] buf = new byte[k];
int tmp = tot;
for (int i = 0; i < k; i++) {
tmp = tmp * 10;
int res = tmp / divisor;
buf[i] = (byte)(res + '0');
tmp = tmp - res * divisor;
}
System.out.println((System.currentTimeMillis() - start) * .001);
String s = new String(buf);
System.out.println((System.currentTimeMillis() - start) * .001);
System.out.print("3."); System.out.println(s);
System.out.println((System.currentTimeMillis() - start) * .001);
}
Preallocate the value in a very big string, and just make a substring of K elements, so you dont have to calculate each time, and the result will be in an instant.

Categories