This question already has answers here:
math.random, only generating a 0?
(4 answers)
Closed 2 years ago.
I've been trying to create a class to roll dice for games, and my code for one aspect of it is:
public int[] yahtzeeRoll() {
int[] rolls1 = new int[6];
for (int i = 0; i < 6; i++) {
rolls1[i] = ((int) Math.random()*6+1);
}
return rolls1;
}
yet, when I call it in the main method, it only returns 1 for each of the values. Why is this? How can I fix my code so that it generates 6 different numbers when I print the array in the main method?
You are casting the double value returned by Math.random() to int before multiplying by 6, and since Math.random() returns a value < 1, casting it to int results in 0.
Change
rolls1[i] = ((int) Math.random()*6+1);
to
rolls1[i] = (int)(Math.random()*6)+1;
The type casting by appending (type) takes precedence over the * 6 bits afterwards. Therefore, the result from Math.random() is always casted into 0 before you multiply it by 6, which turns out to always be 0 as well.
This answer points to this site which explains it quite well.
Either (int) (Math.random() * 6) + 1 or (int) (Math.random() * 6 + 1) would work as you have intended.
Math.random returns a floating point number between 0 and 1 but you are truncating it down to 0 by using (int) type cast before it. Use parentheses around your expression and then prepend (int) to that if you do wish to use integer truncation.
Btw, I think same sequence should be generated at each run if you don't seed the pseudo-random engine, say with current time or something.
Let's look at the expression.
((int) Math.random()*6+1)
Now Math.random() returns a double that is >=0 and <1.
You then cast that result to an int which means it will always become 0.
If you use.
(int)(Math.random()*6+1)
You are taking the double between 0 and 1, multiplying it by 6 (giving 0 ... 6) adding 1 and then casting to an int. This looks more like what you are looking for.
Math.random() returns double value in range [0, 1) (greater than or equal to 0.0 and less than 1.0). Then you cast that double value to int, so it always results in 0. After that you add 1 to it, so the result always remains 1.
You should cast result of multiplication - Math.random() * 6 instead of casting Math.random() return value:
rolls1[i] = (int)(Math.random()*6)+1;
By the way, you should be aware of operators precedence in Java language. You can have a look here: operator precedence to see nice table that shows that casting has a higher priority than multiplication and addition - this is the reason, why (Math.random()*6) is put in parenthesis for casting (this way you avoid casting only Math.random())
PS. There is also a link to table of operator precedence in official Java tutorial, but it doesn't exactly fit to your problem as it doesn't contain operation of casting - this is the reason, why I provided another link firstly.
You can take a clue from the below output presentation which is self explanatory.
Code:
double random = Math.random();
System.out.println("Math.random()>>"+random);
System.out.println("Math.random()*6>>"+random*6);
System.out.println("(int)(Math.random()*6)>>"+(int)(random*6));
System.out.println("Math.random()*6+1>>"+random*6+1); //+1 here is treated as a string by java and will add at the end of the number
System.out.println("(Math.random()*6+1)>>"+(random*6+1)); //number random*6 will be incremented by 1 as enclosing () will treat them as numbers
System.out.println("(int)(Math.random()*6+1)>>"+(int)(random*6+1));
Output:
Math.random()>>0.6793602796545469
Math.random()*6>>4.076161677927281
(int)(Math.random()*6)>>4
Math.random()*6+1>>4.0761616779272811
(Math.random()*6+1)>>5.076161677927281
(int)(Math.random()*6+1)>>5
We can easily get random floating point numbers within a desired range [X,Y) (note that X is inclusive and Y is exclusive) with the function listed below since Math.random() (and most pseudorandom number generators, AFAIK) produce numbers in [0,1):
function randomInRange(min, max) {
return Math.random() * (max-min) + min;
}
// Notice that we can get "min" exactly but never "max".
How can we get a random number in a desired range inclusive to both bounds, i.e. [X,Y]?
I suppose we could "increment" our value from Math.random() (or equivalent) by "rolling" the bits of an IEE-754 floating point double precision to put the maximum possible value at 1.0 exactly but that seems like a pain to get right, especially in languages poorly suited for bit manipulation. Is there an easier way?
(As an aside, why do random number generators produce numbers in [0,1) instead of [0,1]?)
[Edit] Please note that I have no need for this and I am fully aware that the distinction is pedantic. Just being curious and hoping for some interesting answers. Feel free to vote to close if this question is inappropriate.
I believe there is much better decision but this one should work :)
function randomInRange(min, max) {
return Math.random() < 0.5 ? ((1-Math.random()) * (max-min) + min) : (Math.random() * (max-min) + min);
}
First off, there's a problem in your code: Try randomInRange(0,5e-324) or just enter Math.random()*5e-324 in your browser's JavaScript console.
Even without overflow/underflow/denorms, it's difficult to reason reliably about floating point ops. After a bit of digging, I can find a counterexample:
>>> a=1.0
>>> b=2**-54
>>> rand=a-2*b
>>> a
1.0
>>> b
5.551115123125783e-17
>>> rand
0.9999999999999999
>>> (a-b)*rand+b
1.0
It's easier to explain why this happens with a=253 and b=0.5: 253-1 is the next representable number down. The default rounding mode ("round to nearest even") rounds 253-0.5 up (because 253 is "even" [LSB = 0] and 253-1 is "odd" [LSB = 1]), so you subtract b and get 253, multiply to get 253-1, and add b to get 253 again.
To answer your second question: Because the underlying PRNG almost always generates a random number in the interval [0,2n-1], i.e. it generates random bits. It's very easy to pick a suitable n (the bits of precision in your floating point representation) and divide by 2n and get a predictable distribution. Note that there are some numbers in [0,1) that you will will never generate using this method (anything in (0,2-53) with IEEE doubles).
It also means that you can do a[Math.floor(Math.random()*a.length)] and not worry about overflow (homework: In IEEE binary floating point, prove that b < 1 implies a*b < a for positive integer a).
The other nice thing is that you can think of each random output x as representing an interval [x,x+2-53) (the not-so-nice thing is that the average value returned is slightly less than 0.5). If you return in [0,1], do you return the endpoints with the same probability as everything else, or should they only have half the probability because they only represent half the interval as everything else?
To answer the simpler question of returning a number in [0,1], the method below effectively generates an integer [0,2n] (by generating an integer in [0,2n+1-1] and throwing it away if it's too big) and dividing by 2n:
function randominclusive() {
// Generate a random "top bit". Is it set?
while (Math.random() >= 0.5) {
// Generate the rest of the random bits. Are they zero?
// If so, then we've generated 2^n, and dividing by 2^n gives us 1.
if (Math.random() == 0) { return 1.0; }
// If not, generate a new random number.
}
// If the top bits are not set, just divide by 2^n.
return Math.random();
}
The comments imply base 2, but I think the assumptions are thus:
0 and 1 should be returned equiprobably (i.e. the Math.random() doesn't make use of the closer spacing of floating point numbers near 0).
Math.random() >= 0.5 with probability 1/2 (should be true for even bases)
The underlying PRNG is good enough that we can do this.
Note that random numbers are always generated in pairs: the one in the while (a) is always followed by either the one in the if or the one at the end (b). It's fairly easy to verify that it's sensible by considering a PRNG that returns either 0 or 0.5:
a=0 b=0 : return 0
a=0 b=0.5: return 0.5
a=0.5 b=0 : return 1
a=0.5 b=0.5: loop
Problems:
The assumptions might not be true. In particular, a common PRNG is to take the top 32 bits of a 48-bit LCG (Firefox and Java do this). To generate a double, you take 53 bits from two consecutive outputs and divide by 253, but some outputs are impossible (you can't generate 253 outputs with 48 bits of state!). I suspect some of them never return 0 (assuming single-threaded access), but I don't feel like checking Java's implementation right now.
Math.random() is twice for every potential output as a consequence of needing to get the extra bit, but this places more constraints on the PRNG (requiring us to reason about four consecutive outputs of the above LCG).
Math.random() is called on average about four times per output. A bit slow.
It throws away results deterministically (assuming single-threaded access), so is pretty much guaranteed to reduce the output space.
My solution to this problem has always been to use the following in place of your upper bound.
Math.nextAfter(upperBound,upperBound+1)
or
upperBound + Double.MIN_VALUE
So your code would look like this:
double myRandomNum = Math.random() * Math.nextAfter(upperBound,upperBound+1) + lowerBound;
or
double myRandomNum = Math.random() * (upperBound + Double.MIN_VALUE) + lowerBound;
This simply increments your upper bound by the smallest double (Double.MIN_VALUE) so that your upper bound will be included as a possibility in the random calculation.
This is a good way to go about it because it does not skew the probabilities in favor of any one number.
The only case this wouldn't work is where your upper bound is equal to Double.MAX_VALUE
Just pick your half-open interval slightly bigger, so that your chosen closed interval is a subset. Then, keep generating the random variable until it lands in said closed interval.
Example: If you want something uniform in [3,8], then repeatedly regenerate a uniform random variable in [3,9) until it happens to land in [3,8].
function randomInRangeInclusive(min,max) {
var ret;
for (;;) {
ret = min + ( Math.random() * (max-min) * 1.1 );
if ( ret <= max ) { break; }
}
return ret;
}
Note: The amount of times you generate the half-open R.V. is random and potentially infinite, but you can make the expected number of calls otherwise as close to 1 as you like, and I don't think there exists a solution that doesn't potentially call infinitely many times.
Given the "extremely large" number of values between 0 and 1, does it really matter? The chances of actually hitting 1 are tiny, so it's very unlikely to make a significant difference to anything you're doing.
What would be a situation where you would NEED a floating point value to be inclusive of the upper bound? For integers I understand, but for a float, the difference between between inclusive and exclusive is what like 1.0e-32.
Think of it this way. If you imagine that floating-point numbers have arbitrary precision, the chances of getting exactly min are zero. So are the chances of getting max. I'll let you draw your own conclusion on that.
This 'problem' is equivalent to getting a random point on the real line between 0 and 1. There is no 'inclusive' and 'exclusive'.
The question is akin to asking, what is the floating point number right before 1.0? There is such a floating point number, but it is one in 2^24 (for an IEEE float) or one in 2^53 (for a double).
The difference is negligible in practice.
private static double random(double min, double max) {
final double r = Math.random();
return (r >= 0.5d ? 1.5d - r : r) * (max - min) + min;
}
Math.round() will help to include the bound value. If you have 0 <= value < 1 (1 is exclusive), then Math.round(value * 100) / 100 returns 0 <= value <= 1 (1 is inclusive). A note here is that the value now has only 2 digits in its decimal place. If you want 3 digits, try Math.round(value * 1000) / 1000 and so on. The following function has one more parameter, that is the number of digits in decimal place - I called as precision:
function randomInRange(min, max, precision) {
return Math.round(Math.random() * Math.pow(10, precision)) /
Math.pow(10, precision) * (max - min) + min;
}
How about this?
function randomInRange(min, max){
var n = Math.random() * (max - min + 0.1) + min;
return n > max ? randomInRange(min, max) : n;
}
If you get stack overflow on this I'll buy you a present.
--
EDIT: never mind about the present. I got wild with:
randomInRange(0, 0.0000000000000000001)
and got stack overflow.
I am fairly less experienced, So I am also looking for solutions as well.
This is my rough thought:
Random number generators produce numbers in [0,1) instead of [0,1],
Because [0,1) is an unit length that can be followed by [1,2) and so on without overlapping.
For random[x, y],
You can do this:
float randomInclusive(x, y){
float MIN = smallest_value_above_zero;
float result;
do{
result = random(x, (y + MIN));
} while(result > y);
return result;
}
Where all values in [x, y] has the same possibility to be picked, and you can reach y now.
Generating a "uniform" floating-point number in a range is non-trivial. For example, the common practice of multiplying or dividing a random integer by a constant, or by scaling a "uniform" floating-point number to the desired range, have the disadvantage that not all numbers a floating-point format can represent in the range can be covered this way, and may have subtle bias problems. These problems are discussed in detail in "Generating Random Floating-Point Numbers by Dividing Integers: a Case Study" by F. Goualard.
Just to show how non-trivial the problem is, the following pseudocode generates a random "uniform-behaving" floating-point number in the closed interval [lo, hi], where the number is of the form FPSign * FPSignificand * FPRADIX^FPExponent. The pseudocode below was reproduced from my section on floating-point number generation. Note that it works for any precision and any base (including binary and decimal) of floating-point numbers.
METHOD RNDRANGE(lo, hi)
losgn = FPSign(lo)
hisgn = FPSign(hi)
loexp = FPExponent(lo)
hiexp = FPExponent(hi)
losig = FPSignificand(lo)
hisig = FPSignificand(hi)
if lo > hi: return error
if losgn == 1 and hisgn == -1: return error
if losgn == -1 and hisgn == 1
// Straddles negative and positive ranges
// NOTE: Changes negative zero to positive
mabs = max(abs(lo),abs(hi))
while true
ret=RNDRANGE(0, mabs)
neg=RNDINT(1)
if neg==0: ret=-ret
if ret>=lo and ret<=hi: return ret
end
end
if lo == hi: return lo
if losgn == -1
// Negative range
return -RNDRANGE(abs(lo), abs(hi))
end
// Positive range
expdiff=hiexp-loexp
if loexp==hiexp
// Exponents are the same
// NOTE: Automatically handles
// subnormals
s=RNDINTRANGE(losig, hisig)
return s*1.0*pow(FPRADIX, loexp)
end
while true
ex=hiexp
while ex>MINEXP
v=RNDINTEXC(FPRADIX)
if v==0: ex=ex-1
else: break
end
s=0
if ex==MINEXP
// Has FPPRECISION or fewer digits
// and so can be normal or subnormal
s=RNDINTEXC(pow(FPRADIX,FPPRECISION))
else if FPRADIX != 2
// Has FPPRECISION digits
s=RNDINTEXCRANGE(
pow(FPRADIX,FPPRECISION-1),
pow(FPRADIX,FPPRECISION))
else
// Has FPPRECISION digits (bits), the highest
// of which is always 1 because it's the
// only nonzero bit
sm=pow(FPRADIX,FPPRECISION-1)
s=RNDINTEXC(sm)+sm
end
ret=s*1.0*pow(FPRADIX, ex)
if ret>=lo and ret<=hi: return ret
end
END METHOD
arr[i]=s+t-Math.abs(s-j)/2;
here is the line, s= 600 j = 631 t =60 , the answer should be 645.5 but it prints 645.0.
arr[] is double
Assuming that the types of s and j are int, you must be performing Java's integer division, which results in an int. s-j results in -31, and the Math.abs overload that takes an int is called, and 31 is returned. Integer division in Java means that 31/2 is 15 the int, not 15.5 the double.
Use the floating-point literal 2.0 to force floating-point division (or cast one of the / operands to a double):
arr[i]=s+t-Math.abs(s-j)/2.0;
Its because you are losing precision while dividing ints .Put a cast around the division
arr[i]= s+ t- (double) Math.abs(s-j)/2;
Try putting.
arr[i]=s+t-Math.abs(s-j)/2.0;
The trick here is that when you do divide by 2 it will give you an integer answer. So for your case( Math.abs(-31)/2 -> 15 instead of 15.5. and thus will truncate the .5
Therefore, by adding the 2.0 it will give you a double answer that is 15.5 and give you the desired solution
Probably s-j is an integer-valued (or long-valued) expression in your example, which makes Java select an integer/long valued Math.abs(...) call, returning an integer/long value. When dividing integer values, the decimal places are truncated. For example, 3 / 2 becomes 1, 15 / 2 becomes 7.
An easy way to make the expression evaluated with floating point math, is to divide by 2.0 instead:
arr[i] = s + t - Math.abs(s-j) / 2.0;
These other writing styles will work too:
arr[i] = s + t - Math.abs(s-j) / 2.;
arr[i] = s + t - Math.abs(s-j) / 2f;
arr[i] = s + t - Math.abs(s-j) / 2d;
You should set 2f in order to make a decimal division (now you are doing a integer division in Math.abs(s-j)/2)
Then your code should be
arr[i] = s + t - Math.abs(s-j)/2f;
I'm having an odd issue in which my math inside a for loop will not calculate at all until the very last iteration, at which point it comes out as 100%. The equation I'm using is a simple percentage equation to calculate how much of an array of files has been processed thus-far. My code is below:
for(int z=0;z<theFiles.size();z++) {
...
System.out.println(z); // Prints out the current iteration.
System.out.println(theFiles.size()); // Prints out the length of the array (35 in my test sample).
double test = Math.abs(z / theFiles.size() * 100); // Calculation to find the percentage of 100 the current iteration is (this is where things seem to break). Comes out as 0 if it's set as an int also.
System.out.println(test); // Prints out the percentage complete for this iteration.
}
Anyone have an idea why the variable "test" keeps coming out 0.0? I recall having a similar problem to this in JavaScript, but I'm not sure how to fix it in Java and forgot how I had done so in JS.
It is due to integer divison. Cast one of the value to double
Example:
double test = Math.abs((double)z / theFiles.size() * 100);
As per JLS 15.17.2
Integer division rounds toward 0. That is, the quotient produced for operands n and d that are integers after binary numeric promotion (§5.6.2) is an integer value q whose magnitude is as large as possible while satisfying |d · q| ≤ |n|. Moreover, q is positive when |n| ≥ |d| and n and d have the same sign, but q is negative when |n| ≥ |d| and n and d have opposite signs.
z / theFiles.size() will always be zero if z < theFiles.size() as both are int. To fix your issue do (z *100) /theFiles.size() or cast z to Double.
When I call Math.ceil(5.2) the return is the double 6.0. My natural inclination was to think that Math.ceil(double a) would return a long. From the documentation:
ceil(double a)
Returns the smallest (closest to negative infinity) double value
that is not less than the argument and is equal to a mathematical
integer.
But why return a double rather than a long when the result is an integer? I think understanding the reason behind it might help me understand Java a bit better. It also might help me figure out if I'll get myself into trouble by casting to a long, e.g. is
long b = (long)Math.ceil(a);
always what I think it should be? I fear there could be some boundary cases that are problematic.
The range of double is greater than that of long. For example:
double x = Long.MAX_VALUE;
x = x * 1000;
x = Math.ceil(x);
What would you expect the last line to do if Math.ceil returned long?
Note that at very large values (positive or negative) the numbers end up being distributed very sparsely - so the next integer greater than integer x won't be x + 1 if you see what I mean.
A double can be larger than Long.MAX_VALUE. If you call Math.ceil() on such a value you would expect to return the same value. However if it returned a long, the value would be incorrect.