counting different values in a vector with Aparapi - java

i want to implement an Entropy function in parallel with APARAPI.
in that function i need to count different keys in a vector but it cant execute correctly.
assume that we have just 3 different values.
here is my codes:
final int[] V = new int[1024];
// Initialization for V values
final int[] count = new int[3];
Kernel kernel = new Kernel(){
#Override
public void run(){
int gid = getGlobalId();
count[V[gid]]++;
}
};
kernel.execute(Range.create(V.length));
kernel.dispose();
after run this code segment, when i print count[] values it gives me 1,1,1.
it seems that count[V[gid]]++ execute just 1 time for each V[gid].
thanks.

So here is the problem. The ++ operator is actually three operations in one: read the current value, increment it, write the new value. In Aparapi you have potentially 1024 GPU threads running simultaneously. That means they will read the value, probably all the same time when the value is 0, then increment it to 1, then all 1024 threads will write 1. So it is acting as expected.
What you are trying to do is called a Map-reduce function. You are just skipping a lot of steps. You need to remember Aparapi is a system that has no Thread safety, so you have to write your algorithms to accommodate that. That is where Map-reduce comes in and here is how to do one. I just wrote it and added it to the Aparapi repository at its new home, details below.
int size = 1024;
final int count = 3;
final int[] V = new int[size];
//lets fill in V randomly...
for (int i = 0; i < size; i++) {
//random number either 0, 1, or 2
V[i] = (int) (Math.random() * 3);
}
//this will hold our values between the phases.
int[][] totals = new int[count][size];
///////////////
// MAP PHASE //
///////////////
final int[][] kernelTotals = totals;
Kernel mapKernel = new Kernel() {
#Override
public void run() {
int gid = getGlobalId();
int value = V[gid];
for(int index = 0; index < count; index++) {
if (value == index)
kernelTotals[index][gid] = 1;
}
}
};
mapKernel.execute(Range.create(size));
mapKernel.dispose();
totals = kernelTotals;
//////////////////
// REDUCE PHASE //
//////////////////
while (size > 1) {
int nextSize = size / 2;
final int[][] currentTotals = totals;
final int[][] nextTotals = new int[count][nextSize];
Kernel reduceKernel = new Kernel() {
#Override
public void run() {
int gid = getGlobalId();
for(int index = 0; index < count; index++) {
nextTotals[index][gid] = currentTotals[index][gid * 2] + currentTotals[index][gid * 2 + 1];
}
}
};
reduceKernel.execute(Range.create(nextSize));
reduceKernel.dispose();
totals = nextTotals;
size = nextSize;
}
assert size == 1;
/////////////////////////////
// Done, just print it out //
/////////////////////////////
int[] results = new int[3];
results[0] = totals[0][0];
results[1] = totals[1][0];
results[2] = totals[2][0];
System.out.println(Arrays.toString(results));
Keep in mind while it may seem inefficient it actually works pretty well on much larger number. This algorithm works just fine with
size = 1048576.
With the new size the following result was computed on my system in about a second.
[349602, 349698, 349276]
One final note, you might want to consider moving to the more active project at aparapi.com. It includes several fixes to bugs and a lot of extra features and performance enhancements over the older library you linked above. It is also in maven central with about a dozen releases. so it is easier to use. I just wrote the code in this answer but decided to use it in the new Aparapi repository's example section, you can find that at the following link in the new Aparapi repository.

Related

searching for the highest and the smallest value in a specific range - Random

