How can I maintain probability across multiple executions in Java - java

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).

Related

Java Random.nextInt() repeating numbers only in a loop

I am trying to procedurally generate a world on a 2D grid. For the random numbers generation I am using a single global java.utils.Random Instance and a seed.
Like this:
public class Game {
private static final int SEED = 1111;
private static final Random RANDOM = new Random(SEED);
private static final int roomsCount = generateRandomNumberOfRooms();
}
Everything worked just fine untill I wrote this method:
public ArrayList<XYCoords> generateRandomCoordinates(){
ArrayList<XYCoords> coords = new ArrayList<>(roomsCount);
for(int i = 0; i < roomsCount; i+=1) {
XYCoords xy = new XYCoords(RANDOM.nextInt(WIDTH), RANDOM.nextInt(HEIGHT));
coords.add(xy);
}
return coords;
}
When I execute it I get the list of XYCoordinates but they all have the same two X and Y values, for example (11,20) or (12, 5)... etc. and all the rooms land on the same spot. It looks to me like the call to RANDOM.nextInt() in the for loop doesn't update the state of the instance RANDOM.
In all other functions that I call RANDOM.nextInt() it works fine. Some of them use for loops too. The problem is only with this function. It is used once directly in main() and not nested anywhere.
Does anyone have any sense of where the problem might be? I can upload more code if you need, but I think it is irrelevant.
Unwanted behaviour 1: each application run generates the same values in the same order. The reason is your RANDOM object which is instantiated with a seed. Try the following adaption: (Removing the seed, allowing Random to give you random values):
public class Game {
private static final Random RANDOM = new Random();
private static final int roomsCount = generateRandomNumberOfRooms();
}
If you need the seed for some reason, you could try to update the seed at each startup.
Clarification what the seed actually does:
(Note that the seed is also set from the constructor if you provide a seed)
setSeed
public void setSeed(long seed)
Sets the seed of this random
number generator using a single long seed. The general contract of
setSeed is that it alters the state of this random number generator
object so as to be in exactly the same state as if it had just been
created with the argument seed as a seed. The method setSeed is
implemented by class Random by atomically updating the seed to (seed ^
0x5DEECE66DL) & ((1L << 48) - 1) and clearing the haveNextNextGaussian
flag used by nextGaussian(). The implementation of setSeed by class
Random happens to use only 48 bits of the given seed. In general,
however, an overriding method may use all 64 bits of the long argument
as a seed value.
Parameters: seed - the initial seed
Unwanted behaviour 2: the cords are all the same after the loop. The XYCoords class probably declares the x and y as static variables. Solution: Remove the static declaration. As the values are static, the objects share these values as they are bound to the class. The last values which are set are the values you will get if you iterate over all of your XYCoords objects.
In general it is a mixture of both things which lead to the result that you get the same values all the time.

How to stop Random from generating everytime besides the first time?

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.

Confidence intervals in java, testing the random pick of an element in a list of objects

