JAVA : generate integer numbers randomly with probabilities - java

How can I generate integer numbers randomly from (1 to 100) with probability for example 30% if the numbers range from (1 to 50), and with probability 70% if the numbers range from (50 to 100)?
int integer = new Random().nextInt(100) + 1;
// Probabilities
..... code here ....
How would I do that?

Here is a method getRandom() which returns a single random number meeting the criteria you specified. It actually uses a random number between 0 and 9 to determine which of the two ranges to use.
public int getRandom() {
Random random = new Random();
int val = random.nextInt(10);
if (val < 3) {
return random.nextInt(50) + 1; // random range 1 to 50
}
else {
return random.nextInt(51) + 50; // random range 50 to 100
}
}

Here's a general solution that will return one of any number of events, where you specify the relative weights of the events. The weights could be probabilities, but they don't have to; they don't have to add up to 1. For example, if you have three events, and you want the first one to have probability 20%, the second 30%, and the third 50%, you could call addEvent on each event with 2, 3, and 5 as the second parameter, or 20, 30, and 50, or 0.2, 0.3, and 0.5, or any other combination of numbers that has those ratios. For your case, you could make the generic parameter an interval and add two events with weights 3 and 7 (or 30 and 70, or whatever); then, when you call randomEvent, and it returns an interval with endpoints m and n inclusive, you then generate another random number in that interval:
value = m + random.nextInt(n - m + 1);
where random is your own instance of Random.
class RandomDistribution<T> {
private class Event {
public final T event;
public final double relativeWeight;
public Event(T event, double relativeWeight) {
this.event = event;
this.relativeWeight = relativeWeight;
}
}
private double totalWeight = 0D;
private ArrayList<Event> events = new ArrayList<>();
private Random generator = new Random();
public void addEvent(T event, double relativeWeight) {
events.add(new Event(event, relativeWeight));
totalWeight += relativeWeight;
}
public T randomEvent() {
double random = generator.nextDouble() * totalWeight;
for (Event event : events) {
random -= event.relativeWeight;
if (random < 0D) {
return event.event;
}
}
// It's possible to get here due to rounding errors
return events.get(events.size() - 1).event;
}
}

You can use MockNeat probabilities() method.
String s = mockNeat.probabilites(String.class)
.add(0.1, "A")
.add(0.2, "B")
.add(0.5, "C")
.add(0.2, "D")
.val();
The above example will generate "A" with 10% probability, B with 20% probability and so on.
Integer x = m.probabilites(Integer.class)
.add(0.2, m.ints().range(0, 100))
.add(0.5, m.ints().range(100, 200))
.add(0.3, m.ints().range(200, 300))
.val();
The above example will generate a number in the range [0, 100) with 20% probability, a number in the range [100, 200) with 50% probability and a number in the range [200, 300) with 30% probability.
Disclaimer: I am the author of the library, so I might be biased when I am recommending it.

Related

Generate random numbers with different probabilities within given ranges

Is there a simple algorithm that will print results of rolling a die such that the probability of getting 1,2,3,4,5 is 1/9 and the probability of getting a 6 is 3/9.
I would like to implement this in Java and intentionally only use Math.random(), if statements, for/ while loops.
As others suggested to make the sum of all events equal to 1, then number 9 will have a probability of 4/9 to be chosen.
Generate a random number between 1 and 9, inclusive on both ends. If the number be 1 to 5, you rolled that number, otherwise, you rolled 6. Note that there are 4 chances in this scheme to roll a 6, and 5 total chances to roll 1 through 5.
Random random = new Random();
int roll = random.nextInt(9) + 1; // create a random number
if (roll > 5) {
System.out.println("You rolled a 6");
}
else {
System.out.println("You rolled a " + roll);
}
To simulate more dice rolls you can add the above logic inside a for loop that runs for as many loops as you want.
Generating values for random variables with a certain distribution usually works like this:
You have a function which generates a random 0 <= q < 1,
You apply the quantile function and you obtain the value of your variable.
In your case you have a discrete random variable. You need an instance of Random:
private static final Random random = new Random();
the values assumed by the variable:
private static final double[] values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
Compute the cumulative distribution function (sum of probabilities of the values up to the specific value) for these values:
private static final double[] cdf = {1.0 / 9, 2.0 / 9, 3.0 / 9, 4.0 / 9, 5.0 / 9, 1.0};
You random generating function will return the last value for which the cdf is not greater than q:
public static double randomValue() {
double q = random.nextDouble();
for (int i = 0; i < values.length; i++) {
if (q > cdf[i]) continue;
return values[i];
}
throw new IllegalStateException();
}
Seems pretty straightforward:
// Pass in an instance of class Random
public static int gen(Random r) {
int i = r.nextInt(9); // uniformly generate 0,...,8 inclusive
if (i < 5) {
return i + 1; // returns 1,...,5 w/ probability 1/9
} else {
return 6; // returns 6 w/ probability 4/9
}
}
Warning, I no longer have a Java compiler on my machine, so I haven't compiled this. However, the algorithm is valid as confirmed in another language.

