Why does binary searching take REALLY long sometimes? - java

I wrote two programs that create random int[] and then generate random ints to search for. Well, really I only wrote one program, then modified the search method (like I'm supposed to for OOP, right?). I'm using System.nanoTime() to calculate the time lapsed during search. I get values of 10,000-13,000 consistently for the linear search, and MOSTLY times less than 5,000 for binary search(averaging in the sort time across all the searches, less than 4,000 typically for the search alone). Occasionally, though, it will through back times over 13,000, which is even longer than all but the very longest linear searches.
I have java priority set to Real Time in the task manager (Windows). What would cause the search time to triple or more? FWIW, I get about 1 spike in linear for every 3 or 4 in binary, and the linear spike is roughly twice the normal time (22,000 was the worst so far). Is it something with the way I've written the code?
If you don't want to read through the whole thing, in both cases I record the time in the line before calling the search method and the line after, so you can skip to the search method if you think that might be the problem. Reporting of that number is copy/pasted from one program to the other, but binary search program has more reporting that I thought would be interesting. Thanks in advance.
import java.util.Random;
public class LinearSearchTimer{
public static void main(String[] args){
int[] numbers;
final int MAX_RUNS;
double time1, time2, timeSpent, timeTotal;
int searchedNumber;
Random rand = new Random();
boolean result;
boolean[] resultArr;
int resultCounter;
double pctTrue;
MAX_RUNS = 1000;
numbers = new int[MAX_RUNS];
resultArr = new boolean[MAX_RUNS];
resultCounter = 0;
timeTotal = 0;
//build array with random ints
for(int k = 0; k < numbers.length; k++){
numbers[k] = rand.nextInt(10001);
}
//generate random number and search array for it, then store to result array
for(int i = 0; i < numbers.length; i++){
searchedNumber = rand.nextInt(10001);
time1 = System.nanoTime();
result = search(numbers, searchedNumber);
time2 = System.nanoTime();
resultArr[resultCounter] = result;
resultCounter++;
timeSpent = time2 - time1;
timeTotal += timeSpent;
}
pctTrue = resultPercent(resultArr);
System.out.println("Avg time : " + timeTotal / MAX_RUNS);
System.out.println("Percent found: " + pctTrue * 100);
}
//search algorithm, returns true if found, false if not
public static boolean search(int[] numbers, int searchedNumber){
int i = 0;
boolean found = false;
while (found == false && i < numbers.length){
if (numbers[i] == searchedNumber)
found = true;
i++;
}
return found;
}
public static double resultPercent(boolean[] arr){
int trueCount = 0;
double result;
double runs;
for(boolean element : arr){
if (element == true)
trueCount++;
}
runs = arr.length;//for calculating percentage as a forced double
result = trueCount / runs;
return result;
}
}
and then...
import java.util.Arrays;
import java.util.Random;
public class BinarySearchTimer{
public static void main(String[] args){
//declare variables
int[] numbers;
final int MAX_RUNS;
double time1, time2, timeSpent, timeTotal;
int searchedNumber;
Random rand;
boolean result;
boolean[] resultArr;
int resultCounter;
double pctTrue;
double timeSort1, timeSort2, timeSortSpent;
//instantiate variables
MAX_RUNS = 1000;
numbers = new int[MAX_RUNS];
resultArr = new boolean[MAX_RUNS];
resultCounter = 0;
timeTotal = 0;
rand = new Random();
//build array with random ints
for(int k = 0; k < numbers.length; k++){
numbers[k] = rand.nextInt(10001);
}
//sort array
timeSort1 = System.nanoTime();
Arrays.sort(numbers);
timeSort2 = System.nanoTime();
timeSortSpent = timeSort2 - timeSort1;
//generate random number and call search method
for(int i = 0; i < numbers.length; i++){
searchedNumber = rand.nextInt(10001);
//get start time
time1 = System.nanoTime();
result = search(numbers, searchedNumber, 0, numbers.length - 1);
//get end time
time2 = System.nanoTime();
resultArr[resultCounter] = result;
resultCounter++;
timeSpent = time2 - time1;
timeTotal += timeSpent;
}
pctTrue = resultPercent(resultArr);
System.out.println("Avg time : " + timeTotal / MAX_RUNS);
System.out.println("Percent found: " + pctTrue * 100);
System.out.println("Actual sort time: " + timeSortSpent);
System.out.println("Sort time shared per search: " + timeSortSpent / MAX_RUNS);
System.out.println("Effective average search time: " + (timeTotal / MAX_RUNS + timeSortSpent / MAX_RUNS));
}
//search algorithm, returns true if found, false if not
public static boolean search(int[] numbers, int searchedNumber, int low, int high){
int mid = (high + low) / 2;
if(low > high)
return false;
if(numbers[mid] == searchedNumber){
return true;
}
else if(searchedNumber < numbers[mid]){
mid--;
return search(numbers, searchedNumber, low, mid);
}
else if(searchedNumber > numbers[mid]){
mid++;
return search(numbers, searchedNumber, mid, high);
}
return false;
}
public static double resultPercent(boolean[] arr){
int trueCount = 0;
double result;
double runs;
for(boolean element : arr){
if (element == true)
trueCount++;
}
runs = arr.length;//for calculating percentage as a forced double
result = trueCount / runs;
return result;
}
}

Related

TestClass for simple sorting algorithms gives unlogical results

I have the following Class with some sorting algorithms like MaxSort, BubbleSort, etc.:
class ArrayUtility {
public static int returnPosMax(int[] A, int i, int j) {
int max = i;
int position = 0;
for(int c = 0; c <= j; c++){
if(c >= i){
if(A[c] > max){
max = A[c];
position = c;
}
}
}
return position;
}
public static int returnMax(int[] A, int i, int j) {
return A[returnPosMax(A, i, j)];
}
public static void swap(int[] A, int i, int j) {
int b = A[i];
A[i] = A[j];
A[j] = b;
}
public static void MaxSort(int[] A) {
int posMax;
for(int i = A.length - 1; i >= 0; i--){
posMax = returnPosMax(A, 0, i);
swap(A, posMax, i);
}
}
public static void BubbleSort(int[] A) {
boolean flag = true;
while (flag != false){
flag = false;
for(int i = 1; i <= A.length - 1; i++){
if(A[i-1]>A[i]){
swap(A, i-1, i);
flag = true;
}
}
if(flag = false) {
break;
}
for(int i = A.length - 1; i >= 1; i--){
if(A[i-1]>A[i]){
swap(A, i - 1, i);
flag = true;
}
}
}
}
public static void BubbleSortX(int[] A) {
boolean flag = true;
while (flag != false){
flag = false;
for(int i = 1; i <= A.length - 1; i++){
if(A[i-1]>A[i]){
swap(A, i-1, i);
flag = true;
}
}
}
}
}
Now i have to create a Test Class to evaluate the different sorting algorithms for different lengths of randomly created Arrays:
import java.util.Random;
import java.util.Arrays;
public class TestSorting{
public static void main(String[] args){
int[] lengthArray = {100, 1000, 10000, 100000};
for(int i = 0; i <= lengthArray.length - 1; i++){
int[] arr = new int[i];
for(int j = 0; j < i; j++){
Random rd = new Random();
int randInt = rd.nextInt();
arr[j] = randInt;
}
/* long startTime = System.nanoTime();
ArrayUtility.MaxSort(arr);
long cpuTime = System.nanoTime() - startTime;
System.out.println("Time: " + cpuTime + " - Array with Length: " + lengthArray[i] + " Using MaxSort"); */
/* long startTime = System.nanoTime();
ArrayUtility.BubbleSortX(arr);
long cpuTime = System.nanoTime() - startTime;
System.out.println("Time: " + cpuTime + " - Array with Length: " + lengthArray[i] + " Using BubbleSortX"); */
long startTime = System.nanoTime();
ArrayUtility.BubbleSort(arr);
long cpuTime = System.nanoTime() - startTime;
System.out.println("Time: " + cpuTime + " - Array with Length: " + lengthArray[i] + " Using BubbleSort");
/*long startTime = System.nanoTime();
Arrays.sort(arr)
long cpuTime = System.nanoTime() - startTime;
System.out.println("Time: " + cpuTime + " - Array with Length: " + lengthArray[i] + " Using BubbleSort"); */
}
}
}
Now when i run a certain sorting algorithm (i set the others as comment for the meantime), i get weird results, for example
Time: 1049500 - Array with Length: 100 Using BubbleSort
Time: 2200 - Array with Length: 1000 Using BubbleSort
Time: 13300 - Array with Length: 10000 Using BubbleSort
Time: 3900 - Array with Length: 100000 Using BubbleSort
And any time i run the test i get different results, such that Arrays with 10 times the length take less time to sort, also i dont understand why the array with 100 integers takes so long.
TL;DR: your benchmark is wrong.
Explanation
To make a good benchmark, you need to do a lot of research. A good starting point is this article and this talk by Alexey Shipilev, the author of micro-benchmark toolkit JMH.
Main rules for benchmarking:
warm up! Do a bunch (like, thousands) of warmup rounds before you actually measure stuff - this will allow JIT compiler to do its job, all optimizations to apply, etc.
Monitor your GC closely - GC event can skid the results drastically
To avoid that - repeat the benchmark many (hundreds thousands) times and get the average.
All this can be done in JMH.
I took a snippet out of your code to show you where your code is buggy.
public static void main(String[] args){
int[] lengthArray = {100, 1000, 10000, 100000};
for(int i = 0; i <= lengthArray.length - 1; i++) { // this loop goes from 0 - 3
int[] arr = new int[i]; // thats why this array will be of size 0 - 3
// correct line would be:
// int[] arr = new int[lengthArray[i]];
for(int j = 0; j < i; j++) {
// correct line would be:
// for (int j = 0; j < arr.length; j++) {
...
Additionally, the hint for benchmarking from Dmitry is also important to note.

Why does the maximum sum subarray stop working consistently if my int array has more than 65535 elements?

I have a program that generates an array based on the user input (the array can be descending, ascending and two types of random) and then it calculates the maximum subarray sum using bruteforce, divide and conquer, and dynamic programming. It seems to work fine and dandy up to values of 65535. After that, each sum is different, which shouldn't happen. 35535 is 2 to the power of 16 minus 1, so I was wondering if I'm hitting some limit. When I print the array it seems to print fine, so I don't think that the problem is that the array isn't generating properly.
This is the main class:
public class MainClass {
public static void main(String[] args) {
int n = Integer.parseInt(args[1]);
int[] maxsubarray1;
maxsubarray1 = new Generator(n,args[3]).getArray();
int[] maxsubarray2 = Arrays.copyOf(maxsubarray1,maxsubarray1.length);
int[] maxsubarray3 = Arrays.copyOf(maxsubarray1,maxsubarray1.length);
System.out.println(Arrays.toString(maxsubarray1));
solver solver = new solver();
int solution;
//if (args[5].equalsIgnoreCase("bruteforce")){
long startTime = System.currentTimeMillis();
solution = solver.bruteforce(maxsubarray1, n);
System.out.println("__________BRUTE FORCE________\nThe sum of the array is "+solution);
long endTime = System.currentTimeMillis() - startTime;
System.out.println(endTime);
//}
//if (args[5].equalsIgnoreCase("divideconquer")){
long startTime2 = System.currentTimeMillis();
int solutiondivideconquer = solver.divideconquer(maxsubarray2, 0, n);
System.out.println("__________DIVIDE AND CONQUERE________\nThe sum of the array is "+ solutiondivideconquer);
long endTime2 = System.currentTimeMillis() - startTime2;
System.out.println(endTime2);
//}
//if (args[5].equalsIgnoreCase("dynprog")){
long startTime3 = System.currentTimeMillis();
int solutiondynprog = solver.dynprog(maxsubarray3, n);
System.out.println("__________DYNAMIC PROGRAMMING________\nThe sum of the array is "+ solutiondynprog);
long endTime3 = System.currentTimeMillis() - startTime3;
System.out.println(endTime3);
//}
}
}
This is the generator code:
import java.util.concurrent.ThreadLocalRandom;
public class Generator {
int size;
String type;
int[] generatedArray;
public Generator(int mysize, String mytype){
size = mysize;
type = mytype;
generatedArray = new int[size];
}
public void ascending(){
for(int i = 0; i < this.size; i++)
generatedArray[i] = i+1;
}
public void descending(){
for(int i = this.size -1; i >= 0; i--)
generatedArray[i] = i+1;
}
public void random(){
for(int i = 0; i <= this.size -1; i++)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10*this.size, 10*this.size);
}
public void randominter(){
for(int i = 0; i <= this.size -1; i++)
if (i % 2 == 0)
generatedArray[i] = ThreadLocalRandom.current().nextInt(1, 10*this.size);
else if (i % 2 == 1)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10*this.size, -1);
}
public int[] getArray(){
if (type.equalsIgnoreCase("descending")){
this.descending();
return generatedArray;
}
if (type.equalsIgnoreCase("ascending")){
this.ascending();
return generatedArray;
}
if (type.equalsIgnoreCase("random")){
this.random();
return generatedArray;
}
if (type.equalsIgnoreCase("randominter")){
this.randominter();
return generatedArray;
}
return null;
}
}
And this is the solver class:
public class solver {
//brute force algorithm with complexity O(n^2)
int bruteforce(int array[], int n){
int max = Integer.MIN_VALUE;
//We go throght all the elements of the list and we try all the
//posible combinations with all the other elements
for (int i = 0; i < n; i++){
int sum = 0;
for (int j = i; j < n ; j++){
//we add the an element in the sum
sum += array[j];
//we check if the sum with the new element is greater that the value we had before
if(sum > max){
//if it's greater, it becomes the new value
max = sum;
}
}
}
//we return the maximum value we have found
return max;
}
//to implement the divide and conquer algorithm we have to take into account the
// maximum subarray can have elements in the right subarray and in the left subarray
int maxCrossingSum(int array[], int l, int m, int h){
int sum = 0;
int left_sum = Integer.MIN_VALUE;
//Has the elements on the left part of the arrray
for ( int i = (int)m; i >= l; i--){
sum = sum + array[i];
if( sum > left_sum ){
left_sum = sum;
}
}
sum = 0;
int right_sum = 0;
//Has the elements in the right part of the array
for ( int j = (int)m+1; j <= h; j++){
sum = sum + array [j];
if (sum > right_sum){
right_sum = sum;
}
}
//returns the sun of the elements on the left and the right of the array
return left_sum + right_sum;
}
//returns the sum of the maximum subarray
int maxSubarraySum(int array[], int l, int h){
if(l == h)
return array[1];
int m = (l + h)/2;
//checks which is the maximum between left and right
int maxBetweenLeftRight = max(maxSubarraySum(array, l, m), maxSubarraySum(array, m+1,h));
int crossing = maxCrossingSum(array, l, m,h-1);
//retrns the maximum between one of the sides and the crossing sum
return max(maxBetweenLeftRight, crossing);
}
//divide and conquere algorithm with complexity O(nlogn)
//only made to make it more understandable from the main
//can call maxSubarraySum and it would be the same
int divideconquer (int array[], int l, int h){
return maxSubarraySum(array, l, h);
}
//dynamic programming algorithm with complexity O(n)
int dynprog(int array[], int n){
int a = array[0];
int b = array[0];
//for all the elements checks if the sum was better until the
//step before or adding the element
for (int i = 1 ; i < n; i++){
a= max (a+ array[i], array[i]);
b= max(b, a);
}
return b;
}
}
Changing all the ints to longs didn't help either.
I've copied your code, changed all ints to longs and it's working fine. Also changed n = Integer.parseInt(args[0]) instead of n = Integer.parseInt(args[1]).
Then I called my program like program_name 1000 random.
I've checked in excel, and only bruteforce was wrong. I've changed Integer.MIN_VALUE to Long.MIN_VALUE. And int sum to long sum.
Main.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class Main {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
long[] maxsubarray1;
maxsubarray1 = new Generator(n, args[1]).getArray();
long[] maxsubarray2 = Arrays.copyOf(maxsubarray1, maxsubarray1.length);
long[] maxsubarray3 = Arrays.copyOf(maxsubarray1, maxsubarray1.length);
System.out.println(Arrays.toString(maxsubarray1));
solver solver = new solver();
long solution;
//if (args[5].equalsIgnoreCase("bruteforce")){
long startTime = System.currentTimeMillis();
solution = solver.bruteforce(maxsubarray1, n);
System.out.println("__________BRUTE FORCE________\nThe sum of the array is " + solution);
long endTime = System.currentTimeMillis() - startTime;
System.out.println(endTime);
//}
//if (args[5].equalsIgnoreCase("divideconquer")){
long startTime2 = System.currentTimeMillis();
long solutiondivideconquer = solver.divideconquer(maxsubarray2, 0, n);
System.out.println("__________DIVIDE AND CONQUERE________\nThe sum of the array is " + solutiondivideconquer);
long endTime2 = System.currentTimeMillis() - startTime2;
System.out.println(endTime2);
//}
//if (args[5].equalsIgnoreCase("dynprog")){
long startTime3 = System.currentTimeMillis();
long solutiondynprog = solver.dynprog(maxsubarray3, n);
System.out.println("__________DYNAMIC PROGRAMMING________\nThe sum of the array is " + solutiondynprog);
long endTime3 = System.currentTimeMillis() - startTime3;
System.out.println(endTime3);
//}
}
}
solver.java
public class solver {
//brute force algorithm with complexity O(n^2)
long bruteforce(long array[], int n){
long max = Long.MIN_VALUE;
//We go throght all the elements of the list and we try all the
//posible combinations with all the other elements
for (int i = 0; i < n; i++){
long sum = 0;
for (int j = i; j < n ; j++){
//we add the an element in the sum
sum += array[j];
//we check if the sum with the new element is greater that the value we had before
if(sum > max){
//if it's greater, it becomes the new value
max = sum;
}
}
}
//we return the maximum value we have found
return max;
}
//to implement the divide and conquer algorithm we have to take into account the
// maximum subarray can have elements in the right subarray and in the left subarray
long maxCrossingSum(long array[], long l, long m, long h){
long sum = 0;
long left_sum = Integer.MIN_VALUE;
//Has the elements on the left part of the arrray
for ( int i = (int)m; i >= l; i--){
sum = sum + array[i];
if( sum > left_sum ){
left_sum = sum;
}
}
sum = 0;
long right_sum = 0;
//Has the elements in the right part of the array
for ( int j = (int)m+1; j <= h; j++){
sum = sum + array [j];
if (sum > right_sum){
right_sum = sum;
}
}
//returns the sun of the elements on the left and the right of the array
return left_sum + right_sum;
}
//returns the sum of the maximum subarray
long maxSubarraySum(long array[], long l, long h){
if(l == h)
return array[1];
long m = (l + h)/2;
//checks which is the maximum between left and right
long maxBetweenLeftRight = max(maxSubarraySum(array, l, m), maxSubarraySum(array, m+1,h));
long crossing = maxCrossingSum(array, l, m,h-1);
//retrns the maximum between one of the sides and the crossing sum
return max(maxBetweenLeftRight, crossing);
}
//divide and conquere algorithm with complexity O(nlogn)
//only made to make it more understandable from the main
//can call maxSubarraySum and it would be the same
long divideconquer (long array[], int l, int h){
return maxSubarraySum(array, l, h);
}
//dynamic programming algorithm with complexity O(n)
long dynprog(long array[], int n){
long a = array[0];
long b = array[0];
//for all the elements checks if the sum was better until the
//step before or adding the element
for (int i = 1 ; i < n; i++){
a= max (a+ array[i], array[i]);
b= max(b, a);
}
return b;
}
private long max(long a, long b) {
if (a > b ) return a;
else return b;
}
}
Generator.java
import java.util.concurrent.ThreadLocalRandom;
public class Generator {
int size;
String type;
long[] generatedArray;
public Generator(int mysize, String mytype) {
size = mysize;
type = mytype;
generatedArray = new long[size];
}
public void ascending() {
for (int i = 0; i < this.size; i++)
generatedArray[i] = i + 1;
}
public void descending() {
for (int i = this.size - 1; i >= 0; i--)
generatedArray[i] = i + 1;
}
public void random() {
for (int i = 0; i <= this.size - 1; i++)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10 * this.size, 10 * this.size);
}
public void randominter() {
for (int i = 0; i <= this.size - 1; i++)
if (i % 2 == 0)
generatedArray[i] = ThreadLocalRandom.current().nextInt(1, 10 * this.size);
else if (i % 2 == 1)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10 * this.size, -1);
}
public long[] getArray() {
if (type.equalsIgnoreCase("descending")) {
this.descending();
return generatedArray;
}
if (type.equalsIgnoreCase("ascending")) {
this.ascending();
return generatedArray;
}
if (type.equalsIgnoreCase("random")) {
this.random();
return generatedArray;
}
if (type.equalsIgnoreCase("randominter")) {
this.randominter();
return generatedArray;
}
return null;
}
}
I was wrong, it CAN BE an overflow error if Array[i] = i + 1, since the sum is length * (min + max) / 2 > Integer.MAX_VALUE