So I have this method that picks at random an object from a list of 2 objects. I would like to write a junit test (#Test) asserting based on a confidence level that somehow there's a 50% chance for each of the 2 objects to be picked.
The piece of code under test:
public MySepecialObj pickTheValue(List<MySepecialObj> objs, Random shufflingFactor) {
// this could probably be done in a more efficient way
// but my point is asserting on the 50% chance of the
// two objects inside the input list
Collections.shuffle(objs, shufflingFactor);
return objs.get(0);
}
In the test I would like to provide 2 mocks (firstMySepecialObjMock and secondMySepecialObjMock) as input objects of type MySepecialObj and new Random() as the input shuffling parameter, then assert that the firstMySepecialObjMock happens to be the choice 50% of the times and secondMySepecialObjMock happens to be the choice in the other 50% of the times.
Something like:
#Test
public void myTestShouldCheckTheConfidenceInterval() {
// using Mockito here
MySepecialObj firstMySepecialObjMock = mock(MySepecialObj.class);
MySepecialObj secondMySepecialObjMock = mock(MySepecialObj.class);
// using some helpers from Guava to build the input list
List<MySepecialObj> theListOfTwoElements = Lists.newArrayList(firstMySepecialObjMock, secondMySepecialObjMock);
// call the method (multiple times? how many?) like:
MySepecialObj chosenValue = pickTheValue(theListOfTwoElements, new Random());
// assert somehow on all the choices using a confidence level
// verifying that firstMySepecialObjMock was picked ~50% of the times
// and secondMySepecialObjMock was picked the other ~50% of the times
}
I am not sure about the statistics theory here, so maybe I should provide a different instance of Random with different parameters to its constructor?
I would also like to have a test where I could set the confidence level as a parameter (I guess usually is 95%, but it could be another value?).
What could be a pure java solution/setup of the test involving a confidence level parameter?
What could be an equivalent solution/setup of the test involving some helper library like the Apache Commons?
First of all this is the normal way to pick random elements from a List in Java. (nextInt(objs.size() produces random integers between 0 and objs.size()).
public MySepecialObj pickTheValue(List<MySepecialObj> objs, Random random) {
int i = random.nextInt(objs.size());
return objs.get(i);
}
You can read in Wikipedia about how many times you should perform an experiment with 2 possible outcomes for a given confidence level. E.g. for confidence level of 95% you get a confidence interval of 1.9599. You also need to provide a maximum error say 0.01. Then the number of times to perform the experiment:
double confidenceInterval = 1.9599;
double maxError = 0.01;
int numberOfPicks = (int) (Math.pow(confidenceInterval, 2)/(4*Math.pow(maxError, 2)));
which results in numberOfPicks = 9603. That's how many times you should call pickTheValue.
This would be how I recommend you perform the experiment multiple times (Note that random is being reused):
Random random = new Random();
double timesFirstWasPicked = 0;
double timesSecondWasPicked = 0;
for (int i = 0; i < numberOfPicks; ++i) {
MySepecialObj chosenValue = pickTheValue(theListOfTwoElements, random);
if (chosenValue == firstMySepecialObjMock) {
++timesFirstWasPicked;
} else {
++timesSecondWasPicked;
}
}
double probabilityFirst = timesFirstWasPicked / numberOfPicks;
double probabilitySecond = timesSecondWasPicked / numberOfPicks;
Then assert that probabilityFirst, probabilitySecond are no further than maxError from 0.5
I found a BinomialTest class in apache-commons-math but I don't see how it can help in your case. It can calculate the confidence level from the number of experiments. You want the reverse of that.

Class Random only Generates 0

Okay
I have The problem that i want to generate 64 numbers between 0 and 1 (that means 0 or 1)
the function i have currently is:
public static int randNr(int max) {
Random r = new Random();
int o = r.nextInt(max);
return o;
}
But it always returns 0.
Is there any way to make that it generates also a 1 ?
EDIT:
the function is located in a different java file than when i calling it!
Two issues:
1) nextInt(max); generates a number from 0 and up to but not including max. My guess is that you're passing 1 as max. Pass 2 and all will be well.
2) Creating a new generator object each time ruins the statistical properties of the generator. You should create one Random instance and (i) either pass into the function or (ii) have the instance stored as a member variable.
This function works fine. You are probably calling it with the wrong arguments. It should be:
randNr(2)
Why? Because it's using the Random#nextInt(max) method, which will return a random integer in the range [0, max-1] (including 0 and max-1).
Note: It's not recommended to create a new Random object each time you call the function. One solution would be to declare the Random object as an static member of the class:
public class Test
{
private static Random r = new Random();
// ...
}
Another solution would be to use the static method Math.random()1:
int o = (int) Math.round(Math.random());
1: Could someone confirm if this method is faster than the OP's one?

Testing a method producing a random result

I want to test this method:ArrayList<File> songs;
public void playRandomSong()
{
Random random = new Random();
int iNextSong = random.nextInt(songs.size());
File songToPlay = songs.get(iNextSong);
if (mediaPlayer != null && mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer = new MediaPlayerImpl(songToPlay, new WhenDone());
mediaPlayer.play();
currentSong = songToPlay;
}
I'm thinking in this way: Run the method multiple times and see if it returns one of the elements more than once. But how would I write that in code?
Random does not guarantee that it will not return the same value twice...
So you can not test "see if it returns one of the elements more than once"
If you need that you will have to implement a Set around the Random, but be aware of the Birthday paradox...
I think you have 2 options:
1 : You may try to seed your Random, so you can predict the sequence...
2 : Remove the Random and make use of the [Collections.shuffle][1] to shuffle you arrayList
With Option 1 you will have to change the signature of your method.
With Option 2 you will also play every song once.
Instead of creating a RNG in your method
public void playRandomSong() {
Random random = new Random();
...
}
you should pass the source of randomness in (this is called dependency injection)
public void playRandomSong(Random random) {
...
}
and then you can generate a Random instance with a known seed in your unit test to get repeatable but typical results.
public void testPlayRandomSong() {
Random random = new Random(0xd5021e90339050ab);
// Test that 1000 runs plays each song roughly the right number of times.
...
}
I see another problem in your code: if you want to play songs in random order you are doing that in wrong way. This algorithm should not repeat song until all songs in list are played. To achieve that there is an algorithm called Knuth shuffling. You can take it from Collections class: java.util.Collections#shuffle.
Here is an article on randomness testing that you might find useful:
http://beust.com/weblog/2012/02/20/various-ways-to-get-randomness-wrong/

Categories