The general contract of nextFloat is that one float value, chosen (approximately) uniformly from the range 0.0f (inclusive) to 1.0f (exclusive)...
Just think how much trouble you would have saved yourself if you had read the documentation first. Never go round thinking you know what a method does, nor make any assumptions about its behaviour.Tan Quang wrote:. . . After that, I reread the document . . .
My first recommendation would be only to use floats when some other code, for example this constructor, forces you to.So, I want to know some solution for this case.
There are three kinds of actuaries: those who can count, and those who can't.
Campbell Ritchie wrote:I would suggest you won't be able to achieve an inclusive‑inclusive range reliably at all.
It simply said, “floating point” in the thread title, and I assumed the use of floats was to allow the loop to run in less time than the OP's whole lifetime. Yes, you could use doubles with a cast to a float, but that brings me out in spots even worse than plain simple floatsPaul Clapham wrote:. . . If the question had been about random double values . . . .
There are three kinds of actuaries: those who can count, and those who can't.
Paul Clapham wrote:In your desired distribution, what is the probability of 1.0 occurring?
Campbell Ritchie wrote:Just think how much trouble you would have saved yourself if you had read the documentation first. Never go round thinking you know what a method does, nor make any assumptions about its behaviour.
My first recommendation would be only to use floats when some other code, for example this constructor, forces you to.
I would suggest you won't be able to achieve an inclusive‑inclusive range reliably at all. You could try converting the floating‑point number to its corresponding integer value, adding 1, and converting it back to floating‑point. I think that will be a very error‑prone action, which will definitely not work for negative arguments. It will probably also fail for MAX_VALUE, ∞, and NaNs. Otherwise you could try looking at pseudorandom number algorithms and write your own random generator.
Piet Souris wrote:Well, chance of getting that max is practically 0, anyway.
But a way would be to use Math.nextAfter(max, max + 1) and use it like:
As Campbell writes: the use of doubles is much easier, although you could cast your doubles to floats.
Campbell Ritchie wrote:I wasn't familiar with Math#nextAfter() before; thank you, Piet. That looks a better option than my adding 1.
Campbell Ritchie wrote:It simply said, “floating point” in the thread title, and I assumed the use of floats was to allow the loop to run in less time than the OP's whole lifetime. Yes, you could use doubles with a cast to a float, but that brings me out in spots even worse than plain simple floats
Tan Quang wrote:
Paul Clapham wrote:In your desired distribution, what is the probability of 1.0 occurring?
Because (in fairness) this is a random number function, so the probability of creating its number is random, there is no priority for any results!
Paul Clapham wrote:Well, no, when you call the nextFloat() method it returns a random float number. That means that the probability of returning any float value is 1/N, where N is the number of different float values in [0, 1).
Now you want to select from [0, 1]. There are N+1 float values in that range. So the probability of returning 1 by your code should be 1/(N+1), and so should be the probability of returning any float value below 1.
So what I would do is this: Get a random long value. If it's less than 1/(N+1) then return 1, otherwise return the float value which nextFloat() returns.
I think that answers the question you asked. However I don't think you understand the question, instead you're going off on tangents about how Java represents floating-point numbers, which has little to say about randomness.
Paul Clapham wrote:...
Now you want to select from [0, 1]. There are N+1 float values in that range. So the probability of returning 1 by your code should be 1/(N+1), and so should be the probability of returning any float value below 1.
So what I would do is this: Get a random long value. If it's less than 1/(N+1) then return 1, otherwise return the float value which nextFloat() returns....
Tan Quang wrote:You mean it will be like this?
There are three kinds of actuaries: those who can count, and those who can't.
Paul Clapham wrote:That's not in any way related to what I posted, no.
Piet Souris wrote:Paul means this (I reckon. If not, he will correct me):
suppose there are four floats between 0 and 1: 0f, 0.25f. 0.50f and 0.75f.
Then N = 4, N + 1 = 5, and the procedure would be:
draw a double (I assume, Paul mentions a long), and if that double < 1/5 return 1, else return the float. Now, two problems with that:
1) how to calculate N? I tried two ways, but the outcomes differed a factor 1000. Perhaps looking at the specs of a float might give the correct answer.
2) and if we suppose that random.nextDouble() IS uniformly distributed, then what are the chances of getting 0f, .25f, .5f, .75f or 1f?
Mike Simmons wrote:It's hard to imagine an application where this function would do something useful, that's significantly different from the results you'd get from Random.nextFloat().
Paul Clapham wrote:it's often useful to write code which satisfies a boss's requirement even if said requirement is not actually of any use.
You are right. Seems I've never read that information!Paul Clapham wrote:But there is no mystery about how to calculate N, the API documentation for Random.nextFloat() tells us exactly what it is.
There are three kinds of actuaries: those who can count, and those who can't.
Paul Clapham wrote:That's not in any way related to what I posted, no.
Your values "RAND.nextFloat()" are in the range [0, 1). If you add 1 (as you did) then you get numbers in the range [1, 2). If you then take their reciprocals (as you did) then you get numbers in the range (0.5, 1].
So yeah, you'll get 1 as the result occasionally. With the same frequency as any other value in the range, actually. And no, you won't ever get a number greater than 1.
Piet Souris wrote:Paul means this (I reckon. If not, he will correct me):
suppose there are four floats between 0 and 1: 0f, 0.25f. 0.50f and 0.75f.
Then N = 4, N + 1 = 5, and the procedure would be:
draw a double (I assume, Paul mentions a long), and if that double < 1/5 return 1, else return the float. Now, two problems with that:
1) how to calculate N? I tried two ways, but the outcomes differed a factor 1000. Perhaps looking at the specs of a float might give the correct answer.
2) and if we suppose that random.nextDouble() IS uniformly distributed, then what are the chances of getting 0f, .25f, .5f, .75f or 1f?
Mike Simmons wrote:[composed mostly before seeing Piet's reply]
Paul Clapham wrote:That's not in any way related to what I posted, no.
It is related, in the sense that it's the result of incorrectly applying the formula you gave, in a way that will yield a very different probability distribution than what was desired.
Tan Quang: When Paul referred to "1/(1+N)", "N" meant the number of different possible values that you expect to be able to return. N is not, repeat NOT, the return value of Random.nextFloat(). That would be very different. The formula
1 / (RAND.nextFloat() + 1)
gives a value in the range (0.5,1] - and also importantly, it's no longer a uniform distribution. Taking the reciprocal is not a linear operation. If you look at how many value are in (0.5,0.6] and compare to how many are in (0.9,1], you will find the counts are consistently rather different.
Which doesn't really matter - the formula was not what Paul was saying, anyway.
I suggest the following, a different formulation which I believe is pretty close to what Paul was saying:
Now, I took my definition of N from the API for Random.nextFloat(). But, you could also legitimately try very different values - and you will find the chance of getting 1.0f exactly can vary quite a bit. Which goes back to Paul's original comment - you need to decide how many discrete values you want your distribution to be able to return. It's an arbitrary choice you get to make, which directly affects the results.
Also related is the fact that floating-point arithmetic is inherently imprecise, and if your code depends very much on whether a value is exactly equal to a given floating-point value (rather than close to or greater / less than that value) then your program is probably asking for trouble. It's hard to imagine an application where this function would do something useful, that's significantly different from the results you'd get from Random.nextFloat().
Mike Simmons wrote:Here's one more like Paul's original instructions - corrected a different way than Piet did:
I believe it's equivalent to my original code, as long as N=1<<24 to match what's used in nextFloat(). My original code allows smoothly changing N to any other value desired, as well. My second code with CORRECTION_RATIO is different, giving N possible values, rather than N + 1, spread evenly over [0,1].
Tan Quang wrote:So, I hope you understand what I'm saying!
Tan Quang wrote:Looking at your code is like if the random result is 0, I will receive 1. Therefore, I will never get 0... it's like (0, 1]?
Mike Simmons wrote:
Paul Clapham wrote:it's often useful to write code which satisfies a boss's requirement even if said requirement is not actually of any use.
Yeah, true. Also, there can indeed be real-world cases where you want the max value to occasionally appear, and people will notice and complain if that doesn't happen. But it really only would happen in cases where the outputs are sufficiently limited to a set of discrete values, enough so that 1/(N+1) is significantly different from 0. But in such cases, it's probably better to use nextInt() or nextLong() to control exactly what the values will be.
By the way, here's another version - similar idea, with a different value set (that may or may not matter):
Tan Quang wrote:The ratio about of 56 /1 billion with 0 and 64 /1 billion with 1.
Tan Quang wrote:All I want is random with all results, no priority for any results!
Mike Simmons wrote:Yeah, true. Also, there can indeed be real-world cases where you want the max value to occasionally appear, and people will notice and complain if that doesn't happen. But it really only would happen in cases where the outputs are sufficiently limited to a set of discrete values, enough so that 1/(N+1) is significantly different from 0. But in such cases, it's probably better to use nextInt() or nextLong() to control exactly what the values will be.
By the way, here's another version - similar idea, with a different value set (that may or may not matter):
Mike Simmons wrote:Yeah, that's just left over from the code for other methods. N can certainly be int in that code. Also, most of the other uses of long in my code can probably be int, including nextInt() rather than nextLong() - as long as you don't choose an N which is too big for int. I was experimenting with different values of N and using doubles for comparison, and I left those types in there.
I think that is poor style; most people do use .0 and use of the D suffix is likely to reduce the legibility of your code. You still need the f suffix for floats, but I only use floats if some other code forces me to.Tan Quang wrote:. . . // I usually don't write .0 . . .
You realise that 1.0000000596046448 contains 17 significant figures in decimal and is far beyond the precision of double arithmetic; had you declared it as a float, it would have degenerated to the equivalent of 1.00000001f. The imprecision inherent in floating‑point arithmetic means you won't get an even distribution of outputs by multiplying. I think you should have stuck with Piet's suggestion with Math#nextAfter().
return (float)(RAND.nextFloat() * CORRECTION_RATIO); // OR: RAND.nextFloat() * 1.0000000596046448
. . .
Does it have any harm other than a lack of aesthetics?
No. Neither nor. You should use Piet's suggestion.Tan Quang wrote:. . . Should I leave it in the form of expression (1) or the final result (2)? . . .
Consider Paul's rocket mass heater. |