[Python-ideas] New function to add into the "random" module

Franklin? Lee leewangzhong+python at gmail.com
Thu Feb 2 09:21:42 EST 2017


On Thu, Feb 2, 2017 at 7:01 AM, <himchanterry at gmail.com> wrote:

> from random import *
>
>
>
> def randfloat(x , y , maxfloatpt=None):
>
>     if x > y:
>
>         x , y = y , x
>
>     lenx = len(str(x))
>
>     leny = len(str(y))
>
>     intx = int(x)
>
>     inty = int(y)
>
>     bigger = max(lenx,leny)
>
>     if maxfloatpt == None:
>
>         if bigger == lenx:
>
>             intxlen = len(str(intx))
>
>             maxfloatpt = len(str(x)[intxlen:])
>
>         elif bigger == leny:
>
>             intylen = len(str(inty))
>
>             maxfloatpt = len(str(y)[intylen:])
>
>         else:
>
>             pass
>
>    else:
>
>         pass
>
>     num = randint(intx , inty)
>
>     num = str(num)
>
>     num = '%s.' % num
>
>     for i in range(0 , maxfloatpt):
>
>         flnum = randint(0 , 9)
>
>         str(flnum)
>
>         num = '%s%s' % (num , flnum)
>
>     return float(num)
>
>
>
> P.S.: If the indent has anything wrong, just correct me, thx!
>
>
>
> P.P.S.: The function is tested, it’s working 😊
>

It looks like this is generating a random float one digit at a time.
Instead, consider the following:

Say you have a function which generates a number between 0 and n. You want
to generate a number between floats x and y, as fairly as you can. So
stretch the range 0...n onto the range x...y, linearly. That means 0 goes
to x, n goes to y, things close to 0 go to things close to x, etc.

If x is 0, then it's simple:

    def stretch(num):
        return num / n * y

We just need to make x = 0 temporarily, shifting y down as well:

    def stretch(num):
        return (num / n * (y - x)) + x

Really, we care about the _length_ of the interval [x,y], relative to the
length of [0,n].

Since we want to reach as many numbers as possible in [x,y], we just need n
to be really big. The limit of n depends on how randint is implemented. I'm
not sure whether Python uses extra randoms in the case of long ints, but
let's say that 2^15 is both big enough for us and small enough for Python's
randints to be pretty random.

    import random
    def randfloat(x, y):
        r = random.randint(0, 2**15) #our random int
        length = y - x #length of the interval
        f = (r / 2**15 * length) + x
        return f

(Python 2 will do truncating division up there, so you'd need to make it do
floating point division with a __future__ import or a cast.)

To be responsible, we should probably up the limit to around 2^54 (which is
the limit of precision for the 64-bit floats used by Python), and we'd need
to learn about how random randint can be with large numbers, then generate
larger random numbers using smaller ones.

To be really responsible, we would not assume that floats are 64-bit.

(Fortunately, we don't have to be responsible, because Daniel pointed out
that this function exists in Python's random.)

The idea of linearly mapping one range to another is useful, so please
remember it. In fact, the stretch works even if x is bigger than y.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20170202/2efc8bc0/attachment.html>


More information about the Python-ideas mailing list