I'm trying to distribute a system and I need to use nextGaussian() from the Random Java class. The only way I found to break the data dependency a unique seed creates was using multiple seeds, thus, creating multiple randoms.
Let's forget about the context of my problem, I just want to know how well normalized is using multiple Random instances compared to using only one instance. In other words... How random is this genNew compared to genSame?
The code:
public double[] genNew(int lim, long seed)
{
double[] rand = new double[lim];
for(int i = 0; i < lim; i++)
{
//A random for each iteration.
Random r = new Random(i*seed);
rand[i] = r.nextGaussian();
}
return rand;
}
public double[] genSame(int lim, long seed)
{
double[] rand = new double[lim];
//A random for all iterations
Random r = new Random(seed);
for(int i = 0; i < lim; i++)
rand[i] = r.nextGaussian();
return rand;
}
The results I get are very different when I apply both arrays to my code. I just can't explain why.
EDIT: I know this won't generate the same arrays, it is just that when using a big ammount of normalized randoms to calculate a number, both numbers should be close (because of the normalization), but they aren't.
I found a way to generate adecuate numbers and break the data dependency.
I don't understand why this factor works, but it does. I found it by chance and I've done almost a million millions tests on it and keeps working without failing.
If someone understands why this works, please tell:
Random r = new Random(seed * 43112609)
This number is a prime. That's the only clue I have, but still, I really can't understand why it works.
Related
Firstly I am not the greatest with Math, so please excuse any ignorance relating to that. I am trying to maintain probability based randomness across multiple executions but I am failing. I have this input in a JSONObject
{
"option1": 25,
"option2":25,
"option3" :10,
"option4" :40
}
This is my function that selects a value from the above JSONObject based on the probability assigned:
public static String selectRandomoptions(JSONObject options) {
String selectedOption = null;
if (options != null) {
int maxChance = 0;
for (String option : options.keySet()) {
maxChance += options.getInt(option);
}
if (maxChance < 100) {
maxChance = 100;
}
Random r = new Random();
Integer randomValue = r.nextInt(maxChance);
int chance = 0;
for (String option : options.keySet()) {
chance += options.getInt(option);
if (chance >= randomValue) {
selectedOption = options.toLowerCase();
break;
}
}
}
}
the function behaves within a reasonable error margin if I call it x amount of times in a single execution ( tested 100+ calls), the problem is that I am running this every hour to generates some sample data in an event-driven app to verify our analytics process/data but we need it to be somewhat predictable, at least within a reasonable margin?
Has anyone any idea how I might approach this? I would rather not have to persist anything but I am not opposed to it if it makes sense or reduces complexity/time.
The values returned by Random.nextInt() are uniformly distributed, so that shouldn't be a problem.
I you would like to make random results repeatable, then you may want to use Random with seed.
Rather than create a new Random() object each time you want a new random number, just create the Random object once per run, and use the Random.nextInt() object once per run.
Looking at the documentation of Random() constructor,
This constructor sets the seed of the random number generator to a
value very likely to be distinct from any other invocation of this
constructor.it only guarantees it to be different
that's a bit of a weaker contract than the number you get from nextInt().
If you want to get the same sequence of numbers on each run, use the Random(long seed) or the setSeed(long seed) method of the random object. Both these methods set the seed of the generator. If you used the same seed for each invocation it's guaranteed that you will get the same sequence of numbers from the generator.
Random.setSeed(long).
Hello everyone I have this command:
for (z = 0; z < utenti.length; z++) {
utenti[z] = rand.nextInt(1000) + 1;
}
After it's done generating random numbers between 1 and 1000 I want it to stop, the command is one of the functions in my program, but everytime i recall it the numbers generete randomly again. Is there a way to stop the random generation after the first time?
Is there a way to stop the random generation after the first time?
Yes. Don't execute that code after the first time. For example:
if (firstTime) {
for (z = 0; z < utenti.length; z++) {
utenti[z] = rand.nextInt(1000) + 1;
}
firstTime = false;
}
I you don't want to run the piece of code twice, then why are you calling it twice?
Since this piece of code is required to be executed just once, it probably is in the wrong place. It perhaps belongs in a constructor or something, depending on your program structure.
You might just do what Stephen C did in his answer, using a boolean to keep track of whether it's the first time or not. That might be the simplest option for you.
In addition to the other answer, also note that one the constructors of the Random class accepts a seed. If you keep the seed the same, the sequence of pseudo-random numbers will be the same. This saves you the memory usage of the utenti array, especially with large arrays.
private long seed;
private void determineSeed() {
long seed = new Random().nextLong();
}
And then use:
Random rand = new Random(this.seed);
for (int i = 0; i < utenti.length; i++) {
int number = rand.nextInt(1000) + 1);
// Don't save it to an array, do something with number
}
A drawback is that you cannot usage specific element of the sequence (for example, utenti[i]), you must use the random numbers in sequence.
My problem is that I need to produce a random number, which is fine I've done that part, but then I need to use that random number to loop.
So for example if the random number was 13, then loop a piece of code 13 times.
I've had a mess around and haven't managed to get anything working and haven't been able to find anything online to help me.
Basically what I'm trying to find out if this is even possible?
thanks guys.
This is a simple for loop:
for (int i = new Random().nextInt(); i > 0; i--) {
// do stuff
}
This is pretty basic Java. You have a number that you get once you randomize. Just use it in a while loop or a for loop.
int x = GetRandomNumber(); //You have stated you have already done this...
for(int i = 0; i < x; i++){
//Do stuff here
}
Here you go:
Random random = new Random();
int a = random.nextInt(); // As you said, you got this so far...
while (a > 0) { // if you need your random number for something, just copy its value to new variable and place it here instead of a
// some code
a--;
}
Let's say I want to generate 20 random numbers on a 8 by 6 grid.(8 columns, 6 rows) . Based on the answer from here:Creating random numbers with no duplicates, I wrote my code like this:
Random randomNumGenerator = new Random();
Set<Integer[][]> generated = new LinkedHashSet<Integer[][]>();
while (generated.size() < 20) {
int randomRows = randomNumGenerator.nextInt(6);
int randomColumns = randomNumGenerator.nextInt(8);
generated.add(new Integer[][]{{randomRows,randomColumns}});
}
In reality what happens is the Set see Integer[][]{{5,5}}; and Integer[][]{{5,5}};as NOT duplicate.Why? Even tho my purpose is to get 20 non-duplicate pair of numbers, this does not work. How do I fix this?
The Set checks for duplicates using the equals method (and also the hashCode method) of its inner type, but the Integer[][]'s equals method compares the memory addresses and not the contents.
Why do you use a Set of Integer[][] if you just want to store pairs?
Unfortunately, in Java there is no Pair class, but if you do not want to create your own, you can use the Map.Entry for that.
Random randomNumGenerator = new Random();
Set<Map.Entry<Integer, Integer>> generated = new LinkedHashSet<>();
while (generated.size() < 20) {
int randomRows = randomNumGenerator.nextInt(6);
int randomColumns = randomNumGenerator.nextInt(8);
generated.add(new AbstractMap.SimpleEntry<>(randomRows,randomColumns));
}
System.out.println(generated);
Array equals is == in Java, so an array is only equal to itself. Normaly you use Arrays.equals(array1, array2) to compare them by content, but in this case, arrays are simply the wrong choice. You can either create a bean, as rafalopez79 suggested of use an array of Collections (List in your case), as a List will compare the content on equals, see the documentation. Choice is pretty much yours, a bean would probably be a bit cleaner.
How about this code. I ran it through the debugger, it works nicely and yes, the contains() method checks the value of the Integer, not the reference. You can change the range of the random number as needed, I used 5 to facilitate testing. Yes I know it's not very robust, as written this will be an endless loop (because of the limited range of 5) but it's a simple example to make the point.
UPDATE: Actually this has a bug in that it won't check for uniqueness across all the rows, but that's easily fixed as well. I just re-read the original question and looking at the original code I'm not sure I know what you want exactly. If you just want a grid with 48 unique Intergers arranged 8 by 6 this will do it, but there are several ways to do this.
final int rows = 6;
final int cols = 8;
Random randomGenerator = new Random();
ArrayList[] grid = new ArrayList[rows];
for(int i=0; i<rows; i++)
{
grid[i] = new ArrayList<Integer>();
for(int j=0; j<cols; j++)
{
for(;;)
{
Integer newInt = new Integer(randomGenerator.nextInt(5));
if(!grid[i].contains(newInt))
{
grid[i].add(newInt);
break;
}
}
}
}
static int n = -1;
private static int repeatBuffer[] = new int[10];
static {
repeatBuffer[0] = 0;
//and more
repeatBuffer[9] = 9;
}
static public void randomize() {
do {
Random r = new Random();
randomNumber = r.nextInt(20);
} while (!uniqueInt(randomNumber));
Log.e(TAG, "" + randomNumber); //here I need have a unique int
}
private static Boolean uniqueInt(int random) {
for (int i = 0; i < 9; i++) {
if (random == repeatBuffer[i]) {
return false;
}
}
if (++n > 9)
n = 0;
repeatBuffer[n] = random;
return true;
}
Sometimes I'm getting same int twice, I'm wondering where is the problem? And is it even work? I spend quite a lot of time on this, and I give up. I think I need some minor tweaks in code :)
An easier way to get a random int is to create a List of integers List<Integer>, adding it with numbers that you would like to have. Then shuffling the List using Collections.shuffle(list);. Now start reading from the beginning of the list and you will get a unique random int each time.
Just make sure that each time you "read" a number from the list, either remove it from the list or increase the index for where you read.
That's the normal behavior of a random number generator, it's correct to generate repeated numbers as long as the number distribution remains uniform.
If you need a set of unique random numbers, you can generate them inside a loop and ask at every iteration if the newly generated number is present in the set of generated numbers. If not, add it, if yes, keep iterating - until the set has the desired size.
Er, a unique random between 1 and 20? What happens when it runs the 21st time?
Try making a List of the Integers between 1 and 20. Use Collections.shuffle() to shuffle the list. Then pop the first item off the front of the list and use that.