Generate a random integer with a specified number of digits Java [duplicate]

This question already has answers here:
How do I generate random integers within a specific range in Java?
(72 answers)
Closed 6 years ago.
I ran into this problem today and I'm sure there is an elegant solution I am not thinking of.
Let's say I want to generate a random integer(or long) in Java with a specified number of digits, where this number of digits can change.
I.e. pass in a number of digits into a method, and return a random number with the specified number of digits
Ex.) N = 3, generate a random number between 100-999; N = 4, generate a random number between 1000-9999
private long generateRandomNumber(int n){
/*Generate a random number with n number of digits*/
}
My attempt so far (this works, but it seems messy)
private long generateRandomNumber(int n){
String randomNumString = "";
Random r = new Random();
//Generate the first digit from 1-9
randomNumString += (r.nextInt(9) + 1);
//Generate the remaining digits between 0-9
for(int x = 1; x < n; x++){
randomNumString += r.nextInt(9);
}
//Parse and return
return Long.parseLong(randomNumString);
}
Is there a better/more efficient solution than this?
*There are lots of solutions for generating random numbers in a specified range, I was more curious on the best way to generate random numbers given a set number of digits, as well as making the solution robust enough to handle any number of digits.
I did not want to have to pass in a min and max, but rather just the number of digits needed
private long generateRandomNumber(int n) {
long min = (long) Math.pow(10, n - 1);
return ThreadLocalRandom.current().nextLong(min, min * 10);
}
nextLong produces random numbers between lower bound inclusive and upper bound exclusive so calling it with parameters (1_000, 10_000) for example results in numbers 1000 to 9999.
Old Random did not get those nice new features unfortunately. But there is basically no reason to continue to use it anyways.
public static int randomInt(int digits) {
int minimum = (int) Math.pow(10, digits - 1); // minimum value with 2 digits is 10 (10^1)
int maximum = (int) Math.pow(10, digits) - 1; // maximum value with 2 digits is 99 (10^2 - 1)
Random random = new Random();
return minimum + random.nextInt((maximum - minimum) + 1);
}
You can simply disregard the numbers that are not in the required range. That way your modified pseudo random number generator guarantees that it generates a number in the given range uniformly at random:
public class RandomOfDigits {
public static void main(String[] args) {
int nd = Integer.parseInt(args[0]);
int loIn = (int) Math.pow(10, nd-1);
int hiEx = (int) Math.pow(10, nd);
Random r = new Random();
int x;
do {
x = r.nextInt(hiEx);
} while (x < loIn);
System.out.println(x);
}
}
Here is the way I would naturally write a method like this:
private long generateRandomNumber(int n){
double tenToN = Math.pow(10, n),
tenToNMinus1 = Math.pow(10, n-1);
long randNum = (long) (Math.random() * (tenToN - tenToNMinus1) + tenToNMinus1);
return randNum;
}

Create numbers with boundaries based on a probability per number

I would like to create some numbers each time based on a probability.
Example:
Numbers from : 1-5
Number 1 has probability to be created by 0.55,
Number 2 has probability to be craeted by 0.25,
Number 3 has probability to be craeted by 0.10,
Number 4 has probability to be craeted by 0.05,
Number 5 has probability to be craeted by 0.05
In this case, it has to usually create number 1, and often number 2, sometimes number 3 and rarely number 4 or 5
So, the "method": create_the_numbers(int ending_number) should be like this pseado-code:
public int create_the_numbers(int ending_number){
return probability(Random.getInt(ending_number))
}
There is an question for the C# here: Probability Random Number Generator
The following method will do it:
private static int get() {
double d = Math.random();
if (d < 0.55) return 1; // 0.55
if (d < 0.80) return 2; // 0.25
if (d < 0.90) return 3; // 0.10
if (d < 0.95) return 4; // 0.05
return 5; // 0.05
}
Using Math.random() is simple, but has it limitations. Read the javadoc. Alternatively, use Random.
I believe you are asking how to weight probabilities. A simple method is as follows:
int getWeightedRandomInt(double... weights) {
final Random random = new Random();
double val = random.nextDouble();
for (int i = 0; i < weights.length; i++) {
if (val < weights[i])
return i;
}
throw new IllegalArgumentException("badly formed weights");
}
This is used by passing sorted cumulative weights. In your example:
getWeightedRandomInt(0.55, 0.8, 0.9, 0.95, 1.0);
If you are using Java 8:
Arrays.stream(weights).filter(w -> val < w)
.findFirst().orElseThrow(IllegalArgumentException::new);

