I am writing a multi-threaded Java program that generates lot of random numbers.
Additional Details:
These numbers are used to create a list of random numbers from 0-99 without repetition and such that every number in the range 0-99 exists in the list (In other words, the list contains 100 unique elements in the range 0-99).
Generating Random Numbers [Things already tried!]
I have an ArrayList of numbers from 0-100. I generate a random number and use it as an index which is used to pop out an element from the ArrayList.
I have used Collections.shuffle().
Here is the code for approach 1:
ArrayList<Integer> arr = new ArrayList<Integer>();
for (int i = 0; i < N; i++){
arr.add(i, i);
}
for(int i=0; i<N; i++){
int indx = rand.nextInt(arr.size());
res.add(arr.get(indx));
arr.remove(indx);
}
For second approach, I replaced the second for loop with Collections.shuffle(arr).
As generating list of random numbers is the most expensive part of my algorithm, I want to optimize it. This brings me to the questions:
What is the fastest way to generate random numbers?
What is the fastest way to generate the list of random numbers as described above?
PS:
I found Collections.shuffle() to be slower than the first approach
Someone suggested me using rngd to generate random numbers from hardware in Unix. Has anyone tried this before? How do you do that?
I think the problem with Collections.shuffle() is that is uses default Random instance which is a thread-safe singleton. You say that your program is multi-threaded, so I can imagine synchronization in Random being a bottle-neck.
If you are happily running on Java 7, simply use ThreadLocalRandom. Look carefully, there is a version of shuffle() taking Random instance explicitly:
Collections.shuffle(arr, threadLocalRandom);
where threadLocalRandom is created only once.
On Java 6 you can simply create a single instance of Random once per thread. Note that you shouldn't create a new instance of Random per run, unless you can provide random seed every time.
Part of the problem might be the overhead of the Integer boxing and unboxing. You might find it helpful to reimplement the Fisher-Yates shuffle directly on an int[].
My approach woul be to generate the numbers with the Math.random() method as in the example here and initialize the list via a static init block like this:
private static List<int> list = new ArrayList<int>();
static {
for(int i = 0; i < 100; i++) {
// randomize number
list.add(number);
}
}
Hope this helped, have Fun!
To shuffle an array a of n elements (indices 0..n-1):
for i from n − 1 downto 1 do
j ← random integer with 0 ≤ j ≤ i
exchange a[j] and a[i]
Check Fischer and Yattes algorithm.
Related
I have looked up how to add 0-99 to an array. But, my assignment was 1-1000000. I just keep getting really large numbers and no small numbers. Is it just because the chance of getting large numbers is a lot higher? I just wanted to make sure I was doing it right. Thanks in advance for any help!
int a[]= new int[50];
for(int i = 0; i < 50; i++) {
a[i] = (int)(Math.random() * 10000000);
}
Depends what do you call by small numbers.
For example, getting number lower than 1000 means that it would need to fit to lower 0.1% of the interval as 1000 it's just 0.1% of all the numbers from 1 million.
Additionally, note that this way you'll get numbers between 0 and 999999 (inclusive). To get 1-1000000 you need to add 1:
a[i] = (int)(Math.random() * 10000000)+1;
Well if you hoped to get a number below 1000, there's a 1/10000 chance, which translates to 0.01%. Your code is fine, but with these settings getting a low number is quite unlikely
Yes, large numbers will dominate with that. That's because half the numbers are over 500,000. Similarly, 9/10 of the numbers are over 100,000. So 9/10 of the numbers will have six digits.
[Somewhat orthogonal solution to your question]
One of the options you can consider is to shuffle the array after adding the numbers based on your expected distribution, which can be all numbers added once/certain numbers added multiple times/certain prime numbers multiple times, etc.
I personally used it to cover some cases for a game development.
Here is an answer which can help you shuffle: Credits
List<Integer> solution = new ArrayList<>();
for (int i = 1; i <= 6; i++) {
solution.add(i);
}
Collections.shuffle(solution);
An array is taken as input from the user. The array contains integers. Add some, all, or maybe just one is enough, to get a sum as close to 100 as possible.
The array can contain 1-100 integers
Each integer in the array has the value between 1-100, some could be the same. The come in random order in the array
there is no limit how many that should be added in order to get as close to 100 as possible
If several combinations are possible or give equal answers are equally close to 100, as 99 and 101, the highest should be chosen.
My problem is that I really don´t know how to work the loops. I have tried nestling two, but I find it tricky not to know how many integers in the array that might be needed for the calculation.
My loops so far loops each integer:
//looping over all integers in the array
for (int i = 0; i < myArray.length; i++) {
//check already here if it is close to 100?
//compare the integer above to the next
for (int j = i + 1; nextWeight < myArray.length; j++) {
//the results should be saved temporary to comparision to new sums
}
}
I know it is not much and I know it could somehow involve dynamic programming.
Does anyone have any idea that could help me on the way?
By my interpretation of your question, your biggest problem lies within your algorithm. You should first decide on an algorithm, then go to the coding. If I wanted to do what you are asking I would sort the array first, either in ascending or descending order. There are many sorting algorithms. However, I think what you are looking at is a subset sum problem which could be solved by a recursive binary tree traversal algorithm. I won't give you the code, but it would do the trick if you have time to research it.
int getnum50()
{
Random rand = new Random();
return (1+rand.nextInt(50));
}
You are given a predefined function named getnum50() which returns an
integer which is one random number from 1-50.
You can call this function as many times as you want but beware
that this function is quite resource intensive.
You cannot use any other random generator. You can NOT change the
definition of getnum50().
Print numbers 1-100 in random order. (Not 100 random numbers)
Note:
i. Every number should be printed exactly once.
ii. There should be no pattern in the numbers listing. List should be
completely random i.e., all numbers have equal probability
appearing at any place.
iii. You may call getnum50() any number of time to get random number
from 1 to 50 but try to make the code optimised.
iv. You cannot use any other random generator function except
getnum50().
I wrote some code which was showing correct output.
import java.util.Random;
public class RandomInteger{
int number[]=new int[100];//To store numbers in random order
public RandomInteger(){
int n[]=new int[100];//array to store which random numbers are generated
int off[]={-1,0};//offset to add
System.out.println("Length of array number100 is:"+number.length);
System.out.println("Generating random numbers in the range 1-100:");
for(int n1=0;n1<number.length;n1++){
int rnd=off[(getnum50()-1)/50]+(getnum50()*2);
if(n[rnd-1] == 0){
n[rnd-1]=1;//to indicate which random number is generated
number[n1]=rnd;
System.out.println(number[n1]+" ");
}
}
}
//end of constructor
int getnum50(){
Random rand = new Random();
return (1+rand.nextInt(50));
}
public static void main(String args[]){
RandomInteger m= new RandomInteger();
}
//end of main()
}
//end of class
While it was accepted in that round, in the next round the interviewer tells me that getnum50() is a costly method and even in best case scenario I have to call it twice for every number generated. i.e. 200 times for 1-100. In worst case scenario it would be infinity and tens of thousand in average case. He asks me to optimize the code so as to significantly improve the average case.
I could not answer.So please give me proper answer for the question? How will I optimize my above code??
One stupid optimization would be be to just realize that since your randomized source is limited to 1-50, you might as well set TWO array positions, e.g.
rand = getnum50();
n[rand] = 1;
n[rand+50] = 1;
Now the array will be slightly "less" random, because every index n is going simply be 1/2 of whatever's at n+50, but at least you've cut ~half the build array construction time.
I think they want you to produce a shuffle algorithm.
In this, you start with an array of exactly 100 numbers ( 1 through 100 in order ), and then on each iteration you shuffle the numbers.
Do it enough times, and the original array is completely random.
The 50 is a red herring. Use two calls to random50, mod 10. Now you have two digits: tens and ones place. This gives you a random100() function.
The real killer is the generate-and-check approach. Instead, put the numbers 1-100 into an arraylist, and use your random100 to REMOVE a random index. Now your worst case scenario has 2n calls to random50. There's a few problems left to solve - overruns - but that's the approach I'd look at.
Your problem us that if you are toward the end of the list you will have to generate lots of random numbers to get a number in the couple of spots left. You could reduce a couple of ways one the fits into your current answer fairly will is as follows:
while(n[rnd-1] == 1)
{
rnd++;
rnd=end%101;
}
n[rnd-1]=1;//to indicate which random number is generated
number[n1]=rnd;
System.out.println(number[n1]+" ");
However if you assume that the getnum50 is more expensive than anything you can write you could reduce the number of getnum50 that you call while filling in the second half of the list. Each time you find a number you could reduce your search space by one so (using non primitives):
while(myArrayList.size()>1)
{
int rnd=0;
if(myArrayList.size()>50);
rnd=((getnum50()-1)/50)+((getnum50()*2)%myArrayList.size())+1;
else
rnd=getnum50()%myArrayList.size()+1;
System.out.println(rnd);
myArrayList.remove(rnd);
}
System.out.println(myArrayList.get(rnd);
myArrayList.remove(rnd);
In this example your best, average and worst are 149 getnum50 calls;
The reason you are calling the method getnum50() twice is because of this line:
int rnd = off[(getnum50()-1)/50] + (getnum50()*2);
which seems self-explanatory. And the reason your worst case scenario is so bad is because of this block:
if(n[rnd - 1] == 0){
n[rnd - 1] = 1; //to indicate which random number is generated
number[n1] = rnd;
System.out.println(number[n1] + " ");
}
Depending on how bad your luck is, it could take a very long time to get each value. So, best case, you make your two getnum50() calls, which WILL happen the first time, but as you fill up your array, it becomes increasingly less likely. For 100 numbers, the last number will have a 1% chance of success on the first time, and every time it fails, you make another two calls to getnum50().
Sorry, this doesn't answer HOW to improve your efficiency, but it does explain why the efficiency concerns. Hope it helps.
This question already has answers here:
What is a plain English explanation of "Big O" notation?
(43 answers)
Closed 9 years ago.
I really can't figure out what "Big-O" is and how to use it in practice, so i hope someone could give me a simple explaining and maybe a little programming example in java.
I have the following questions:
What does these terms mean (as simple as possible) and how is it used in java:
BigO(1), BigO(n), BigO(n2) and BigO(log(n)) ?
How do you calculate a Big-O from an existing java code?
How do you use Big-O sorting
How do you use Big-O recursion
Hope someone will be able to help.
Thank you in advantage
Big O is used to give an idea of how fast an algorithm will scale as input size increases
O(1) means that as input size increases, the running time will not change
O(n) means that as input size doubles, the running time will double, more or less
O(n^2) means that as input size double, the running time will quadruple, more or less
O(f(n)) means that as input size doubles, the running time will increase to around f(2n)
Regarding Big-O, sorting, and recursion.
Big-O sorting isn't really an algorithm. You can however use Big O to tell you how fast your sorting algorithm is.
For computing Big-O of a recursive function, I would recommend using the Master Theorem.
Guidelines for determining Big O:
Usually, you need to determine what your input size is (like array length, or number of nodes in your linked list, etc)
Then ask yourself, what happens if your input size doubles? Or triples?
If you have a for loop that goes through each element:
//say array a has n elements
for (int i = 0; i < n; i++) {
// do stuff
a[i] = 3;
}
Then doubling n would make the loop run twice as long, so it would be O(n). Tripling n would triple the time it takes, so the code scales linearly with the input size.
If you have a 2D array and nested for loops:
// we say that each dimension of the array is upper bounded by n,
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
// do stuff
a[i][j] = 7;
}
}
As n doubles, the code will take 2^2 = 4 times as long. If input size triples, code will take 3^2 = 9 times as long. So Big O is O(n^2).
The Big-O notation is a notation made for showing computer algorithm performance, when the input is very large.
Three quick programming examples, in Java:
O(1):
for (int i=0; i<3; i++) {
System.out.println(i);
}
O(n):
int n = 1000000; /* Some arbitrary large number */
for (int i=0; i<n; i++) {
System.out.println(i);
}
O(n2):
int n = 1000000; /* Some arbitrary large number */
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
System.out.println(i * j);
}
}
Read more: http://en.wikipedia.org/wiki/Big_O_notation
Big O (it is the letter O - which is big- as opposed to the letter o which is small) gives an idea of how an algorithm scales when the input size (n) changes. The numbers are
If for instance n doubles from say 100 to 200 items,
an O(1) algorithm will take approximately the same time.
an O(n) algortihm will take double the time.
an O(n^2) algorithm will take four times the time (2^2)
an O(n^3) algorithm will take eight times the time (2^3)
And so on.
Note that log(n) can be understood as "the number of digits in n". This means that if you from n having two digits (like 99) to n having the double number of digits (four digits like 9999) the running time only doubles. This typically happens when you split the data in two piles and solve each separately and merge the solutions back, for instance in sorting.
Typically each loop over the input data multiply by n. so a single loop is O(n) but if you need to compare every element to every other element you get O(n^2), and so on. Note that the times are relative so a slow O(n) algorithm may be outperformed by a fast O(n^2) algorithm for small values of n.
Also note that O is worst case. So quicksort which generally run fast still is O(^2) because there is pathetic input data which cause it to compare every element to every other.
This is interesting because most algorithms are fast for small data sets, but you need to know how they work with input data perhaps thousands or millions of times larger where it is important if you have O(n^2) or O(n^3) or worse. The numbers are relative so it does not say anything bps out if a given algorithm is slow or fast, just how the worst case looks like when you double the input size.
Does anyone know if the Java's Random.nextInt() will ever repeat itself after sometime?
Concretely, is there such a number n such that the following two lists are equal?
List<Integer> a = new LinkedList<>();
List<Integer> b = new LinkedList<>();
for (int i = 0; i < n; ++i)
a.add(randObject.nextInt());
for (int i = n; i <= n * 2 ; ++i)
b.add(randObject.nextInt());
Is it guaranteed that every random object has a period?
(Note: Objects of different seeds don't have to have the same period)
Does anyone know if the Java's Random.nextInt() will ever repeat itself after sometime?
Yes it will. Since the generator has a finite amount of state, the generated sequence has a finite period.
Concretely, what is the number n such that the following two lists are equal?
That's not specified and depends on the Java implementation.
Is it guaranteed that there will always be such n for each Random object, regardless of what its seed is?
The period is finite. However, it's not necessarily the case that it's the same for every seed.
If you are really really really lucky enough, yes. Otherwise no.
But from the javadoc
The general contract of nextInt is that one int value is pseudorandomly generated and returned. All 2^32 possible int values are produced with (approximately) equal probability.