New function to add into the "random" module

Hi, my name is Terry, and I’d like to propose a small function that could be added into the Python’s “random” module. This function is for generating a random float/decimal number. I would like to know if there’s such function that does the same thing, if there is, please point out to me. If not, I would like to ask you developers to add this function into future Python versions. The function code is as follow: 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 😊

On Thu, Feb 2, 2017 at 7:01 AM, <himchanterry@gmail.com> wrote:
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.

On 2 February 2017 at 12:01, <himchanterry@gmail.com> wrote:
P.P.S.: The function is tested, it’s working 😊
First of all, thanks for your suggestion, and for taking the time to help improve Python. As noted, random.uniform probably does what you want, so we don't really need this function. But in case it's of interest to you, there's some additional considerations around proposed additions to the stdlib that we'd normally look at with a suggestion like this. If you find any other improvements you'd be interested in proposing, it might be helpful to you to be aware of them. The first thing that struck me was the performance of your approach. With multiple number<->string conversions it is likely to be extremely slow, making this function completely unsuitable for things like simulations, where the ability to generate many millions of results fast is critical. Python stdlib functions typically get used in a wide range of situations, and we need to make sure they are suitable for as large a range of applications as we can. Also, I'd be curious to know how you tested your function. Random number generators are notoriously difficult to get right, and you are here combining the results of multiple calls to the underlying PRNG. By doing so, you might (as far as I know, it's unlikely, but it's possible) have degraded the randomness of the result. Did your function pass the standard tests for randomness? Note: I don't know what those tests are, but I do know that such things exist, and I'd expect anything in the stdlib to have been validated by people who *do* know such things. Again, stdlib functions get used in a wide range of applications, and the authors typically rely on the Python developers to have "got the details right" on their behalf. Anyway, these are just a couple of thoughts for you. I hope they were of interest, and thanks again for contributing. Paul

On Thu, Feb 2, 2017 at 7:01 AM, <himchanterry@gmail.com> wrote:
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.

On 2 February 2017 at 12:01, <himchanterry@gmail.com> wrote:
P.P.S.: The function is tested, it’s working 😊
First of all, thanks for your suggestion, and for taking the time to help improve Python. As noted, random.uniform probably does what you want, so we don't really need this function. But in case it's of interest to you, there's some additional considerations around proposed additions to the stdlib that we'd normally look at with a suggestion like this. If you find any other improvements you'd be interested in proposing, it might be helpful to you to be aware of them. The first thing that struck me was the performance of your approach. With multiple number<->string conversions it is likely to be extremely slow, making this function completely unsuitable for things like simulations, where the ability to generate many millions of results fast is critical. Python stdlib functions typically get used in a wide range of situations, and we need to make sure they are suitable for as large a range of applications as we can. Also, I'd be curious to know how you tested your function. Random number generators are notoriously difficult to get right, and you are here combining the results of multiple calls to the underlying PRNG. By doing so, you might (as far as I know, it's unlikely, but it's possible) have degraded the randomness of the result. Did your function pass the standard tests for randomness? Note: I don't know what those tests are, but I do know that such things exist, and I'd expect anything in the stdlib to have been validated by people who *do* know such things. Again, stdlib functions get used in a wide range of applications, and the authors typically rely on the Python developers to have "got the details right" on their behalf. Anyway, these are just a couple of thoughts for you. I hope they were of interest, and thanks again for contributing. Paul
participants (4)
-
Daniel Moisset
-
Franklin? Lee
-
himchanterry@gmail.com
-
Paul Moore