I have to generate two random numbers for 52000 instances in an ArrayList, attack 1 and attack 2, where attack 1 must be greater than attack 2, so i have to put them in the list. This is my sample code:
do {
atk_p1 = (int) (Math.random() * (5000-500+1)+500);
atk_p2 = (int) (Math.random() * (5000-500+1)+500);
} while(atk_p1 <= atk_p2);
data.add(String.valueOf(atk_p1));
data.add(String.valueOf(atk_p2));
My problem is that the above code sometimes works (thus atk_p1 is greater than atk_p2) but other times not (thus atk_p2 is greater than atk_p1). I'm trying to solve the issue. Thank you for your help.
The above code is Java.
Another approach would be to generate a and b and then do simple comparison check to see if b is smaller than a.
If it is not you simply swap a and b.
I would just generate the second random number with the first one as it's upper limit:
atk_p1 = (int) (Math.random() * (5000-500+1)+501);
atk_p2 = (int) (Math.random() * (atk_p1)+500);
data.add(String.valueOf(atk_p1));
data.add(String.valueOf(atk_p2));
I solved in this way:
int atk_p1 = 0;
int atk_p2 = 0;
data.add(String.valueOf(atk_p1));
data.add(String.valueOf(atk_p2));
do{
atk_p1 = (int) (Math.random() * (5000-500+1)+500);
atk_p2 = (int) (Math.random() * (5000-500+1)+500);
}while(atk_p1 == atk_p2);
if(atk_p1 > atk_p2){
data.set(34, String.valueOf(atk_p1));
data.set(36, String.valueOf(atk_p2));
}else{
data.set(34, String.valueOf(atk_p2));
data.set(36, String.valueOf(atk_p1));
}
The problem was the arraylist.add() operation, it is not strict to the sequential order of the instructions. Using indexes to specify where to put the information worked great.
If you want to generate two random numbers, a and b, such that a < b, then
Generate a.
Generate b as a plus a random number greater than zero.
EDIT: This is wrong, and I admit it. See comments below. Mea culpa.
Related
I am trying to create a method to make some of the word's letters visible and other ones *. This is actually a simple word guessing game. I ask the user to choose whether they want to give an answer or request a letter. For example if the answer is "ball" and user decides to request a word, ball should turn into "*a**".
That is the method I have came up with:
public static void showALetter(String correctAnswer) {
int randomLetterIndex = (int) Math.random() % (correctAnswer.length());
for (int i = 0; i < correctAnswer.length(); i++) {
if (i == randomLetterIndex) {
System.out.print(correctAnswer.charAt(randomLetterIndex));
} else {
System.out.print("*");
}
}
}
It only shows the first letter of the correct answer at every single request. What should I do ?
Math.random() returns a double with a value between zero and one (technically [0.0, 1.0) written as a mathematical interval). This is not what you want, so you instead need to use the newer java.util.Random class:
Random random = new Random();
int randomLetterIndex = random.nextInt(correctAnswer.length());
The random.nextInt(int limit) method will return a value from zero (inclusive) to limit (exclusive) which is what you need here for your puproses.
If you're going to use random numbers over and over again, then create your Random instance as a static class member and have your methods refer to that, so that you only create the object once.
Math.random() returns a number from zero to one. So, your randomLetterIndex will always be zero. Use this instead.
(int) (Math.random() * correctAnswer.length())
This will give a random number between 0 and correctAnswer.length() - 1.
Math.random() returns a double higher or equal than 0 and less then 1, (int) Math.random() will always return 0.
Use
(int)(Math.random() * correctAnswer.length())
The modulo is useless here, this way you always hit inside the given string as (int) cast returns the floor value so the result will never be equal or higher than correctAnswer.length().
I have the following piece of code:
public class Main {
private static final Random rnd = new Random();
private static int getRand(int n) {
return (Math.abs(rnd.nextInt())%n);
}
public static void main(String[] args) {
int count=0, n = 2 * (Integer.MAX_VALUE/3);
for(int i=0; i<1000000; i++) {
if(getRand(n) < n/2) {
count++;
}
}
System.out.print(count);
}
}
This always gives me a number close to 666,666. Meaning two-thirds of the numbers generated are below the lower half of n. Not that this is obtained when n = 2/3 * Integer.MAX_VALUE. 4/7 is another fraction that gives me a similar spread (~5714285). However, I get an even spread if n = Integer.MAX_VALUE or if n = Integer.MAX_VALUE/2. How does this behavior differ with the fraction used. Can somebody throw some light on it.
PS: I got this problem from the book Effective Java by Joshua Bloch.
The problem is in the modulo (%) operator which results in an uneven distribution of numbers.
For example, imagine MAX_INT is 10, and n = 7, the mod operator will map the values 8, 9 and 10 to 1, 2 and 3, respectively. This will result that the numbers 1, 2 and 3 will have double the probability of all other numbers.
One way to solve this is by checking the output of rnd.nextInt() and try again while it's bigger than N.
You would get 50-50 if you kept only values of Math.abs(rnd.nextInt()) in the range of [0..2/3(Integer.MAX_VALUE)]. For the rest 1/3*Integer.MAX_VALUE numbers, due to modulo you will get a smaller number in the range of [0..1/3 Integer.MAX_VALUE].
All in all, numbers in the range of [0..1/3 Integer.MAX_VALUE] have double the chance to appear.
The Random class is designed to generate pseudo-random numbers. That means they are elements of a defined sequence that have an uniform distribution. If you don't know the sequence, they seem to be random.
Having said that, the problem is that you mess up the uniform distribution you get by using the modulus operator. On coding horror, there is a very nice article that explains this issue, although for a slightly different problem. Now, you can find a solution to your problem along with a proof here.
As observed above, getRand does not generate uniformly distributed random numbers over the range [0, n].
In general, suppose that n = a * Integer.MAX_VALUE / b, where a/b > 0.5
For ease of writing, let M = Integer.MAX_VALUE
The Probability Density Function (PDF) of getRand(n) is given by:
PDF(x) = 2/M for 0 < x < (b-a)M/b
= 1/M for (b-a)M/b < x < aM/b
n/2 corresponds to the mid-point of the range [0, aM/b] = aM/2b
Integrating the PDF over the 'first-half' range [0, n/2] we find that the probability (P) that getRand(n) is less than n/2 is given by:
P = a/b
Examples:
a=2, b=3. P = 2/3 = 2/3 = 0.66666... as computed by the questioner.
a=4, b=7. P = 4/7 = 0.5714... close to the questioner's computational result.
This question already has answers here:
Returning a random even number
(5 answers)
Closed 9 years ago.
How do you generate random numbers that go up by twos using Math.random()? For example, I'm trying to generate a random number from the set (2,4,6,8), how would you go it?
For this specific set you could use
(int)(Math.random() * 4) * 2 + 2
Here:
Math.random() generates a number that's greater or equal to 0.0 and strictly less than 1.0;
(int)(... * 4) gives one of 0, 1, 2, 3.
... * 2 + 2 gives one of 2, 4, 6, 8.
Okay, let's make a real general solution.
int lower = 2;
int upper = 8;
int step = 2;
int rand = (int)(Math.random() * (upper-lower+1));
int result = rand - rand%step + lower;
If you want to generate numbers within another set than the one you specified, just change the lower, upper and step variables to fit your set. It includes the upper bound if it's in the set.
The (almost) completely general approach isn't that hard.
static randInt(int first, int last, int step) {
int nsteps = (last+1-first) / step;
return first + step*(int)(nsteps*Math.random());
}
That returns a random integer from {start, start+step, start+2*step, ... } up to and including stop, or the last number before stop if stop is not part of the sequence.
int choice = randInt(2, 8, 2); /* random choice from {2, 4, 6, 8} */
...solved the sample question.
The (almost) part is that this doesn't handle integer overflow or sign errors in the arguments (step is zero, step<0 when first<last, or vice versa.)
int[] numSet={2,4,6,8};
Random myRand=new Random();
int myNum=numSet[myRand.nextInt(numSet.length)];
This creates an array of numbers, the random object, then picks a random element from the array of numbers. This does not assume that the numbers are in any sort of mathematical series. They could be 11, 25, 31, 876, 984368, 7432, 84562, for that matter.
Please don't tell me that there's a polynomial that generates that set from its y-values. I know.
Put those numbers in an array.
Generate a random number using the length of the array - 1 and use it as the index to randomly choose an array element.
You can also use the java.util.Random class like this:
int values[] = {2,4,6,8};
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(values.length);
int randomValue = values[randomInt]; /* Here's your random value from your set */
I would like to add a more general answer.
Assume the smallest integer in the set is A and the size of the set is S. A random integer from the set would be like this:
A + myRandom.nextInt(S) * 2
For your specific example in Java, it would be:
Random myRandom = new Random();
int randomNum = 2 + myRandom.nextInt(4) * 2;
Edit: This problem is solved. If you would like to help on another problem, please visit Java Biasing Random Numbers in a Triangular Array.
I'm doing a multiplication game, so I pick 2 numbers between 0 and 12 inclusive. If I do that like this:
int num1 = (int)(Math.random() * 13);
int num2 = (int)(Math.random() * 13);
the squares (0x0,1x1,2x2,etc) are picked half the time (because 1x2 is the same as 2x1). How can I make all combinations picked at the same frequency? There are 91 possible combinations (n(n+1)/2). If it helps, here is a 13 by 13 triangular array:
{{0},
{0,0},
{0,0,0},
{0,0,0,0},
{0,0,0,0,0},
{0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}};
I've tried picking the first number and giving the second number a 50% chance of being the first one. This did not work. I tried giving the second number a 1/91 chance of being the first one. This resulted in the smaller numbers being picked a far greater number of times (around 7/91 of the time; it is a smooth, curved increase). I thought about having a single random number: int roll = random.next(91) and then splitting it into 2 entries (like a coordinate (x,y)) but I could not figure out how to split it.
The int roll = random.next(91) strategy will work just fine. You get guaranteed, worry-free uniform distribution, and better performance to boot, since you're only picking 1 random number. You simply need to find a formula that identifies where one "row" ends and another begins. Look for the pattern:
0, 1, 3, 6, 10, 15, ...
There's a reason they're called "triangular numbers..."
Let's flesh this out a bit more. You want to actually find the nearest triangle number smaller than the random roll that you picked: that gets you to the right row, and the difference of that triangle number and roll gets you the offset into that row.
Given that the nth triangle number is given by n*(n+1)/2, how do you find the largest one smaller than roll? Given the small size of the array, a naïve implementation should be plenty fast:
int largestTriangleNumberSmallerThan(int x) {
int i = 0;
int last = 0;
while (true) {
int triangle = i*(i+1)/2;
if (triangle > x) return last;
last = triangle;
i++;
}
}
http://ideone.com/vzQEBz
Of course, that's boring and didn't take any thought. We can do better! We can do it in constant* time, regardless of how big the input is! Start by inverting the function (we only care about the positive root, of course):
n = (Math.sqrt(8y + 1) - 1)/2
Then truncate the decimal part, and run it back through:
int largestTriangleNumberSmallerThan(int x) {
int n = (int) (Math.sqrt(8*x + 1) - 1)/2;
return n*(n+1)/2;
}
http://ideone.com/1qBHfX
To put it all together:
int roll = random.nextInt(91);
int num1 = (int) (Math.sqrt(8*roll + 1) - 1)/2;
int num2 = roll - num1*(num1+1)/2;
That's it!
*assuming that the native StrictMath#sqrt(double) function is constant time - I'm actually not sure about this.
computerTotal = (int) Math.ceil(Math.random() * 21);
Can someone show me how to get 16 - 21 random number I keep getting errors when i try to implement the Math.floor function... As you can see i'm not very good at putting functions within functions.
Many Thanks!
If Java, use the Random Class.
Random r = new Random();
int myRand = 16+ r.nextInt(6); //16+[0-6) = 16-21
For creating random numbers between (including) min and max, you can do this:
Math.floor(Math.random() * (max - min + 1)) + min
Edit: The JAVA tag was added only after I suggested this; before it had no tags hinting at a specific language at all – so that there might be better/already implemented methods for this in language X is well possible. This is a very generic approach.