Generate a permutation x number of times and calculate probability of it's Chi Square Distribution

This question is extremely specific. I have found dozens of places telling you how to generate random permutations in Java, but it never got as far as calculating the probability of the Chi Square Distribution. Let me tell you that setting it up seemed fair enough, with many tutorials online, but one thing about this code that has really nagged me was the fact that in the second part of the assignment, I'm supposed to generate a random permutation of a string from index j where j is chosen randomly between the range of 0 and i. One method is supposed to output a probability of 1.0 all the time, which is biased and unfair, while the second method generates a probability of any number between 0 and 1.0. I've got the first part of that in part 1, but the second part I am having trouble making it not display 1.0 all the time. The assignment says that i simply steps through the array. In this circumstance, two styles of permutation generation were tried:
Method 1:
public static String generatePermutation(String prefix, String t){
int n = 6;
String s = "";
StringBuilder test = new StringBuilder(t);
if (n == 0){
System.out.println(prefix);
}
else {
for(int i = 0; i < n; i++){
int j = randInt(0, i);
char temp = test.charAt(j);
test.setCharAt(j, test.charAt(i));
test.setCharAt(i, temp);
}
s = test.toString();
return s;
}
return s;
}
public static int randInt(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
Method 2:
public static String generatePermutation(String prefix, String t){
char[] letters = t.toCharArray();
shuffle(letters);
String s = new String(letters);
return s;
}
public static void shuffle(char[] array){
int n = array.length;
Random rand = new Random();
while(n > 1){
int k = rand.nextInt(n--);
char temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
public static int randInt(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
Both methods did not seem to give me a random number probability between 0 and 1.0. The current code for part 2 of the assignment is structured like this:
package math3323assignment7;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Collections;
import org.apache.commons.math3.distribution.ChiSquaredDistribution;
import com.google.common.collect.Multiset;
import com.google.common.collect.TreeMultiset;
public class assignment7part2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
String s = "ABCDEF";
Map<String, Integer> counts = new HashMap<>();
Integer count;
int expected = (int)factorial(s.length());
for(int i = 0; i < 720000; i++){
String t = generatePermutation("",s);
count = counts.get(t);
if(count == null){
count = 1;
}
else {
count = count + 1;
}
counts.put(t, count);
System.out.println(t);
}
for(Entry<String, Integer> entry : counts.entrySet()){
System.out.println(entry.getValue() + " times: " + entry.getKey());
}
double chistat = 0.0;
for(Entry<String, Integer> entry: counts.entrySet()){
double di = entry.getValue() - expected;
chistat += di*di/expected;
}
ChiSquaredDistribution chisq = new ChiSquaredDistribution(719.0);
double prob = chisq.cumulativeProbability(chistat);
System.out.printf("ChiSquare statistic = " + chistat + " the probability is " + prob);
}
public static String generatePermutation(String prefix, String t){
char[] letters = t.toCharArray();
shuffle(letters);
String s = new String(letters);
return s;
}
public static long factorial(int n){
if (n <= 1){
return 1;
}
else {
return n * factorial(n-1);
}
}
public static void shuffle(char[] array){
int n = array.length;
Random rand = new Random();
while(n > 1){
int k = rand.nextInt(n--);
char temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
public static int randInt(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
}
As you can see, the Apache Math Distribution class from the Apache API is being used to create the Chi Square Distribution. A separate for loop is being used to calculate the Chi Square statistic. Unfortunately, when I run the program, the output always has a similar vein right at the very end to this:
Prints all random permutations 720,000 times
Counts all the times each permutation occurs, and print out the numbers
ChiSquare statistic = 79360.74444444438 the probability is 1.0
I want the final part to print out like this:
ChiSquare statistic = 79360.74444444438 the probability is 0.64
May you please help me fix this to where the final result of the second part of the program looks like the above line?
The expected value you are using is incorrect. Your output should demonstrate a count that is somewhere around 1000 for each random permutation. One would expect each to be exactly 1000 in a non-random setting, because 720000 / 1000 = 720 which is what you are computing with
int expected = (int)factorial(s.length());
Instead try
int expected = 1000;

Looping through a method and using the results

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.

Java Compute Average Execution Time

I want to compute the average execution time of x number of runs (i.e. 10)... I can easily execute 10 times using the loop in the main method, but how can I store the execution times & compute the average? I'm thinking this is something really simple, but I'm drawing a blank at the moment... Thanks in advanced!
import java.util.Arrays;
import java.util.Random;
public class OptQSort1 {
static boolean insertionSortCalled = false;
private static final Random random = new Random();
private static final int RANDOM_INT_RANGE = 9999;
private static int[] randomArray(int size) {
// Randomize data (array)
final int[] arr = new int[size];
for (int i = 0; i < arr.length; i++) {
arr[i] = random.nextInt(RANDOM_INT_RANGE);
}
return arr;
}
// Sort
private static void sort(int[] arr) {
if (arr.length > 0)
sortInPlace(arr, 0, arr.length - 1);
}
private static void sortInPlace(int[] arr, int left, int right) {
// OptQSort1:
int size = right - left + 1;
if (size < 10 && !insertionSortCalled) {
insertionSortCalled = true;
insertionSort(arr, 0, arr.length - 1);
}
if (left >= right)
return; // sorted
final int range = right - left + 1;
int pivot = random.nextInt(range) + left;
int newPivot = partition(arr, left, right, pivot);
sortInPlace(arr, left, newPivot - 1);
sortInPlace(arr, newPivot + 1, right);
}
private static int partition(int[] arr, int left, int right, int pivot) {
int pivotVal = arr[pivot];
swapArrayVals(arr, pivot, right);
int storeIndex = left;
for (int i = left; i <= (right - 1); i++) {
if (arr[i] < pivotVal) {
swapArrayVals(arr, i, storeIndex);
storeIndex++;
}
}
swapArrayVals(arr, storeIndex, right);
return storeIndex;
}
private static void swapArrayVals(int[] arr, int from, int to) {
int fromVal = arr[from];
int toVal = arr[to];
arr[from] = toVal;
arr[to] = fromVal;
}
public static void insertionSort(int[] arr, int left, int right) {
int in, out;
for (out = left + 1; out <= right; out++) {
int temp = arr[out];
in = out;
while (in > left && arr[in - 1] >= temp) {
arr[in] = arr[in - 1];
--in;
}
arr[in] = temp;
}
}
public static void main(String[] args) {
long StartTime = System.nanoTime();
int runCount = 0;
// Array size
int[] arr = randomArray(1000);
int[] copy = Arrays.copyOf(arr, arr.length);
// Print original data (array)
System.out.println("The starting/unsorted array: \n"
+ Arrays.toString(arr));
sort(arr);
do {
// check the result
Arrays.sort(copy);
if (Arrays.equals(arr, copy)) {
System.out.println("The ending/sorted array: \n"
+ Arrays.toString(arr));
// print time
long TotalTime = System.nanoTime() - StartTime;
System.out.println("Total elapsed time (milliseconds) " + "is: "
+ TotalTime + "\n");
runCount++;
}
} while (runCount < 10);
}
}
You can compute the average by just measuring the total time for 10 iterations of your code, then divide that by 10.
e.g:
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 0; i < 10; ++i) {
doSort();
}
long elapsed = System.currentTimeMillis() - start;
long average = elapsed / 10;
}
As a helpful tip, use a named constant rather than a literal value for the number of iterations:
private final static int ITERATIONS = 10;
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; ++i) {
doSort();
}
long elapsed = System.currentTimeMillis() - start;
long average = elapsed / ITERATIONS;
}
This means you only have to change the number in one place if you want to run, say, 50 or 100 iterations.
You should also be aware that it is very difficult to get accurate timing results from this kind of experiment. It's a good idea to include a "warm-up" phase to allow the JIT to evaluate and optimize the code, and to have a much larger number of iterations:
private static final int WARMUP_ITERATIONS = 10000;
private static final int RUN_ITERATIONS = 100000;
public static void main(String[] args) {
// Warmup with no timing
for (int i = 0; i < WARMUP_ITERATIONS; ++i) {
doSort();
}
// Now the real test
long start = System.currentTimeMillis();
for (int i = 0; i < RUN_ITERATIONS; ++i) {
doSort();
}
long elapsed = System.currentTimeMillis() - start;
long average = elapsed / RUN_ITERATIONS;
}
To calculate the average time, you need the sum of the times. The sum of the times is the total time, so you don't even need to know the individual times or record them. Just take the end-to-end time and divide by the count.
int count = ...
long start = System.nanoTime();
for(int i=0;i<count;i++) {
// do something
}
long time = System.nanoTime() - start;
long averageTime = time/count;
The JIT doesn't fully warmup until you have done at least 10,000 iterations, so you might ignore the first 11,000 if this is practical.
A simple way to do this is
int count = ...
long start = 0;
for(int i=-11000;i<count;i++) {
if(i == 0) start = System.nanoTime();
// do something
}
long time = System.nanoTime() - start;
long averageTime = time/count;
BTW: Only include in the test time the things you want to time. Generating random numbers , for example, could take longer than the sort itself which could give misleading results.
EDIT: The compile threshold which determines when a method or loop is compiled is controlled with -XX:CompileThresholed= which defaults to 10000 on the server JVM and 1500 on the client JVM. http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
-XX:CompileThreshold=10000 Number of method invocations/branches before
compiling [-client: 1,500]
You can use a list of integers to store the result for each run, but you don't need it to calculate average, just divide totaltime by number of runs.
Btw, your measurements are not very good:
1) Generation of random arrays is included there
2) 10 runs is not enought
before the execution:
long start = System.currentTimeMillis();
after the execution:
long end = System.currentTimeMillis();
add each time in an ArrayList like this:
times.add(end-start);
get the average time:
Long total = 0;
for(Long l : times)
total += l;
System.out.println("Average Time: "+(total/times.size()));
Be careful the unit of time of the return value is a millisecond.
Just keep a second long value that is a running total of the Totaltime values. When the loop exits, just divide by runCount.
Alternatively, create an ArrayList<Long> to store the times. Each time you do one run, add Totaltime to the array. After the loop exits, you can average the values and also compute other statistics (min/max, standard deviation, etc.).

Categories

Resources