I am generating random numbers and I am having a equal distribution issue. The first and last numbers in the range always have half the change of getting chosen because they don't have that possibility of being rounded to on both sides.
For example, if the user chooses a min of 1 and a max of 10, 1 and 10 will have a decreased chance of getting picked compared to the others.
Here is my current code:
double num = random.nextDouble() * (max - min) + min;
String finalNum = String.format("%." + precision + "f", num);
I know I could fix this by using a nextInt() instead but the problem is that I want to keep it a double because the user selects how many decimal places there will be.
Help is appreciated.
double min = 1.0;
double max = 10.0;
double rand = r.nextDouble();
//now we add 1 for the spread (we want the number to be from 0.5 to 10.5)
double range = max - min + 1;
rand *=range;
//now we shift by an offset of min-0.5;
rand += (min -0.5);
//now we round the number
int intRand = Math.round(rand);
you can use rand (double) for displaying your precision
and use intRand (int) for your integer random.
Related
I need to generate random real numbers in the range [-0.5, 0.5], both bounds inclusive.
I found various ways to generate similar ranges, like
-0.5 + Math.random()
But the upper bound is always exclusive, I need it inclusive as well. 0.5 must be inside the range.
One way to achieve this would be to create random int from -500 to 500 and then divide it by 1000.
int max = 500;
int min = -500;
int randomInt = rand.nextInt((max - min) + 1) + min;
float randomNum = randomInt / 1000.00f;
System.out.println(randomNum);
You can change the precision by adding and removing zeros from the integer boundaries and the divisor. (eG: create integers from -5 to +5 and divide by 10 for less precision)
A disadvantage of that solution is that it does not use the maximum precision provided by float/double data types.
I haven't seen any answer that uses bit-fiddling inside the IEEE-754 Double representation, so here's one.
Based on the observation that a rollover to a next binary exponent is the same as adding 1 to the binary representation (actually this is by design):
Double.longBitsToDouble(0x3ff0000000000000L) // 1.0
Double.longBitsToDouble(0x3ffFFFFFFFFFFFFFL) // 1.9999999999999998
Double.longBitsToDouble(0x4000000000000000L) // 2.0
I came up with this:
long l = ThreadLocalRandom.current().nextLong(0x0010000000000001L);
double r = Double.longBitsToDouble(l + 0x3ff0000000000000L) - 1.5;
This technique works only with ranges that span a binary number (1, 2, 4, 8, 0.5, 0.25, etc) but for those ranges this approach is possibly the most efficient and accurate. This example is tuned for a span of 1. For ranges that do not span a binary range, you can still use this technique to get a different span. Apply the technique to get a number in the range [0, 1] and scale the result to the desired span. This has negligible accuracy loss, and the resulting accuracy is actually identical to that of Random.nextDouble(double, double).
For other spans, execute this code to find the offset:
double span = 0.125;
if (!(span > 0.0) || (Double.doubleToLongBits(span) & 0x000FFFFFFFFFFFFFL) != 0)
throw new IllegalArgumentException("'span' is not a binary number: " + span);
if (span * 2 >= Double.MAX_VALUE)
throw new IllegalArgumentException("'span' is too large: " + span);
System.out.println("Offset: 0x" + Long.toHexString(Double.doubleToLongBits(span)));
When you plug this offset into the second line of the actual code, you get a value in the range [span, 2*span]. Subtract the span to get a value starting at 0.
You can adjust the upper bound by the minimal value (epsilon) larger than the maxium value you expect. To find the epsilon, start with any positive value and make it as small as it can get:
double min = -0.5;
double max = 0.5;
double epsilon = 1;
while (max + epsilon / 2 > max) {
epsilon /= 2;
}
Random random = ThreadLocalRandom.current();
DoubleStream randomDoubles = random.doubles(min, max + epsilon);
Edit: alternative suggested by #DodgyCodeException (results in same epsilon as above):
double min = -0.5;
double max = 0.5;
double maxPlusEpsilon = Double.longBitsToDouble(Double.doubleToLongBits(max) + 1L)
Random random = ThreadLocalRandom.current();
DoubleStream randomDoubles = random.doubles(min, maxPlusEpsilon);
Given HOW GOD SPIDERS answer, here is a ready to use function :
public static double randomFloat(double minInclusive, double maxInclusive, double precision) {
int max = (int)(maxInclusive/precision);
int min = (int)(minInclusive/precision);
Random rand = new Random();
int randomInt = rand.nextInt((max - min) + 1) + min;
double randomNum = randomInt * precision;
return randomNum;
}
then
System.out.print(randomFloat(-0.5, 0.5, 0.01));
#OH GOD SPIDERS' answer gave me an idea to develop it into an answer that gives greater precision. nextLong() gives a value between MIN_VALUE and MAX_VALUE with more than adequate precision when cast to double.
double randomNum = (rand.nextLong() / 2.0) / Long.MAX_VALUE;
Proof that bounds are inclusive:
assert (Long.MIN_VALUE/2.0)/Long.MAX_VALUE == -0.5;
assert (Long.MAX_VALUE/2.0)/Long.MAX_VALUE == 0.5;
Random.nextDouble gives a value in the range of [0, 1]. So to map that to a range of [-0.5, 0.5] you just need to subtract by 0.5.
You can use this code to get the desired output
double value = r.nextDouble() - 0.5;
So basically I need to generate a number between a min and max (could be negative as well) and there should be a possibility the number could end with a decimal 0.5.
So, for example, the numbers could be 5, 6, -8.5, 3.5.
I have this to generate my number (example):
rand.nextInt(20 + 1 + 10) - 10;
You could generate an integer with twice the range you want, and then halve it.
Something like this:
int min = -5;
int max = 15;
double r = min + 0.5 * rand.nextInt(2 * (max - min));
If you want max included in the random range, then:
double r = min + 0.5 * rand.nextInt(2 * (max + 1 - min));
Math.round((min + (rand.nextDouble() * Math.abs(max - min))) / 0.5) * 0.5;
should do the trick by creating a correct value in range [min, max] (including both min and max as possible values!)
I am not very familiar with how to alter the range of both Math.random or a new Random() to generate a double like this. I need to be able to generate a double between -10 and 25 cents (my program is dealing with money; hence why I said cents). And a separate instance is generating a random double between 90 and -75 cents. I saw this when I was searching for my answer:
double result = Math.random() * (upper - lower) + lower;
But when I implemented the idea into my code, the range didn't seem to work when using a range between a positive and a negative number...
I tested it with the upper limit of 0.25 and lower of -0.10, but noticed it printed 0.3567587946356543 at one instance of the test I did. So by this I concluded that I obviously didn't adjust the range correctly..
Please help :(
This is my first time using stackoverflow so please go easy on me, I will elaborate if anything I said didn't make sense..
This is my existing method using this code:
public double variation(double price){
//formula: (Math.random() * range) + min; where range = max - min
//80% of the time returns amount between -10 & 25 cents
if(Math.random() > 0.19){
return (Math.random() * 0.35) - 0.10;
}
//20% of the time returns amount between -75 & 90 cents
return (Math.random() * 1.65) - 0.75;
}
I know the method takes in a double price that it doesn't use; it's part of the teacher's requirements to take in a double price but to disregard its value. So ignore that please.
Now you have included all your code in the question, so my answer is changed to:
When it printed 0.3567587946356543 then it comes from the 20% part with range -.75 to 0.90 when the first Math.random() call in if(Math.random() > 0.19){ becomes false.
Old answer:
I think you forgot the minus at the lower value:
double upper = 0.25;
double lower = -0.10;
double result = Math.random() * (upper - lower) + lower;
To generate between -10 and 25, try doing :-
Random r = new Random();
int d = r.nextInt(35)+1;
d = d - 10;
double result = d/100.0;
or a one liner
double result = ((r.nextInt(35)+1)-10)/100.0;
Looks like your formula is actually correct:
double result = Math.random() * (upper - lower) + lower;
You can test it by putting the min and max possible random (which is zero, 1)
Random Value | Result
---------------------------
0 | -0.1 (lower)
1 | 0.25
0.5 | 0.075
0.01 | -0.0965
Working back to get the Random value for the result to be 0.356758795, the Math.random() must return 1.305025128 which is not gonna be the case. :)
Having said that, Apache Commons3 has this nifty method RandomUtils.nextDouble(double startInclusive, double endInclusive); that does it for you.
To get an output with a long decimal:
it's a little bit rough, but it gets the job done.
Random rand = new Random();// creates 'Random' method
int number = rand.nextInt(35)+1;// gets a random integer out of 35
double randDouble = rand.nextDouble();//gets a random double
double finalNumber = ((number + randDouble)-10)/100;//adds the integer and the double,
//subtracts ten, and divides by 100
System.out.println(finalNumber);// prints the number
Here are some examples of the output (copied and pasted exactly).
0.22748959958842008
0.1963085030978741
0.17300671109908058
-0.002656673961685705
-0.08854411636457332
0.03578255664449403
To get an output with a two digit output:
Random rand = new Random(); // creates 'Random' method
float x = rand.nextInt(35)+1; // gets a random integer(0 through 35)
float y = x - 10; // subtracts that number by ten(making the new range -10 through 25)
float z = y/100; // puts number in decimal form
NOTICE this line int number = rand.nextInt(35)+1(in the long decimal version). The reason you have to do +1 at the end is because Java understands 1 as 0. see chart below
JAVA |0 1 2 3 4 5
-------|-----------
HUMANS |1 2 3 4 5 6
I took 400.0 and - 400.0 for example.
double min = 400.0;
double max = 2 * min;
System.out.println(Math.random() * max - min);
And the output is
138.0921773815627
212.7567891431654
9.063135840057157
-256.8594518458244
-99.84573995806142
116.53331370219462
33.29613621235126
I want to make a method in java where I can input the maximum and minimum numbers and it will give me a random number, but with a higher chance of a bigger number than a smaller one. How would I do this?
There is lots of ways to do this depending on what you mean by higher. You can skew your distribution with a function.
int num = (int) (func(Math.random()) * (max - min)) + min;
Your func could be Math.sqrt or Math.pow(x, n) where n < 1 to favour higher numbers.
I would like it to be 10% more likely to have an answer over ten.
If this is your requirement, you actually have two distributions.
private static final Random rand = new Random();
public static int randBetween(int min, int max) {
return rand.nextInt(max - min + 1) + min;
}
int next = rand.nextInt(100) < 10 ? // a 10% chance
randBetween(10, max) : // random of at least 10
randBetween(min, max); // otherwise any number.
In java I have:
Random random = new Random();
double randomNum = random.nextDouble();
which creates a random number between 0 and 1. However I want a number between -1000 and 1000, how would I scale this?
Thanks
2 possibilities:
[less dense]: multiple your results by 2000, and subtract 1000
from the result. It won't be as 'dense' as possibility 2.
get a random int in range [-1000,999], and add a random double in
range [0,1].
Note that possibility 2 ensures better randomness and better 'density' of your numbers, at the cost of 2 random calls [which might be expansive, if it is an issue].
Um, maths?
double randomNum = (random.nextDouble()-0.5d) * 2000;
Random random = new Random();
double randomNum = (random.nextDouble() * 2000.0d) - 1000.0d;
Try this algorithm:
Generate a random value in the range 0 to 1.
multiply that value by 2000 (the size of the desired range).
subtract 1000 from the result of step 2 (move the value into the desired range).
This gives you a number on that range
double randomNum = (random.nextDouble() * 2000) -1000;
Here is a general function you could use to linearly rescale a number between zero and one (val01) to a different range (min..max):
public static double rescale(double val01, double min, double max) {
return val01 * (max - min) + min;
}
public static double doubleBetween(double start, double end) {
Random random = new Random();
// We need 64 bits because double have 53 bits precision, so int is too short
// We have now a value between 0 and Long.MAX_VALUE.
long value = -1L;
while (value < 0)
value = Math.abs(random.nextLong()); // Caution, Long.MIN_VALUE returns negative !
// Cast to double
double valueAsDouble = (double) value;
// Scale so that Long.MAX_VALUE is exactly 1 !
double diff = (end-start)/(double) Long.MAX_VALUE;
return start + valueAsDouble*diff;
}
This will give the correct interval including both ends with full double precision. doubles have a special -0.0 value (the negative zero) which will not be given by this routine.
Random random = new Random();
int randomNum = random.nextInt(2000) - 1000;
public static double randomInterval(double minValue,double maxValue){
Random random = new Random();
double r;
do {
r = random.nextDouble();
} while (r < minValue || r >= maxValue);
return r;
}
Example :
double a = randomInterval(-1000,1000) ;