Theoretically optimal algorithm
Here is an improvement of the other answer I posted. The other answer has the advantage that it is easier to extend to the more general case of generating one discrete distribution from another. In fact, the other answer is a special case of the algorithm due to Han and Hoshi.
The algorithm I will describe here is based on Knuth and Yao (1976). In their paper, they also proved that this algorithm achieves the minimum possible expected number of coin flips.
To illustrate it, consider the Rejection sampling method described by other answers. As an example, suppose you want to generate one of 5 numbers uniformly [0, 4]. The next power of 2 is 8 so you flip the coin 3 times and generate a random number up to 8. If the number is 0 to 4 then you return it. Otherwise, you throw it out and generate another number up to 8 and try again until you succeed. But when you throw out the number, you just wasted some entropy. You can instead condition on the number you threw out to reduce the number of future coin flips you'll need in expectation. Concretely, once you generate the number [0, 7], if it is [0, 4], return. Otherwise, it's 5, 6, or 7, and you do something different in each case. If it's 5, flip the coin again and return either 0 or 1 based on the flip. If it's 6, flip the coin and return either 2 or 3. If it's 7, flip the coin; if it's heads, return 4, if it's tails start over.
The leftover entropy from our initial failed attempt gave us 3 cases (5, 6, or 7). If we just throw this out, we throw away log2(3) coin flips. We instead keep it, and combine it with the outcome of another flip to generate 6 possible cases (5H, 5T, 6H, 6T, 7H, 7T) which let's us immediately try again to generate a final answer with probability of success 5/6.
Here is the code:
# returns an int from [0, b)
def __gen(b):
rand_num = 0
num_choices = 1
while True:
num_choices *= 2
rand_num *= 2
if coin.flip():
rand_num += 1
if num_choices >= b:
if rand_num < b:
return rand_num
num_choices -= b
rand_num -= b
# returns an int from [a, b)
def gen(a, b):
return a + __gen(b - a)