Python: why does `random.randint(a, b)` return a range inclusive of `b`?
boundary, integer, python, random
Solution
I tried to get to the bottom of this by examining some old sources. I suspected that `randint` was implemented before Python's long integer: meaning that if you wanted a random number that included `INT_MAX`, you would have needed to call `random.randrange(0, INT_MAX + 1)` which would have overflowed and resulted in arguments of `(0, 0)` or `(0, INT_MIN)` depending.
However, looking as far back as even the Python 1.5.2 sources, in `Lib/whrandom.py` we see:
#
# Get a random integer in the range [a, b] including both end points.
# (Deprecated; use randrange below.)
#
def randint(self, a, b):
return self.randrange(a, b+1)
`whrandom.randint` was continued to be deprecated in 2.0, 2.1, 2.2, and 2.3; but `random.randint` was marked as deprecated in 2.1, although no longer marked as deprecated in 2.2.
Also, `random.py` from version 2.1 is the first to note in `random.randint`'s docstring:
def randrange(self, start, stop=None, step=1, int=int, default=None):
"""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' and 'default' arguments.
"""
The only available source older than that is the 0.9.1 source, and as far as I can tell, `randint` was not implemented at that point.
Thus, I conclude that the reasoning for `randint` including the endpoint is known to only Guido himself at this point; given the docstring from Python 2.1, it sounds like the reason may have been a simple mistake.
Problem
It has always seemed strange to me that `random.randint(a, b)` would return an integer in the range `[a, b]`, instead of `[a, b-1]` like `range(...)`. Is there any reason for this apparent inconsistency?