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/
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).
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.
I have a simple educational kids game with 7 questions. One imageView and four buttons for each question, the user must match the correct answer(button) with what is shown in the image view. I want the images(questions) to be random every game but never repeat a question during a game until all 7 have been asked. I am only using 3 images as of now just to get it working.
Option 1
int[] res = {R.drawable.img1, R.drawable.img2, R.drawable.img3};
Method
private void randomImage() {
Random rand = new Random();
int rndInt = rand.nextInt(res .length);
imgView.setImageDrawable(getResources().getDrawable(res[rndInt]));
}
Option 2
private ArrayList<Integer> res1 = new ArrayList<Integer>();
res1.add(R.drawable.img1);
res1.add(R.drawable.img2);
res1.add(R.drawable.img3);
Method
private void randomImage1() {
Collections.shuffle(res1);
for(int i=0;i<res1.size();i++){
imgView.setImageResource(res1.get(i));
}
}
Both of these work for randomizing, but I am having a little trouble figuring out how to check if an image has already appeared and to correct it if it had.
In fact I'm not really quite sure where to start. Any help would be appreciated.
If you dont want to see repeated items from array then use shuffleArray() like this example and for a list use shuffle(list) like this example2
I'm attempting to generate a random four digit number with no repeating digits. I have a method to generate the number and two to check for length and repetition. It compiles and works as expected, however, occasionally, I will get a StackOverflowError while it is running. Here is the block of code where it seems to be having a problem with:
//ensures that generated pattern is four digits long
public void randomCheck(){
int patternNum = Integer.parseInt(pattern);
if(patternNum<1000){
numGen();
}
else{
repeatCheck();
}
}
//ensures that pattern is unique
public void repeatCheck(){
solutionNumber();
if((secondSolnDigit==firstSolnDigit)||(firstSolnDigit==thirdSolnDigit)||
(firstSolnDigit==fourthSolnDigit)||(secondSolnDigit==thirdSolnDigit)||
(secondSolnDigit==fourthSolnDigit)||(thirdSolnDigit==fourthSolnDigit)){
numGen();
}
else{
return pattern;
}
}
//generates random number
public void numGen();{
Random rand = new Random();
int randomNum = rand.nextInt(10000);
String patternString = Integer.toString(randomNum);
pattern = patternString;
randomCheck();
}
The stack overflow error happen when a there is too many method call in each other. It generally happen in recursive methods. Here it happens because you call numGen() from randomCheck() and repeatCheck() then numGen() call back randomCheck().
The solution here is to test in a while loop, remove you method randomCheck() and replace your code by:
//ensures that pattern is unique AND four digits long
public void repeatCheck(){
solutionNumber();
int patternNum = Integer.parseInt(pattern);
while((secondSolnDigit==firstSolnDigit)||(firstSolnDigit==thirdSolnDigit)||
(firstSolnDigit==fourthSolnDigit)||(secondSolnDigit==thirdSolnDigit)||
(secondSolnDigit==fourthSolnDigit)||(thirdSolnDigit==fourthSolnDigit) || patternNum<1000){
numGen();
}
return pattern;
}
//generates random number
public void numGen();{
Random rand = new Random();
int randomNum = rand.nextInt(10000);
String patternString = Integer.toString(randomNum);
pattern = patternString;
}
Moreover why do you cast your integer in string and then cast it back in integer, can't you just use the int as it is generated? and convert it after if you really need it as a string.
Hope this helped.
StackOverflowError is when you have to many method calls stacked on one another. There is a limit in Java to how many method calls can be stacked on one another.
You are calling randomCheck() from your numGen() method and calling numGen() from your randomCheck() method this appears to be the problem. Your code is probably chasing it's own tail. If numGen() is not called from randomCheck() then repeatCheck() is which also calls numGen().
It may work fine sometimes if it reaches the end of method calls before the stack runs out of space. But in some cases it is making more method calls than others adding more calls to the stack and eventually running out of space. That is why it works sometimes and not others.
You could try using a loop to accomplish the same thing. This way you won't have to worry about StackOverflowError.
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?