Concepts / Generating Random Floating-Point Numbers with random.random()

Generating Random Floating-Point Numbers with random.random()

random.randint(low, high) generates a random integer within an inclusive range, including both the low and high endpoints.

  • Programming

A Number That Changes Each Call

Random-number functions are useful when a program must make a choice that is not fixed in advance. Python's random.random() produces a pseudorandom floating-point number between 0.0 and 1.0. The value may look unpredictable, but each call produces the next value determined by the random module's internal state.

What do you think happens?

If a loop calls random.random() three times, will all three calls return the same value?

Reveal answer

Answer: No. Each call returns a new pseudorandom float and advances the random module's internal state.

The values appear unpredictable, but they belong to a deterministic sequence determined by the module's state. Without resetting the seed, another run can produce a different sequence.

The Output Interval

random.random() generates a pseudorandom float in the range [0.0, 1.0). The square bracket means that 0.0 is included. The parenthesis means that 1.0 is excluded.

A result can be exactly 0.0, but it will never be exactly 1.0. Other results lie between those boundaries. This half-open interval is useful when scaling the result: multiplying by 100 produces a float in [0.0, 100.0), while multiplying by 6 and converting to an integer can produce one of 0, 1, 2, 3, 4, or 5.

included interval continuesstops before0.0includedBetween 0.0 and 1.0possible float values1.0excluded
Where can random.random() place a result, and why is 0.0 possible while 1.0 is not?
python

The printed value is not fixed in advance. A valid run might display a value such as 0.37, but the exact result depends on the random module's internal state. The important check is that the result is at least 0.0 and less than 1.0.

Following the Internal State

Every call to random.random() is a separate event. The random module maintains internal state, and that state changes as calls are made. The next call uses the new state to determine the next pseudorandom float. The function does not need to remember the previous value as a variable; the module's internal state controls what comes next.

import random for step in range(3): value = random.random() print(value)

internal state advancesinternal state advancesIteration 1random.random() produces afloatIteration 2next float from updatedstateIteration 3next float from updatedstate
What value is produced on each loop iteration, and how does the pseudorandom sequence advance?

When Expected Output Diverges

When actual random output differs from a sequence you expected, the divergence occurs at the call to random.random() itself. The cause can be an unset seed, a different seed, or a different number of random calls made before the code under inspection runs. The surrounding loop may be working correctly; the pseudorandom value entering the loop's output is what differs.

Suppose you expected five values: [0.1, 0.2, 0.3, 0.4, 0.5]. Instead, the program produced [0.7, 0.8, 0.9, 0.6, 0.5]. The first divergence is the first call to random.random(): the actual first value is 0.7 rather than the expected 0.1. This does not by itself indicate a bug in the loop. To reproduce the earlier sequence, use the same seed that produced it.

first call differslater values follow another sequence0.1expected first value0.7actual first value0.2expected second value0.8actual second value
At which step does the actual pseudorandom sequence first differ from the expected sequence?

Integer Boundaries with randint()

random.randint(low, high) generates a random integer in an inclusive range. Both endpoints are possible. For random.randint(5, 10), the possible results are 5, 6, 7, 8, 9, and 10, and each has a 1-in-6 chance on any given call.

both endpoints includedstops before upper endpoint5included by randint(5, 10)5included by range(5, 10)10included by randint(5, 10)10excluded by range(5, 10)
Which endpoint values can each construct produce?
ExpressionPossible endpoint behavior
random.randint(5, 10)5 and 10 can both be returned
range(5, 10)5 is included and 10 is excluded

The upper boundary is handled differently by randint() and range().

python

The same inclusive-boundary idea can represent a real-world integer choice. For example, random.randint(1, 100) can select an integer from 1 through 100, including both 1 and 100. Use randint() when the endpoints belong to the requested set of possible integer results.

next possible integersends at included high endpoint1low endpoint included2 through 99intermediate integers100high endpoint included
How does a requested range map to the possible outputs of randint(1, 100)?

Mistakes in Random Calls

  • Forgetting to import the random module

    The name random is not available until the module has been imported.

    Fix: Write import random before calling random.randint() or random.random().

  • Treating randint() like range() and excluding the high value

    randint() includes both its low and high endpoints.

    Fix: Expect 1, 2, 3, 4, 5, or 6 from random.randint(1, 6).

  • Passing the boundaries in the wrong order

    The call does not express the intended low-to-high range.

    Fix: Place the lower integer first and the higher integer second.

  • Passing non-integer arguments to randint()

    randint() requires integer parameters.

    Fix: Pass integer values such as random.randint(1, 6).

  • Expecting random.random() to return exactly 1.0

    The upper boundary of random.random() is exclusive.

    Fix: Treat the result as a value in [0.0, 1.0), where 0.0 is included and 1.0 is not.

high endpoint changes from 5 to 6randint(1, 5)possible values 1 through 5randint(1, 6)possible values 1 through 6
What changes when the high argument is corrected to include the intended endpoint?

Practice and Recap

EASY

Write a short Python program that imports random, calls random.random() four times in a loop, and prints each result. Before running it, write down the range every printed value must satisfy. Then explain why your exact four values may differ if you run the program again.

Hints
  • Use for and range() to repeat the call four times.
  • Each result must be at least 0.0 and less than 1.0.
  • The internal state of the random module advances after each call.
  • Use the same seed before both runs if you need identical sequences.
  1. random.random() returns a pseudorandom float in [0.0, 1.0): 0.0 is possible, while 1.0 is excluded. Each call advances the random module's internal state and returns the next value in its pseudorandom sequence. Without resetting the seed, separate runs can produce different sequences; using the same seed makes sequences reproducible. When debugging, locate the first call whose result differs from your expectation. For integer choices, random.randint(low, high) includes both endpoints, unlike range(), which excludes its upper endpoint.

Key Takeaways

  • random.random() generates a pseudorandom float in the half-open interval [0.0, 1.0).
  • The lower boundary 0.0 is included, while the upper boundary 1.0 is excluded.
  • Repeated calls advance the random module's internal state and produce successive values from a pseudorandom sequence.
  • Setting the same seed before repeated runs makes the sequence reproducible.
  • random.randint(low, high) includes both integer endpoints, unlike range(), and requires integer arguments.