so far in the program the values were searched randomly, but I want to modify the program to search for random numbers in a given range. Generally speaking, My point is that the draw should be from the given range (from-to), and not up to 1000 random numbers as in the above code, so my question is:
How can I pass the value from and to random: rand.nextInt (?) so that the numbers are randomly drawn in a given range. so I generally need to get a printout from the program like in the question: expected output
// Create array to be searched
final int[] arrayToSearch = new int[20];
Random rnd = new Random();
for (int i = 0; i < arrayToSearch.length; i++)
arrayToSearch[i] = rnd.nextInt(1000);
System.out.println(Arrays.toString(arrayToSearch));
final int PARTITIONS = 4;
Thread[] threads = new Thread[PARTITIONS];
final int[] partitionMin = new int[PARTITIONS];
final int[] partitionMax = new int[PARTITIONS];
for (int i = 0; i < PARTITIONS; i++) {
final int partition = i;
threads[i] = new Thread(new Runnable() {
#Override
public void run() {
// Find min/max values in sub-array
int from = arrayToSearch.length * partition / PARTITIONS;
int to = arrayToSearch.length * (partition + 1) / PARTITIONS;
int min = Integer.MAX_VALUE,
max = Integer.MIN_VALUE;
for (int j = from; j < to; j++) {
min = Math.min(min, arrayToSearch[j]);
max = Math.max(max, arrayToSearch[j]);
}
partitionMin[partition] = min;
partitionMax[partition] = max;
});
so far:
partition 0: from=0, to=5, min=23, max=662 //the draw in the range 0-5, draw is outside the specified range
expected output:
partition 1: from=0, to=5, min=1, max=3 // the draw takes place within the given range 0 to 5
partition 2: from=20, to=30, min=22, max=29 //the draw takes place within the given range 20 to 30
How can I pass the value from and to random: rand.nextInt (?) so that the numbers are randomly drawn in a given range
Try it like this. This will generate values between from and to inclusive.
int from = -100;
int to = 100;
int draw = ThreadLocalRandom.current().nextInt(from, to);
You can actually generate your own Supplier to just get random numbers in a specified range.
The BiFunction returns a Supplier. And the Supplier can be called to get the a random number in the range.
BiFunction<Integer, Integer, IntSupplier> rndGen = (f,
t) -> () -> ThreadLocalRandom.current().nextInt(f, t+1);
IntSupplier rnd = rndGen.apply(from,to);
So each time rnd.getAsInt() is invoked, you will get a number in the desired range.
Note: There are of course methods that do this pretty much automatically. But I presumed you wanted to work out the logic of finding min and max yourself so I did not include those.
Class Random has method ints (long streamSize, int randomNumberOrigin, int randomNumberBound) to generate IntStream of random numbers in the given range, and then the summary statistics may be collected for such stream:
static void printMinMax(int size, int from, int to) {
IntSummaryStatistics stats = new Random()
.ints(size, from, to)
.summaryStatistics();
System.out.printf("min = %d, max = %d%n", stats.getMin(), stats.getMax());
}
Test:
printMinMax(20, 20, 200); // min = 30, max = 198
Create a random number of your choosing however you want.
If it's under your From value, add your From value to it.
If it's over your To value mod it by your To value.

Why is Arrays.binarySearch not improving the performance compared to walking the array?

I gave a shot at solving the Hackerland Radio Transmitters programming challange.
To summarize, challenge goes as follows:
Hackerland is a one-dimensional city with n houses, where each house i is located at some xi on the x-axis. The Mayor wants to install radio transmitters on the roofs of the city's houses. Each transmitter has a range, k, meaning it can transmit a signal to all houses ≤ k units of distance away.
Given a map of Hackerland and the value of k, can you find the minimum number of transmitters needed to cover every house?
My implementation is as follows:
package biz.tugay;
import java.util.*;
public class HackerlandRadioTransmitters {
public static int minNumOfTransmitters(int[] houseLocations, int transmitterRange) {
// Sort and remove duplicates..
houseLocations = uniqueHouseLocationsSorted(houseLocations);
int towerCount = 0;
for (int nextHouseNotCovered = 0; nextHouseNotCovered < houseLocations.length; ) {
final int towerLocation = HackerlandRadioTransmitters.findNextTowerIndex(houseLocations, nextHouseNotCovered, transmitterRange);
towerCount++;
nextHouseNotCovered = HackerlandRadioTransmitters.nextHouseNotCoveredIndex(houseLocations, towerLocation, transmitterRange);
if (nextHouseNotCovered == -1) {
break;
}
}
return towerCount;
}
public static int findNextTowerIndex(final int[] houseLocations, final int houseNotCoveredIndex, final int transmitterRange) {
final int houseLocationWeWantToCover = houseLocations[houseNotCoveredIndex];
final int farthestHouseLocationAllowed = houseLocationWeWantToCover + transmitterRange;
int towerIndex = houseNotCoveredIndex;
int loop = 0;
while (true) {
loop++;
if (towerIndex == houseLocations.length - 1) {
break;
}
if (farthestHouseLocationAllowed >= houseLocations[towerIndex + 1]) {
towerIndex++;
continue;
}
break;
}
System.out.println("findNextTowerIndex looped : " + loop);
return towerIndex;
}
public static int nextHouseNotCoveredIndex(final int[] houseLocations, final int towerIndex, final int transmitterRange) {
final int towerCoversUntil = houseLocations[towerIndex] + transmitterRange;
int notCoveredHouseIndex = towerIndex + 1;
int loop = 0;
while (notCoveredHouseIndex < houseLocations.length) {
loop++;
final int locationOfHouseBeingChecked = houseLocations[notCoveredHouseIndex];
if (locationOfHouseBeingChecked > towerCoversUntil) {
break; // Tower does not cover the house anymore, break the loop..
}
notCoveredHouseIndex++;
}
if (notCoveredHouseIndex == houseLocations.length) {
notCoveredHouseIndex = -1;
}
System.out.println("nextHouseNotCoveredIndex looped : " + loop);
return notCoveredHouseIndex;
}
public static int[] uniqueHouseLocationsSorted(final int[] houseLocations) {
Arrays.sort(houseLocations);
final HashSet<Integer> integers = new HashSet<>();
final int[] houseLocationsUnique = new int[houseLocations.length];
int innerCounter = 0;
for (int houseLocation : houseLocations) {
if (integers.contains(houseLocation)) {
continue;
}
houseLocationsUnique[innerCounter] = houseLocation;
integers.add(houseLocationsUnique[innerCounter]);
innerCounter++;
}
return Arrays.copyOf(houseLocationsUnique, innerCounter);
}
}
I am pretty sure this implementation is correct. But please see the detail in the functions: findNextTowerIndex and nextHouseNotCoveredIndex: they walk the array one by one!
One of my tests is as follows:
static void test_01() throws FileNotFoundException {
final long start = System.currentTimeMillis();
final File file = new File("input.txt");
final Scanner scanner = new Scanner(file);
int[] houseLocations = new int[73382];
for (int counter = 0; counter < 73382; counter++) {
houseLocations[counter] = scanner.nextInt();
}
final int[] uniqueHouseLocationsSorted = HackerlandRadioTransmitters.uniqueHouseLocationsSorted(houseLocations);
final int minNumOfTransmitters = HackerlandRadioTransmitters.minNumOfTransmitters(uniqueHouseLocationsSorted, 73381);
assert minNumOfTransmitters == 1;
final long end = System.currentTimeMillis();
System.out.println("Took: " + (end - start) + " milliseconds..");
}
where input.txt can be downloaded from here. (It is not the most important detail in this question, but still..) So we have an array of 73382 houses, and I deliberately set the transmitter range so the methods I have loop a lot:
Here is a sample output from this test in my machine:
findNextTowerIndex looped : 38213
nextHouseNotCoveredIndex looped : 13785
Took: 359 milliseconds..
I also have this test, which does not assert anything, but just keeps time:
static void test_02() throws FileNotFoundException {
final long start = System.currentTimeMillis();
for (int i = 0; i < 400; i ++) {
final File file = new File("input.txt");
final Scanner scanner = new Scanner(file);
int[] houseLocations = new int[73382];
for (int counter = 0; counter < 73382; counter++) {
houseLocations[counter] = scanner.nextInt();
}
final int[] uniqueHouseLocationsSorted = HackerlandRadioTransmitters.uniqueHouseLocationsSorted(houseLocations);
final int transmitterRange = ThreadLocalRandom.current().nextInt(1, 70000);
final int minNumOfTransmitters = HackerlandRadioTransmitters.minNumOfTransmitters(uniqueHouseLocationsSorted, transmitterRange);
}
final long end = System.currentTimeMillis();
System.out.println("Took: " + (end - start) + " milliseconds..");
}
where I randomly create 400 transmitter ranges, and run the program 400 times.. I will get run times as follows in my machine..
Took: 20149 milliseconds..
So now, I said, why don 't I use binary search instead of walking the array and changed my implementations as follows:
public static int findNextTowerIndex(final int[] houseLocations, final int houseNotCoveredIndex, final int transmitterRange) {
final int houseLocationWeWantToCover = houseLocations[houseNotCoveredIndex];
final int farthestHouseLocationAllowed = houseLocationWeWantToCover + transmitterRange;
int nextTowerIndex = Arrays.binarySearch(houseLocations, 0, houseLocations.length, farthestHouseLocationAllowed);
if (nextTowerIndex < 0) {
nextTowerIndex = -nextTowerIndex;
nextTowerIndex = nextTowerIndex -2;
}
return nextTowerIndex;
}
public static int nextHouseNotCoveredIndex(final int[] houseLocations, final int towerIndex, final int transmitterRange) {
final int towerCoversUntil = houseLocations[towerIndex] + transmitterRange;
int nextHouseNotCoveredIndex = Arrays.binarySearch(houseLocations, 0, houseLocations.length, towerCoversUntil);
if (-nextHouseNotCoveredIndex > houseLocations.length) {
return -1;
}
if (nextHouseNotCoveredIndex < 0) {
nextHouseNotCoveredIndex = - (nextHouseNotCoveredIndex + 1);
return nextHouseNotCoveredIndex;
}
return nextHouseNotCoveredIndex + 1;
}
and I am expecting a great performance boost, as now I will at most loop for log(N) times, instead of O(N).. So test_01 outputs:
Took: 297 milliseconds..
Remember, it was Took: 359 milliseconds.. before. And for test_02:
Took: 18047 milliseconds..
So I always get values around 20 seconds with array walking implementation and 18 - 19 seconds for binary search implementation.
I was expecting a much better performance gain using Arrays.binarySearch but obviously it is not the case, why is this? What am I missing? Do I need an array with more than 73382 to see the benefit, or is it irrelevant?
Edit #01
After #huck_cussler 's comment, I tried doubling and tripling the dataset I have (with random numbers) and tried running test02 (of course with tripling the array sizes in the test itself..). For the linear implementation the times go like this:
Took: 18789 milliseconds..
Took: 34396 milliseconds..
Took: 53504 milliseconds..
For the binary search implementation, I got values as follows:
Took: 18644 milliseconds..
Took: 33831 milliseconds..
Took: 52886 milliseconds..
Your timing includes the retrieval of data from your hard drive. This could be taking the majority of your runtime. Omit the data load from your timing to get a more accurate comparison of your two approaches. Imagine if it takes up 18 seconds and you're comparing 18.644 vs 18.789 (0.77% improvement) instead of 0.644 vs 0.789 (18.38% improvement).
If you have a linear operation O(n), such as loading a binary structure, and you combine it with a binary search O(log n), you end up with O(n). If you trust Big O notation, then you should expect O(n + log n) to not be significantly different from O(2 * n) as they both reduce to O(n).
Also, a binary search may perform better or worse than a linear search depending on the density of houses between towers. Consider, say 1024 homes with a tower evenly dispersed every 4 homes. A linear search will step 4 times per tower, while a binary search will take log2(1024)=10 steps per tower.
One more thing... your minNumOfTransmitters method is sorting the already-sorted array passed into it from test_01 and test_02. That resorting step takes longer than your searches themselves, which further obscures the timing differences between your two search algorithms.
======
I created a small timing class to give a better picture of what's happening. I've removed the line of code from minNumOfTransmitters to prevent it from rerunning the sort, and added a boolean param to select whether to use your binary version. It totals the sum of times for 400 iterations, separating out each step. The results on my system illustrate that the load time dwarfs the sort time, which in turn dwarfs the solve time.
Load: 22.565s
Sort: 4.518s
Linear: 0.012s
Binary: 0.003s
It's easy to see how optimizing that last step doesn't make much difference in overall runtime.
private static class Timing {
public long load=0;
public long sort=0;
public long solve1=0;
public long solve2=0;
private String secs(long millis) {
return String.format("%3d.%03ds", millis/1000, millis%1000);
}
public String toString() {
return " Load: " + secs(load) + "\n Sort: " + secs(sort) + "\nLinear: " + secs(solve1) + "\nBinary: " + secs(solve2);
}
public void add(Timing timing) {
load+=timing.load;
sort+=timing.sort;
solve1+=timing.solve1;
solve2+=timing.solve2;
}
}
static Timing test_01() throws FileNotFoundException {
Timing timing=new Timing();
long start = System.currentTimeMillis();
final File file = new File("c:\\path\\to\\xnpwdiG3.txt");
final Scanner scanner = new Scanner(file);
int[] houseLocations = new int[73382];
for (int counter = 0; counter < 73382; counter++) {
houseLocations[counter] = scanner.nextInt();
}
timing.load+=System.currentTimeMillis()-start;
start=System.currentTimeMillis();
final int[] uniqueHouseLocationsSorted = HackerlandRadioTransmitters.uniqueHouseLocationsSorted(houseLocations);
timing.sort=System.currentTimeMillis()-start;
start=System.currentTimeMillis();
final int minNumOfTransmitters = HackerlandRadioTransmitters.minNumOfTransmitters(uniqueHouseLocationsSorted, 73381, false);
timing.solve1=System.currentTimeMillis()-start;
start=System.currentTimeMillis();
final int minNumOfTransmittersBin = HackerlandRadioTransmitters.minNumOfTransmitters(uniqueHouseLocationsSorted, 73381, true);
timing.solve2=System.currentTimeMillis()-start;
final long end = System.currentTimeMillis();
return timing;
}
In your time measurement you include operations that are much slower than array search. Namely filesystem I/O and array sorting.
I/O in general (reading/writing from filesystem, network communication) is by orders of magnitude slower than operations that involve only CPU and RAM access.
Let's rewrite your test in a way that does not read the file on every loop iteration:
static void test_02() throws FileNotFoundException {
final File file = new File("input.txt");
final Scanner scanner = new Scanner(file);
int[] houseLocations = new int[73382];
for (int counter = 0; counter < 73382; counter++) {
houseLocations[counter] = scanner.nextInt();
}
scanner.close();
final int rounds = 400;
final int[] uniqueHouseLocationsSorted = uniqueHouseLocationsSorted(houseLocations);
final int transmitterRange = 73381;
final long start = System.currentTimeMillis();
for (int i = 0; i < rounds; i++) {
final int minNumOfTransmitters = minNumOfTransmitters(uniqueHouseLocationsSorted, transmitterRange);
}
final long end = System.currentTimeMillis();
System.out.println("Took: " + (end - start) + " milliseconds..");
}
Notice in this version of the test the file is read only once and time measuring starts after that.
With the above, I get Took: 1700 milliseconds.. (more or less a few millis) for both the iterative version and the binary search. So we still can't see that binary search is faster. That's because almost all of that time goes into sorting the array 400 times.
Now let's remove the line that sorts the input array from the minNumOfTransmitters method. We sort the array (once) anyway at the beginning of the test.
Now we can see that things are much faster. After removing the line houseLocations = uniqueHouseLocationsSorted(houseLocations) from minNumOfTransmitters I get: Took: 68 milliseconds.. for the iterative version. Clearly, since this duration is already very small, we will not see a significant difference with the binary search version.
So let's increase the number of loop rounds to: 100000.
Now I get Took: 2121 milliseconds.. for the iterative version and Took: 36 milliseconds.. for the binary search version.
Because we now isolated what we measure and focus on the array searches, rather than including operations that are much slower, we can notice the big difference in performance (for the better) of binary search.
If you want to see how many times binary search enters its while loop, you can implement it yourself and add a counter:
private static int binarySearch0(int[] a, int fromIndex, int toIndex, int key) {
int low = fromIndex;
int high = toIndex - 1;
int loop = 0;
while (low <= high) {
loop++;
int mid = (low + high) >>> 1;
int midVal = a[mid];
if (midVal < key) {
low = mid + 1;
} else if (midVal > key) {
high = mid - 1;
} else {
return mid; // key found
}
}
System.out.println("binary search looped " + loop + " times");
return -(low + 1); // key not found.
}
The method is copied from the Arrays class in the JDK - I just added the loop counter and the println.
When the length of the array to search is 73382, the loop enters only 16 times.
That is exactly what we expect: log(73382) =~ 16.
I agree with other answers that the main issue with your tests is that they measure wrong things: IO and sorting. But I don't think suggested tests are good. My suggestion is following:
static void test_02() throws FileNotFoundException {
final File file = new File("43620487.txt");
final Scanner scanner = new Scanner(file);
int[] houseLocations = new int[73382];
for (int counter = 0; counter < 73382; counter++) {
houseLocations[counter] = scanner.nextInt();
}
final int[] uniqueHouseLocationsSorted = uniqueHouseLocationsSorted(houseLocations);
final Random random = new Random(0); // fixed seed to have the same sequences in all tests
long sum = 0;
// warm up
for (int i = 0; i < 100; i++) {
final int transmitterRange = random.nextInt(70000) + 1;
final int minNumOfTransmitters = minNumOfTransmitters(uniqueHouseLocationsSorted, transmitterRange);
sum += minNumOfTransmitters;
}
// actual measure
final long start = System.currentTimeMillis();
for (int i = 0; i < 4000; i++) {
final int transmitterRange = random.nextInt(70000) + 1;
final int minNumOfTransmitters = minNumOfTransmitters(uniqueHouseLocationsSorted, transmitterRange);
sum += minNumOfTransmitters;
}
final long end = System.currentTimeMillis();
System.out.println("Took: " + (end - start) + " milliseconds. Sum = " + sum);
}
Note also that I remove all System.out.println calls from findNextTowerIndex and nextHouseNotCoveredIndex and uniqueHouseLocationsSorted call from minNumOfTransmitters as they affect performance testing as well.
So what I think is important here:
Move all I/O and sorting out of the measurement loop
Perform some warm up outside of measurement
Use the same random sequence for all measurements
Don't dispose result of the calculation so JIT can't optimize that call out altogether
With such test I see about 10 times difference on my machine: around 80ms vs around 8ms.
And if you really want to do performance tests in Java you should consider using JMH aka Java Microbenchmark Harness
Agree with other answers, the IO time is most problem, and sort is second, the search is last time consumer.
And agree phatfingers's example, the binary search sometime is worst than linear search in your problem because totally linear search goes one loop for every element(n times compare) but binary search run for tower times (O(logn)*#tower)), one suggestion is that binary search not start from 0, but from current location
int nextTowerIndex = Arrays.binarySearch(houseLocations, houseNotCoveredIndex+1, houseLocations.length, arthestHouseLocationAllowed)
then it should O(logn)*#tower/2)
Even more, maybe you can calculate every tower cover how many houses avg then first compare avg houses then using binary search start from houseNotCoveredIndex + avg + 1, but not sure the performance is much better.
ps: sort and unique you can using TreeSet as
public static int[] uniqueHouseLocationsSorted(final int[] houseLocations) {
final Set<Integer> integers = new TreeSet<>();
for (int houseLocation : houseLocations) {
integers.add(houseLocation);
}
int[] unique = new int[integers.size()];
int i = 0;
for(Integer loc : integers){
unique[i] = loc;
i++;
}
return unique;
}
uniqueHouseLocationsSorted is not efficient, andy solution seems better, but I think this could improve the time spent (note that I did not test the code):
public static int[] uniqueHouseLocationsSorted(final int[] houseLocations) {
int size = houseLocations.length;
if (size == 0) return null; // you have to check for null later or maybe throw an exception here
Arrays.sort(houseLocations);
final int[] houseLocationsUnique = new int[size];
int previous = houseLocationsUnique[0] = houseLocations[0];
int innerCounter = 1;
for (int i = 1; i < size; i++) {
int houseLocation = houseLocations[i];
if (houseLocation == previous) continue; // since elements are sorted this is faster
previous = houseLocationsUnique[innerCounter++] = houseLocation;
}
return Arrays.copyOf(houseLocationsUnique, innerCounter);
}
Consider also using an Array list as copying the array takes time.

Java Multithreaded vector addition

I am trying to get familiar with java multithreaded applications. I tried to think of a simple application that can be parallelized very well. I thought vector addition would be a good application to do so.
However, when running on my linux server (which has 4 cores) I dont get any speed up. The time to execute on 4,2,1 threads is about the same.
Here is the code I came up with:
public static void main(String[]args)throws InterruptedException{
final int threads = Integer.parseInt(args[0]);
final int length= Integer.parseInt(args[1]);
final int balk=(length/threads);
Thread[]th = new Thread[threads];
final double[]result =new double[length];
final double[]array1=getRandomArray(length);
final double[]array2=getRandomArray(length);
long startingTime =System.nanoTime();
for(int i=0;i<threads;i++){
final int current=i;
th[i]=new Thread(()->{
for(int k=current*balk;k<(current+1)*balk;k++){
result[k]=array1[k]+array2[k];
}
});
th[i].start();
}
for(int i=0;i<threads;i++){
th[i].join();
}
System.out.println("Time needed: "+(System.nanoTime()-startingTime));
}
length is always a multiple of threads and getRandomArray() creates a random array of doubles between 0 and 1.
Execution Time for 1-Thread: 84579446ns
Execution Time for 2-Thread: 74211325ns
Execution Time for 4-Thread: 89215100ns
length =10000000
Here is the Code for getRandomArray():
private static double[]getRandomArray(int length){
Random random =new Random();
double[]array= new double[length];
for(int i=0;i<length;i++){
array[i]=random.nextDouble();
}
return array;
}
I would appreciate any help.
The difference is observable for the following code. Try it.
public static void main(String[]args)throws InterruptedException{
for(int z = 0; z < 10; z++) {
final int threads = 1;
final int length= 100_000_000;
final int balk=(length/threads);
Thread[]th = new Thread[threads];
final boolean[]result =new boolean[length];
final boolean[]array1=getRandomArray(length);
final boolean[]array2=getRandomArray(length);
long startingTime =System.nanoTime();
for(int i=0;i<threads;i++){
final int current=i;
th[i]=new Thread(()->{
for(int k=current*balk;k<(current+1)*balk;k++){
result[k]=array1[k] | array2[k];
}
});
th[i].start();
}
for(int i=0;i<threads;i++){
th[i].join();
}
System.out.println("Time needed: "+(System.nanoTime()-startingTime)*1.0/1000/1000);
boolean x = false;
for(boolean d : result) {
x |= d;
}
System.out.println(x);
}
}
First things first you need to warmup your code. This way you will measure compiled code. The first two iterations have the same(approximately) time but the next will differ. Also I changed double to boolean because my machine doesn't have much memory. This allows me to allocate a huge array and it also makes work more CPU consuming.
There is a link in comments. I suggest you to read it.
Hi from my side if you are trying to see how your cores shares work you can make very simple task for all cores, but make them to work constantly on something not shared across different threads (basically to simulate for example merge sort, where threads are working on something complicated and use shared resources in a small amount of time). Using your code i did something like this. In such case you should see almost exactly 2x speed up and 4 times speed up.
public static void main(String[]args)throws InterruptedException{
for(int a=0; a<5; a++) {
final int threads = 2;
final int length = 10;
final int balk = (length / threads);
Thread[] th = new Thread[threads];
System.out.println(Runtime.getRuntime().availableProcessors());
final double[] result = new double[length];
final double[] array1 = getRandomArray(length);
final double[] array2 = getRandomArray(length);
long startingTime = System.nanoTime();
for (int i = 0; i < threads; i++) {
final int current = i;
th[i] = new Thread(() -> {
Random random = new Random();
int meaningless = 0;
for (int k = current * balk; k < (current + 1) * balk; k++) {
result[k] = array1[k] + array2[k];
for (int j = 0; j < 10000000; j++) {
meaningless+=random.nextInt(10);
}
}
});
th[i].start();
}
for (int i = 0; i < threads; i++) {
th[i].join();
}
System.out.println("Time needed: " + ((System.nanoTime() - startingTime) * 1.0) / 1000000000 + " s");
}
}
You see, in your code most time is consumed by building big table, and then threads are executing very fast, their work is so fast that your calculation of time is wrong because most of time is consumed by creating threads. When i invoked code which works on precalculated loop like this:
long startingTime =System.nanoTime();
for(int k=0; k<length; k++){
result[k]=array1[k]|array2[k];
}
System.out.println("Time needed: "+(System.nanoTime()-startingTime));
It worked two times faster than your code with 2 threads. I hope that you understand what i mean in this case and will see my point when i gave my threads much more meaningless work.

I am trying to get the mode of an input of ten numbers in java

import java.util.*;
public class main {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] quiz = new int[10];
int mean = 0,mode = 0,median,range;
Scanner scan = new Scanner(System.in);
for(int x=0;x<=9;x++){
System.out.print("Enter quiz["+(x+1)+"]:");
quiz[x]= scan.nextInt();
}
Arrays.sort(quiz);
for(int x=0;x<=9;x++){
mean = mean+quiz[x];
}
mean = mean/10;
median = (quiz[4]+quiz[5])/2;
range = quiz[9]-quiz[0];
int[] cntr = new int[10];
for(int x=0;x<=9;x++){
for(int y=0;y<=9;y++){
if (quiz[x]==quiz[y]&&x!=y){
cntr[x]++;
}
}
}
int[] sortcntr = cntr;
int ndx = 0;
Arrays.sort(sortcntr);
for(int z=0;z<=9;z++){
if(cntr[z]==sortcntr[9]){
ndx = z;
}
else
mode=0;
}
mode = quiz[ndx];
System.out.println("Mean: "+mean);
System.out.println("Median: "+median);
System.out.println("Range: "+range);
if(mode==0){
System.out.println("Mode: none");
}
else
System.out.println("Mode: "+mode);
System.out.print(sortcntr[9]);
System.out.print(cntr[9]);
System.out.println(ndx);
}
}
this is the codes that i used everything is right except for the mode. the mode variable there always returns the highest number from the number. the latter part was just for debugging and not for use. please help
The main problem of your code is that you obviously think that the line
int[] sortcntr = cntr;
creates a copy of the array cntr. However, arrays have reference semantics in Java. Thus, you simply create a second reference to the same array. If you then sort sortcntr, it applies to cntr as well since it's the same array.
To create a copy of the array:
int[] sortcntr = new int[ cntr.length ];
System.arraycopy(cntr, 0, sortcntr, 0, cntr.length);
BTW: Wouldn't it make more sense to work with floating-point numbers (double) instead of integer numbers?
for(int x=0;x<=9;x++){
for(int y=0;y<=9;y++){
The inner loop should start at x+1, otherwise you count everything twice.
Just to help you out, if you decide to more generify (As Raffaele said) the process of getting the mode of a given set of data, here is a method I developed a while ago which will even return multiple modes if there are more than one with the same occurrence. (Uses the Java 8 Stream API)
/**
* Computes the mode of the passed integers.
*
* #param args Numbers to find the mode of.
* #return Mode of the passed numbers.
*/
public static int[] mode(int... args) {
/* Create a map of integers to their frequencies */
Map<Integer, Integer> frequencies = IntStream.of(args).collect(
HashMap::new,//Indicated that this collector will result in a HashMap
(integerIntegerMap, value) -> integerIntegerMap.merge(value, 1, Maths::sum), //For each value in the arguments added, merge it with the current map and add the frequencies
(integerIntegerMap, integerIntegerMap2) -> integerIntegerMap.putAll(integerIntegerMap2) //While this is not used, it simply combines 2 HashMaps. (I think this is only used when in parallel)
);
//Here we get the maximum number of occurrences for any number, we could return the mode here; but there could be multiple modes
int maxOccurrences = frequencies.entrySet().stream().mapToInt(Map.Entry::getValue).max().getAsInt();
//Here we simply go through the entry set again, filtering out only the numbers with a frequency equal to the max, then returning them as an array
return frequencies.entrySet().stream().filter(entry -> entry.getValue() == maxOccurrences).mapToInt(Map.Entry::getKey).toArray();
}
-Thomas
Since the input is already sorted to compute range and median, you can use the following code to get the mode after a single loop and without any extra memory (live on ideone):
// this must be sorted
int[] values = {1, 1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 8};
int mode = values[0];
int modeOccurrences = 1;
int occurrences = 1;
int current = values[0];
for (int i = 1; i < values.length; i++) {
int value = values[i];
if (value == current) {
occurrences++;
} else {
if (occurrences > modeOccurrences) {
mode = current;
modeOccurrences = occurrences;
}
occurrences = 1;
current = value;
}
}
if (occurrences > modeOccurrences) {
mode = current;
modeOccurrences = occurrences;
}
You can even generify this piece of code to work with plain objects instead of numerical types, provided modes can be sorted and compared (I used enums in my demo)

How to create a number generator that will only pick a number 1 time?

I am creating a concentration game.
I have an buffered image array where I load in a 25 image sprite sheet.
public static BufferedImage[] card = new BufferedImage[25];
0 index being the card back. and 1 - 24 being the values for the face of the cards to check against if the cards match.
What I am tying to do is this I will have 4 difficulties Easy, Normal, Hard, and Extreme. Each difficulty will have a certain amount of cards it will need to draw and then double the ones it chosen. for example the default level will be NORMAL which is 12 matches so it need to randomly choose 12 unique cards from the Buffered Image array and then double each value so it will only have 2 of each cards and then shuffle the results.
This is what I got so far but it always seems to have duplicates about 99% of the time.
//generate cards
Random r = new Random();
int j = 0;
int[] rowOne = new int[12];
int[] rowTwo = new int[12];
boolean[] rowOneBool = new boolean[12];
for(int i = 0; i < rowOneBool.length; i++)
rowOneBool[i] = false;
for(int i = 0; i < rowOne.length; i++){
int typeId = r.nextInt(12)+1;
while(rowOneBool[typeId]){
typeId = r.nextInt(12)+1;
if(rowOneBool[typeId] == false);
}
rowOne[i] = typeId;
j=0;
}
the 3 amounts I will be needing to generate is Easy 6, Normal 12, and Hard 18 extreme will use all of the images except index 0 which is the back of the cards.
This is more or less in the nature of random numbers. Sometimes they are duplicates. You can easily factor that in though if you want them to be more unique. Just discard the number and generate again if it's not unique.
Here's a simple method to generate unique random numbers with a specified allowance of duplicates:
public static void main(String[] args) {
int[] randoms = uniqueRandoms(new int[16], 1, 25, 3);
for (int r : randoms) System.out.println(r);
}
public static int[] uniqueRandoms(int[] randoms, int lo, int hi, int allowance) {
// should do some error checking up here
int range = hi - lo, duplicates = 0;
Random gen = new Random();
for (int i = 0, k; i < randoms.length; i++) {
randoms[i] = gen.nextInt(range) + lo;
for (k = 0; k < i; k++) {
if (randoms[i] == randoms[k]) {
if (duplicates < allowance) {
duplicates++;
} else {
i--;
}
break;
}
}
}
return randoms;
}
Edit: Tested and corrected. Now it works. : )
From what I understand from your question, the answer should look something like this:
Have 2 classes, one called Randp and the other called Main. Run Main, and edit the code to suit your needs.
package randp;
public class Main {
public static void main(String[] args) {
Randp randp = new Randp(10);
for (int i = 0; i < 10; i++) {
System.out.print(randp.nextInt());
}
}
}
package randp;
public class Randp {
private int numsLeft;
private int MAX_VALUE;
int[] chooser;
public Randp(int startCounter) {
MAX_VALUE = startCounter; //set the amount we go up to
numsLeft = startCounter;
chooser = new int[MAX_VALUE];
for (int i = 1; i <= chooser.length; i++) {
chooser[i-1] = i; //fill the array up
}
}
public int nextInt() {
if(numsLeft == 0){
return 0; //nothing left in the array
}
int a = chooser[(int)(Math.random() * MAX_VALUE)]; //picking a random index
if(a == 0) {
return this.nextInt(); //we hit an index that's been used already, pick another one!
}
chooser[a-1] = 0; //don't want to use it again
numsLeft--; //keep track of the numbers
return a;
}
}
This is how I would handle it. You would move your BufferedImage objects to a List, although I would consider creating an object for the 'cards' you're using...
int removalAmount = 3; //Remove 3 cards at random... Use a switch to change this based upon difficulty or whatever...
List<BufferedImage> list = new ArrayList<BufferedImage>();
list.addAll(Arrays.asList(card)); // Add the cards to the list, from your array.
Collections.shuffle(list);
for (int i = 0; i < removalAmount; i++) {
list.remove(list.size() - 1);
}
list.addAll(list);
Collections.shuffle(list);
for (BufferedImage specificCard : list) {
//Do something
}
Ok, I said I'd give you something better, and I will. First, let's improve Jeeter's solution.
It has a bug. Because it relies on 0 to be the "used" indicator, it won't actually produce index 0 until the end, which is not random.
It fills an array with indices, then uses 0 as effectively a boolean value, which is redundant. If a value at an index is not 0 we already know what it is, it's the same as the index we used to get to it. It just hides the true nature of algorithm and makes it unnecessarily complex.
It uses recursion when it doesn't need to. Sure, you can argue that this improves code clarity, but then you risk running into a StackOverflowException for too many recursive calls.
Thus, I present an improved version of the algorithm:
class Randp {
private int MAX_VALUE;
private int numsLeft;
private boolean[] used;
public Randp(int startCounter) {
MAX_VALUE = startCounter;
numsLeft = startCounter;
// All false by default.
used = new boolean[MAX_VALUE];
}
public int nextInt() {
if (numsLeft <= 0)
return 0;
numsLeft--;
int index;
do
{
index = (int)(Math.random() * MAX_VALUE);
} while (used[index]);
return index;
}
}
I believe this is much easier to understand, but now it becomes clear the algorithm is not great. It might take a long time to find an unused index, especially when we wanted a lot of values and there's only a few left. We need to fundamentally change the way we approach this. It'd be better to generate the values randomly from the beginning:
class Randp {
private ArrayList<Integer> chooser = new ArrayList<Integer>();
private int count = 0;
public Randp(int startCounter) {
for (int i = 0; i < startCounter; i++)
chooser.add(i);
Collections.shuffle(chooser);
}
public int nextInt() {
if (count >= chooser.size())
return 0;
return chooser.get(count++);
}
}
This is the most efficient and extremely simple since we made use of existing classes and methods.

Categories

Resources