When I run this code I got time like 0.25s, I want to improve this code to get time better than 0.16s - this is the limit. I know it depends on the hardware. Time is compute without filling array. I must work on array. How can I improve this ?
Update: I want to get the index of first element of slice which avg is minimal.
public static void main(String[] args) {
int[] A = new int[10000] ;
double randomNum ;
for(int i= 0 ; i<A.length ; i++)
{
randomNum = 0 + (double)(Math.random()*1);
if(randomNum>0.5)
A[i]=-1;
else
A[i]=1;
}
System.out.println("Compute");
long start_time = System.nanoTime();
int result = 0;
double minavg = 100000 ;
double avg;
double suma = 0;
int count = 0;
for(int i=0 ; i<A.length-1 ; i++)
{
for(int k=i ; k<A.length ; k++)
{
suma+=A[k];
count++;
if(count>1)
{
if(A[k]<A[k-1]) {
avg=suma/count;
if(minavg>avg)
{
minavg=avg;
result = i;
}
}
}
}
suma=0;
count=0;
}
long end_time = System.nanoTime();
double difference = (end_time - start_time)/1e9;
System.out.println(difference);
}
One thing that you can do is changing the datatype of suma to int, but remember to cast it back to double in avg computation . This will avoid a lot of datatype conversions in incrementations, in my case it took the time down by about 1/7th.
Secondly, I'm not sure about this condition:
if (A[k] < A[k - 1])
Imho it should be like this (and it takes the time down by 1/2):
if (A[k] < minavg)
but I'm not sure if the final result is correct then, but it fixes issue mentioned by #Crferreira
I'm still not sure about Your original algorithm and the task. here is my rewrite of it. on average it takes the time further down to 1/3rd of last measurement
private static void calculateB(int[] A) {
if (A == null || A.length < 2) {
return;
}
long start_time = System.nanoTime();
int result = 0;
double minavg = 100000;
double avg;
int suma = A[A.length - 1];
int count = 1;
for (int i = A.length - 2; i >= 0; i--) {
count += 1;
int previous = A[i];
suma += previous;
if (previous < minavg) {
avg = (double) suma / count;
if (minavg > avg) {
minavg = avg;
result = i;
}
}
}
long end_time = System.nanoTime();
double difference = (end_time - start_time) / 1e6;
System.out.println(result + " " + minavg + " " + difference);
}
BUT the results from this one are different from original, you have to check if it validates against assignment. I did make the calculations manually and it seems to be OK. This one, iterates the table from the end. Thanks to this, we have a base for sum that we reuse in further iterations.
As for the general rule - I'm not sure what you are calculating - from the code, it looks like it is index of item with lowest avg of following items including the one on index - is this correct ?
I tried to look into that in javascript. I started with an average time of 0.101 and get down to 0.076 with those small modifications:
function main() {
var A = new Array() ;
var randomNum ;
for(var i= 0 ; i<1000 ; i++)
{
randomNum = 0 + Math.random();
if(randomNum>0.5)
A[i]=-1;
else
A[i]=1;
}
console.log("Compute");
var start_time = new Date().getTime();;
var result = 0;
var minavg = 100000 ;
for(var i=0 ; i<A.length-1 ; i++)
{
var suma= A[i];
var count=1;
for(var k=i+1 ; k<A.length ; k++)
{
suma+=A[k];
count++;
if(A[k]<A[k-1]) {
var avg=suma/count;
if(minavg>avg)
{
minavg=avg;
result = i;
}
}
}
}
var end_time = new Date().getTime();
var difference = (end_time - start_time)*1e-3;
console.log(difference);
}
main();
My point was to limit the number or tests and allocate local variable at the very last time in order to maximum CPU register and context. On a compile java version you might have even better results than me.
One optimization is removing the count > 1 test by rearranging the code like this
for(int i=0 ; i<A.length-1 ; i++) {
suma=A[i];
for(int k=i+1 ; k<A.length ; k++) {
suma+=A[k];
count++;
if(A[k]<A[k-1]) {
Related
Comparing creating large ArrayList with intialCapacity I found that it;s slower than creting it without one. Here is the simple program I wrote to measure it:
long start2 = System.nanoTime();
List<Double> col = new ArrayList<>(30000000); // <--- Here
for (int i = 0; i < 30000000; i++) {
col.add(Math.sqrt(i + 1));
}
long end2 = System.nanoTime();
System.out.println(end2 - start2);
System.out.println(col.get(12411325).hashCode() == System.nanoTime());
The average result for new ArrayList<>(30000000): 6121173329
The average result for new ArrayList<>(): 4883894100
on my machine. I thought that it would be faster to create large array once rather than reacreating it once we go beyond the capacity of the current underlying array of ArrayList. Eventually we should have ended up with array size greater or equal than 30000000.
I thought it was optimization, but actualy pessimization. Why that?
I ran the same program multiple times. It was not in a loop
Consider how you are profiling the code - if you include both a 'ramp up time' (to take into account things such as JIT) and average over several calls (to gather some statistics/distribution), the timing may lead you to a different conclusion. For example:
public static void main(String[] args){
//Warm up
System.out.println("Warm up");
for ( int i = 0; i < 5; i++ ){
dynamic();
constant();
}
System.out.println("Timing...");
//time
long e = 0;
long s = 0;
int total = 5;
for ( int i = 0; i < total; i++ ){
long e1 = dynamic();
System.out.print(e1 + "\t");
e += e1;
long s1 = constant();
System.out.println(s1);
s += s1;
}
System.out.println("Static Avg: " + (s/total));
System.out.println("Dynamic Avg: " + (e/total));
}
private static long dynamic(){
long start2 = System.currentTimeMillis();
List<Double> col = new ArrayList<>();
for (int i = 0; i < 30000000; i++) {
col.add(Math.sqrt(i + 1));
}
long end2 = System.currentTimeMillis();
return end2 - start2;
}
private static long constant(){
long start2 = System.currentTimeMillis();
List<Double> col = new ArrayList<>(30000000);
for (int i = 0; i < 30000000; i++) {
col.add(Math.sqrt(i + 1));
}
long end2 = System.currentTimeMillis();
return end2 - start2;
}
On my system setting the initial capacity is always faster, though not by any orders of magnitude.
Edit: As suggested in a comment, consider reading through How do I write a correct micro-benchmark in Java?
I have to create classes to be implemented with the main class someone else has and for some reason I am not getting the right outputs, I'm not sure is my calculations are off which I don't think they are or my insert class is wrong.
Expected Output:
Median = 44.5
Mean = 49.300
SD = 30.581
Actual Output:
Median = 0.0
Mean = 0.967
SD = 4.712
public class StatPackage {
int count;
double [] scores;
final int MAX = 500;
StatPackage() {
count = 0;
scores = new double[MAX];
}
public void insert (double value) {
if (count < MAX){
scores[count] = value;
++ count;
}
}
public double Mean () {
double sum = 0;
//For loop for calculating average or mean
for(int i = 0; i < scores.length; i++){
sum += (scores[i]);
count++;
}
double average = sum/count;
return average;
}
public double Median() {
int min;
int tmp;
int size;
for (int i = 0; i < scores.length - 1; i ++)
{
min = i;
for (int pos = i + 1; pos < scores.length; pos ++)
if (scores [pos] < scores [min])
min = pos;
tmp = (int)scores [min];
scores [min] = scores [i];
scores [i] = tmp;
}
double median = 0;
if (scores.length % 2 == 0){
median = (scores[scores.length/2-1] + scores[scores.length/2])/2;
}
else {
median = (scores[((scores.length/2))]);
}
return median;
}
public double Variance () {
double variance = 0;
double sum = 0;
//For loop for getting the variance
for(int i = 0; i < scores.length; i++){
sum += scores[i];
variance += scores[i] * scores[i];
count++;
}
double varianceFinal = ((variance/count)-(sum*sum)/(count*count));
return (varianceFinal);
}
public double StdDev (double variance) {
double sum = 0;
for(int i = 0; i < scores.length; i++){
sum += scores[i];
variance += scores[i] * scores[i];
count++;
}
double varianceFinal = ((variance/count)-(sum*sum)/(count*count));
return Math.sqrt(varianceFinal);
}
}
The length of your scores array is 500, so every time you are using it in a calculation you are running that 500 times. You need to make your loop continuation conditions dependent on the number of values in the array, no the actual length of the array. I would be careful of your variable naming as well, you are using count in two places sometimes and it has global scope! This method stores the number of values in the array in the count variable:
public void insert (double value) {
if (count < MAX){
scores[count] = value;
++count;
}
}
So use the count variable as the loop-continuation condition when you are getting values from the array, like so:
public double mean() {
double sum = 0;
//For loop for calculating average or mean
for(int i = 0; i < count; i++){
sum += (scores[i]);
}
double average = sum / count;
return average;
}
That should help a little, I don't have time to check out your other methods but maybe this will give you a good starting place. I figured out what was happening by inserting print statements in your methods to make sure the values were as expected. It's a helpful thing to do when debugging. Your mean() method with the print statements looks like this:
public double mean() {
double sum = 0;
//For loop for calculating average or mean
for(int i = 0; i < count; i++){
sum += (scores[i]);
}
// print statements for debugging
System.out.println("count is " + count);
System.out.println("sum is " + sum);
double average = sum / count;
return average;
}
Because the solution is easily found by debugging, I will only give you a hint:
The mean of 3, 4 and 5 is 4: (3+4+5)/3, not (3+4+5)/(n*3) where
n is a positive integer.
If you look at your mean and std and divide it by the expected result, you will see it's a rounded number.
Once you find the solution to 1 problem, you will immediately know why the other results are faulty as well =)
I have the following pieces of code:
long start = System.currentTimeMillis();
for(int i = 0; i < keys.length; ++i) {
obj.getElement(keys[i]);
}
long total = System.currentTimeMillis() - start;
System.out.println(total/1000d + " seconds");
And the following:
long start = System.currentTimeMillis();
for(int i = 0; i < keys.length; ++i) {
obj.hasElement(keys[i]);
}
long total = System.currentTimeMillis() - start;
System.out.println(total/1000d + " seconds");
The implementations of these methods are:
public T getElement(int key) {
int idx = findIndexOfElement(key);
return idx >= 0? ITEMS[idx]:null;
}
public boolean hasElement(int key) {
return findIndexOfElement(key) >= 0;
}
Pretty straightforward. The only difference between the 2 methods is the conditional access to the table.
Problem: When actually measuring the performance of these snippets the getElement takes twice the time than the hasElement.
So for a series of tests I get ~2.5seconds for the first loop of getElement and ~0.8 secs for the second loop of hasElement.
How is it possible to have such a big difference? I understand that the conditional statement is a branch and jump but still seems to me too big.
Is there a way to improve this?
Update:
The way I measure is:
long min = Long.MAX_VALUE;
long max = Long.MIN_VALUE;
long run = 0;
for(int i = 0; i < 10; ++i) {
long start = System.currentTimeMillis();
for(int i = 0; i < keys.length; ++i) {
obj.getElement(keys[i]);
}
long total = System.currentTimeMillis() - start;
System.out.println(total/1000d + " seconds");
if(total < min) {
min = time;
}
if(total > max) {
max = time;
}
run += time;
for(int i = 0; i < 50; ++i) {
System.gc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("min=" + min + " max=" + max);
System.out.println("avg = " + (double)run/1000/keys.length);
Is ITEMS definitely an array, and implemented as an array? If it is somehow implemented as a linked list, that would cause O(n) time instead of O(1) time on the get.
Your branches are probably the limiting factor in the short code posted. In the getElement method there is one branch and in the hasElement method there is another one plus it calls the getElement method, making it two branches for that method.
So in summary, the number of branches are double in that method and it seems very reasonable that the runtime also is double.
I have managed to create a number picker that loops through 5 to 60 in increments of 5. My only problem is that when I get to 60, the application crashes.
//Number pickers
int minValue = 5;
int maxValue = 60;
int step = 5;
String[] numberValues = new String[maxValue/minValue];
for (int i = minValue; i <= maxValue; i+= step)
{
numberValues[(i/step)-1] = String.valueOf(i);
}
mNumberPicker = (NumberPicker)findViewById(R.id.numberPicker);
mNumberPicker.setMinValue(0);
mNumberPicker.setMaxValue(60);
//mNumberPicker.setValue(20);
mNumberPicker.setWrapSelectorWheel(false);
mNumberPicker.setDisplayedValues(numberValues);
There is also an error message in the logcat
java.lang.ArrayIndexOutOfBoundsException: length=12; index=12
I don't understand why as the number has been created successfully so why does the number picker crash when it's chosen?
I will replace question's parameter mNumberPicker to np
setDisplayedValues() : The length of the displayed values array must be equal to the range of selectable numbers which is equal to np.getMaxValue() - np.getMinValue() + 1.
So, you have to make numberValues.length() == np.getMaxValue() - np.getMinValue() + 1 true.
In your case, make np.setMaxValue(12), not (60) and do like below. It will works.
Briefly, if you want 10~200 arrange in NumberPicker and expected step is 10 :
set minValue = 1, maxValue = 20 and step = 10;
int minValue = 1;
int maxValue = 12;
int step = 5;
String[] numberValues = new String[maxValue - minValue + 1];
for (int i = 0; i <= maxValue - minValue; i++) {
numberValues[i] = String.valueOf((minValue + i) * step);
}
np = (NumberPicker)findViewById(R.id.numberPicker);
np.setMinValue(minValue);
np.setMaxValue(maxValue);
np.setWrapSelectorWheel(false);
np.setDisplayedValues(numberValues);
`
Change this:
for (int i = minValue; i <= maxValue; i+= step)
{
numberValues[(i/step)-1] = String.valueOf(i);
}
To this:
for (int i = 0; i < numberValues.length; i++)
{
numberValues[i] = String.valueOf(step + i*step);
}
Or if you want to keep it confusing (haven't tested but should work):
for (int i = minValue; i < maxValue; i+= step)
{
numberValues[(i/step)-1] = String.valueOf(i);
}
There's another way to tackle the issue that, arguably, may seem more intuitive. It uses the onValueChange method:
#Override
public void onValueChange(NumberPicker np, int oldVal, int newVal) {
if (newVal > oldVal) {
if (newVal < np.getMaxValue())
np.setValue(newVal+(myStep-1));
}
else
np.setValue(newVal-(myStep-1));
}
I am trying to loop through this method 10 times that searches an array of numbers captures the run time in nano seconds and prints the results. I then want t take the 10 run times and find the average and standard deviation.
Is there a way to capture the time after 10 run and use the result to find my average and standard deviation?
This is what I have so far:
public class Search {
public static int Array[] = new int[100];
//Building my array with 100 numbers in sequential order
public static void createArray(){
int i = 0;
for(i = 0; i<Array.length; i++)
Array[i] = i + 1;
int check[] = {5, 15, 12};
int target = check[2];
boolean found = false;
int j = 0;
long startTime = System.nanoTime();
for(j=0; j<Array.length;j++){
if(Array[j] == target){
long endTime = System.nanoTime();
System.out.print(endTime - startTime + "ms" + "\t\t");
found = true;
break;
}
}
if(found){
//System.out.println("got you! "+ target + " is at index "+ j +"\t");..... just to test if it was working
}
else{
System.out.println("not available");
}
}
// Printing header
public static void main(String[]args){
System.out.print("First run\tSecond run\tThird run\tFourth run\tFifth run\tSixth run\tSeventh run\tEight run\tNinth run\tTenth run\tAverage \tStandard deviation\n");
// looping through the method 10 times
int i=0;
while(i<10){
createArray();
i++;
}
}
}
Try:
long sum = 0;
long sumSquare = 0;
for(int c = 0 ; c < 10 ; c++) {
long start = System.nanoTime();
// do work
long end = System.nanoTime();
sum += end - start;
sumSquare += Math.pow(end - start, 2);
}
double average = (sum * 1D) / 10;
double variance = (sumSquare * 1D) / 10 - Math.pow(average, 2);
double std = Math.sqrt(variance);
Try creating an array list of size 10 like:
private static List<Long> times = new ArrayList<>(10);
And then, when you find the element just add endTime - startTime to list like:
times.add(..);
And once that's done, in your main method you could do sum, average like:
long totalTime = 0;
for (Long time : times) {
totalTime += time;
}
//print average by dividing totalTime by 10.