开发者

Get a pseudorandom float number in a closed interval [a, b]

I would like to know the best way to get a pseudorandom float number in a closed interval using the Ruby rand kernel function (please not Random module).

To take an example I will use the closed interval [0.0, 7.7] (both 0.0 and 7.7 included in the interval), but any other float interval should be valid too.

For the interval [0.0, 7.7] the next solution is not valid:

rand * 7.7

Why?

If you call rand without arguments you will get a pseudorandom floating point number greater than or equal to 0.0 and less than 1.0. So what is the range of float numbers that the previous solutions can give to us?

rand will return a pseudorandom float number in the range [0.0, 0.9999999...]

0.0 * 7.7
=> 0.0          # Correct!

0.9999999 * 7.7
=> 7.69999923   # Incorrect!

The interval does not match开发者_JAVA百科 with [0.0, 7.7].

Does anyone know an elegant solution to this problem?

Thank you!


There's a Random class that can do what you want:

generator = Random.new # You need to instance it
generator.rand 0.0..7.7

(The documentation states the difference between 0.0..7.7 and 0.0...7.7 will be taken in account.)

In the future 1.9.3, you'll be able to pass a range to Kernel#rand and Random.rand (you can already do that in the preview version).


I would do something like this:

Fineness = 2**64
puts rand(Fineness+1)*7.7/Fineness

Whenever rand returns its maximum possible value, you will get Fineness*7.7/Fineness which turns out to equal 7.7 exactly (but I'm not totally sure this will always be the case, because floats are inexact).

As long as Fineness has more bits in it than a double on your computer, then I believe you will not notice any strangeness in the distribution of your results.


How about:

(rand/0.9999999999999999...)*7.7

Basically, normalize the random number by the largest possible random number. That way you will create the range [0..1].

However, I am unsure how to get the max number, which is less than 1.0 in ruby.


Why do you need this? I don't know of a case where there would be a need for this as a true single or double precision number. On the other hand, there are real cases where you might need numbers between 0.0 and 7.7 in increments of 0.1. In that case you could use well established techniques to go from 0 to 77 and then divide by 10.


Depending on the number of digits of precision you need you could use a round to even approach to snap to the boundaries of the interval to the edges. Hope this helps.

Here is the text from Wikipedia

Round half to evenA tie-breaking rule that is even less biased is round half to even, namely

If the fraction of y is 0.5, then q is the even integer nearest to y. Thus, for example, +23.5 becomes +24, +22.5 becomes +22, −22.5 becomes −22, and −23.5 becomes −24.

This method also treats positive and negative values symmetrically, and therefore is free of overall bias if the original numbers are positive or negative with equal probability. In addition, for most reasonable distributions of y values, the expected (average) value of the rounded numbers is essentially the same as that of the original numbers, even if the latter are all positive (or all negative). However, this rule will still introduce a positive bias for even numbers (including zero), and a negative bias for the odd ones.

This variant of the round-to-nearest method is also called unbiased rounding (ambiguously, and a bit abusively), convergent rounding, statistician's rounding, Dutch rounding, Gaussian rounding, or bankers' rounding. This is widely used in bookkeeping.

This is the default rounding mode used in IEEE 754 computing functions and operators.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