Generate a random double in a range

I have two doubles like the following
double min = 100;
double max = 101;
and with a random generator, I need to create a double value between the range of min and max.
Random r = new Random();
r.nextDouble();
but there is nothing here where we can specify the range.
To generate a random value between rangeMin and rangeMax:
Random r = new Random();
double randomValue = rangeMin + (rangeMax - rangeMin) * r.nextDouble();
This question was asked before Java 7 release but now, there is another possible way using Java 7 (and above) API:
double random = ThreadLocalRandom.current().nextDouble(min, max);
nextDouble will return a pseudorandom double value between the minimum (inclusive) and the maximum (exclusive). The bounds are not necessarily int, and can be double.
Use this:
double start = 400;
double end = 402;
double random = new Random().nextDouble();
double result = start + (random * (end - start));
System.out.println(result);
EDIT:
new Random().nextDouble(): randomly generates a number between 0 and 1.
start: start number, to shift number "to the right"
end - start: interval. Random gives you from 0% to 100% of this number, because random gives you a number from 0 to 1.
EDIT 2:
Tks #daniel and #aaa bbb. My first answer was wrong.
import java.util.Random;
public class MyClass {
public static void main(String args[]) {
Double min = 0.0; // Set To Your Desired Min Value
Double max = 10.0; // Set To Your Desired Max Value
double x = (Math.random() * ((max - min) + 1)) + min; // This Will Create A Random Number Inbetween Your Min And Max.
double xrounded = Math.round(x * 100.0) / 100.0; // Creates Answer To The Nearest 100 th, You Can Modify This To Change How It Rounds.
System.out.println(xrounded); // This Will Now Print Out The Rounded, Random Number.
}
}
Hope, this might help the best : Random Number Generators in Java
Sharing a Complete Program:
import java.util.Random;
public class SecondSplitExample
{
public static void main(String []arguments)
{
int minValue = 20, maxValue=20000;
Random theRandom = new Random();
double theRandomValue = 0.0;
// Checking for a valid range-
if( Double.valueOf(maxValue - minValue).isInfinite() == false )
theRandomValue = minValue + (maxValue - minValue) * theRandom.nextDouble();
System.out.println("Double Random Number between ("+ minValue +","+ maxValue +") = "+ theRandomValue);
}
}
Here is the output of 3 runs:
Code>java SecondSplitExample
Double Random Number between (20,20000) = 2808.2426532469476
Code>java SecondSplitExample
Double Random Number between (20,20000) = 1929.557668284786
Code>java SecondSplitExample
Double Random Number between (20,20000) = 13254.575289900251
Learn More:
Top 4 ways to Generate Random Numbers In Java
Random:Docs
Random random = new Random();
double percent = 10.0; //10.0%
if (random.nextDouble() * 100D < percent) {
//do
}
The main idea of random is that it returns a pseudorandom value.
There is no such thing as fully random functions, hence, 2 Random instances using the same seed will return the same value in certain conditions.
It is a good practice to first view the function doc in order to understand it
(https://docs.oracle.com/javase/8/docs/api/java/util/Random.html)
Now that we understand that the returned value of the function nextDouble() is a pseudorandom value between 0.0 and 1.0 we can use it to our advantage.
For creating a random number between A and B givin' that the boundaries are valid (A>B) we need to:
1. find the range between A and B so we can know how to many "steps" we have.
2. use the random function to determine how many steps to take (because the returned value is between 0.0 and 1.0 you can think of it as "pick a random percentage of increase"
3. add the offset
After all of that, you can see that mob gave you the easiest and most common way to do so in my opinion
double randomValue = rangeMin + (rangeMax - rangeMin) * r.nextDouble();
double RandomValue = Offset + (Range)*(randomVal between 0.0-1.0)

How to generate a random BigInteger value in Java?

I need to generate arbitrarily large random integers in the range 0 (inclusive) to n (exclusive). My initial thought was to call nextDouble and multiply by n, but once n gets to be larger than 253, the results would no longer be uniformly distributed.
BigInteger has the following constructor available:
public BigInteger(int numBits, Random rnd)
Constructs a randomly generated BigInteger, uniformly distributed over the range 0 to (2numBits - 1), inclusive.
How can this be used to get a random value in the range 0 - n, where n is not a power of 2?
Use a loop:
BigInteger randomNumber;
do {
randomNumber = new BigInteger(upperLimit.bitLength(), randomSource);
} while (randomNumber.compareTo(upperLimit) >= 0);
on average, this will require less than two iterations, and the selection will be uniform.
Edit: If your RNG is expensive, you can limit the number of iterations the following way:
int nlen = upperLimit.bitLength();
BigInteger nm1 = upperLimit.subtract(BigInteger.ONE);
BigInteger randomNumber, temp;
do {
temp = new BigInteger(nlen + 100, randomSource);
randomNumber = temp.mod(upperLimit);
} while (s.subtract(randomNumber).add(nm1).bitLength() >= nlen + 100);
// result is in 'randomNumber'
With this version, it is highly improbable that the loop is taken more than once (less than one chance in 2^100, i.e. much less than the probability that the host machine spontaneously catches fire in the next following second). On the other hand, the mod() operation is computationally expensive, so this version is probably slower than the previous, unless the randomSource instance is exceptionally slow.
The following method uses the BigInteger(int numBits, Random rnd) constructor and rejects the result if it's bigger than the specified n.
public BigInteger nextRandomBigInteger(BigInteger n) {
Random rand = new Random();
BigInteger result = new BigInteger(n.bitLength(), rand);
while( result.compareTo(n) >= 0 ) {
result = new BigInteger(n.bitLength(), rand);
}
return result;
}
The drawback to this is that the constructor is called an unspecified number of times, but in the worst case (n is just slightly greater than a power of 2) the expected number of calls to the constructor should be only about 2 times.
The simplest approach (by quite a long way) would be to use the specified constructor to generate a random number with the right number of bits (floor(log2 n) + 1), and then throw it away if it's greater than n. In the worst possible case (e.g. a number in the range [0, 2n + 1) you'll throw away just under half the values you create, on average.
Why not constructing a random BigInteger, then building a BigDecimal from it ?
There is a constructor in BigDecimal : public BigDecimal(BigInteger unscaledVal, int scale) that seems relevant here, no ? Give it a random BigInteger and a random scale int, and you'll have a random BigDecimal. No ?
Here is how I do it in a class called Generic_BigInteger available via:
Andy Turner's Generic Source Code Web Page
/**
* There are methods to get large random numbers. Indeed, there is a
* constructor for BigDecimal that allows for this, but only for uniform
* distributions over a binary power range.
* #param a_Random
* #param upperLimit
* #return a random integer as a BigInteger between 0 and upperLimit
* inclusive
*/
public static BigInteger getRandom(
Generic_Number a_Generic_Number,
BigInteger upperLimit) {
// Special cases
if (upperLimit.compareTo(BigInteger.ZERO) == 0) {
return BigInteger.ZERO;
}
String upperLimit_String = upperLimit.toString();
int upperLimitStringLength = upperLimit_String.length();
Random[] random = a_Generic_Number.get_RandomArrayMinLength(
upperLimitStringLength);
if (upperLimit.compareTo(BigInteger.ONE) == 0) {
if (random[0].nextBoolean()) {
return BigInteger.ONE;
} else {
return BigInteger.ZERO;
}
}
int startIndex = 0;
int endIndex = 1;
String result_String = "";
int digit;
int upperLimitDigit;
int i;
// Take care not to assign any digit that will result in a number larger
// upperLimit
for (i = 0; i < upperLimitStringLength; i ++){
upperLimitDigit = new Integer(
upperLimit_String.substring(startIndex,endIndex));
startIndex ++;
endIndex ++;
digit = random[i].nextInt(upperLimitDigit + 1);
if (digit != upperLimitDigit){
break;
}
result_String += digit;
}
// Once something smaller than upperLimit guaranteed, assign any digit
// between zero and nine inclusive
for (i = i + 1; i < upperLimitStringLength; i ++) {
digit = random[i].nextInt(10);
result_String += digit;
}
// Tidy values starting with zero(s)
while (result_String.startsWith("0")) {
if (result_String.length() > 1) {
result_String = result_String.substring(1);
} else {
break;
}
}
BigInteger result = new BigInteger(result_String);
return result;
}
For those who are still asking this question and are looking for a way to generate arbitrarily large random BigIntegers within a positive integer range, this is what I came up with. This random generator works without trying bunch of numbers until one fits the range. Instead it will generate a random number directly that will fit the given range.
private static BigInteger RandomBigInteger(BigInteger rangeStart, BigInteger rangeEnd){
Random rand = new Random();
int scale = rangeEnd.toString().length();
String generated = "";
for(int i = 0; i < rangeEnd.toString().length(); i++){
generated += rand.nextInt(10);
}
BigDecimal inputRangeStart = new BigDecimal("0").setScale(scale, RoundingMode.FLOOR);
BigDecimal inputRangeEnd = new BigDecimal(String.format("%0" + (rangeEnd.toString().length()) + "d", 0).replace('0', '9')).setScale(scale, RoundingMode.FLOOR);
BigDecimal outputRangeStart = new BigDecimal(rangeStart).setScale(scale, RoundingMode.FLOOR);
BigDecimal outputRangeEnd = new BigDecimal(rangeEnd).add(new BigDecimal("1")).setScale(scale, RoundingMode.FLOOR); //Adds one to the output range to correct rounding
//Calculates: (generated - inputRangeStart) / (inputRangeEnd - inputRangeStart) * (outputRangeEnd - outputRangeStart) + outputRangeStart
BigDecimal bd1 = new BigDecimal(new BigInteger(generated)).setScale(scale, RoundingMode.FLOOR).subtract(inputRangeStart);
BigDecimal bd2 = inputRangeEnd.subtract(inputRangeStart);
BigDecimal bd3 = bd1.divide(bd2, RoundingMode.FLOOR);
BigDecimal bd4 = outputRangeEnd.subtract(outputRangeStart);
BigDecimal bd5 = bd3.multiply(bd4);
BigDecimal bd6 = bd5.add(outputRangeStart);
BigInteger returnInteger = bd6.setScale(0, RoundingMode.FLOOR).toBigInteger();
returnInteger = (returnInteger.compareTo(rangeEnd) > 0 ? rangeEnd : returnInteger); //Converts number to the end of output range if it's over it. This is to correct rounding.
return returnInteger;
}
How does it work?
First it generates a String with random numbers with the same length as the maximum range. For example: with given range of 10-1000 it will generate some number between 0000 and 9999 as a String.
Then it creates BigDecimals to represent the maximum possible value (9999 in previous example) and minimum value (0) and converts the range parameter BigIntegers to BigDecimals. Also in this step to the given range maximum value is added 1 in order to correct rounding errors in the next step.
Then using this formula the generated random number is mapped to the given range:
(generated - inputRangeStart) / (inputRangeEnd - inputRangeStart) * (outputRangeEnd - outputRangeStart) + outputRangeStart
After that it will do a last check whether or not the mapped number fits the given range and sets it to the given range maximum if it doesn't. This is done in order to correct rounding errors.
Just use modular reduction
new BigInteger(n.bitLength(), new SecureRandom()).mod(n)
Compile this F# code into a DLL and you can also reference it in your C# / VB.NET programs
type BigIntegerRandom() =
static let internalRandom = new Random()
/// Returns a BigInteger random number of the specified number of bytes.
static member RandomBigInteger(numBytes:int, rand:Random) =
let r = if rand=null then internalRandom else rand
let bytes : byte[] = Array.zeroCreate (numBytes+1)
r.NextBytes(bytes)
bytes.[numBytes] <- 0uy
bigint bytes
/// Returns a BigInteger random number from 0 (inclusive) to max (exclusive).
static member RandomBigInteger(max:bigint, rand:Random) =
let rec getNumBytesInRange num bytes = if max < num then bytes else getNumBytesInRange (num * 256I) bytes+1
let bytesNeeded = getNumBytesInRange 256I 1
BigIntegerRandom.RandomBigInteger(bytesNeeded, rand) % max
/// Returns a BigInteger random number from min (inclusive) to max (exclusive).
static member RandomBigInteger(min:bigint, max:bigint, rand:Random) =
BigIntegerRandom.RandomBigInteger(max - min, rand) + min

Categories