2

我一直想知道 python 中的 random.randrange() 函数是如何在不是 2 的幂的范围内返回一个具有统一偏差的值(这很容易,因为 N 位是随机产生的)

提前致谢!

4

2 回答 2

4

快速查看源代码后,这是基本原理:

def randrange(start, stop, step)
    width = stop - start
    n = (width + step - 1) // step
    return start + step * int(random() * n)
于 2013-10-28T11:25:59.267 回答
3

你可以阅读源代码:

文件位置:

>>> import random
>>> random.__file__
'C:\\Python27\\lib\\random.pyc'

文件'C:\\Python27\\lib\\random.py'

def randrange(self, start, stop=None, step=1, int=int, default=None,
              maxwidth=1L<<BPF):
    """Choose a random item from range(start, stop[, step]).

    This fixes the problem with randint() which includes the
    endpoint; in Python this is usually not what you want.
    Do not supply the 'int', 'default', and 'maxwidth' arguments.
    """

    # This code is a bit messy to make it fast for the
    # common case while still doing adequate error checking.
    istart = int(start)
    if istart != start:
        raise ValueError, "non-integer arg 1 for randrange()"
    if stop is default:
        if istart > 0:
            if istart >= maxwidth:
                return self._randbelow(istart)
            return int(self.random() * istart)
        raise ValueError, "empty range for randrange()"

    # stop argument supplied.
    istop = int(stop)
    if istop != stop:
        raise ValueError, "non-integer stop for randrange()"
    width = istop - istart
    if step == 1 and width > 0:
        # Note that
        #     int(istart + self.random()*width)
        # instead would be incorrect.  For example, consider istart
        # = -2 and istop = 0.  Then the guts would be in
        # -2.0 to 0.0 exclusive on both ends (ignoring that random()
        # might return 0.0), and because int() truncates toward 0, the
        # final result would be -1 or 0 (instead of -2 or -1).
        #     istart + int(self.random()*width)
        # would also be incorrect, for a subtler reason:  the RHS
        # can return a long, and then randrange() would also return
        # a long, but we're supposed to return an int (for backward
        # compatibility).

        if width >= maxwidth:
            return int(istart + self._randbelow(width))
        return int(istart + int(self.random()*width))
    if step == 1:
        raise ValueError, "empty range for randrange() (%d,%d, %d)" % (istart, istop, width)

    # Non-unit step argument supplied.
    istep = int(step)
    if istep != step:
        raise ValueError, "non-integer step for randrange()"
    if istep > 0:
        n = (width + istep - 1) // istep
    elif istep < 0:
        n = (width + istep + 1) // istep
    else:
        raise ValueError, "zero step for randrange()"

    if n <= 0:
        raise ValueError, "empty range for randrange()"

    if n >= maxwidth:
        return istart + istep*self._randbelow(n)
    return istart + istep*int(self.random() * n)
于 2013-10-28T11:16:28.807 回答