Understanding Float Data Types
The call produces one floating-point value and assigns it to value.
A New Value at Each Call
The function random.random() generates a pseudorandom float. Each time the function is called, it returns a new value. The values appear unpredictable, but they come from a deterministic sequence controlled by the random module's internal state.
The call produces one floating-point value and assigns it to value. The exact number depends on the random module's current internal state, so a different run can produce a different result.
The Half-Open Output Range
random.random() returns 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.
The notation [0.0, 1.0) describes a half-open range: the lower endpoint belongs to the range, while the upper endpoint does not. Therefore, a result of exactly 0.0 is allowed, but a result of exactly 1.0 is not.
Reading the Range Notation
Determine whether each listed value could be returned by random.random(): 0.0, 0.42, and 1.0.
- 1Check 0.0
The opening square bracket includes 0.0, so this value is allowed.
- 2Check 0.42
This value lies between 0.0 and 1.0, so it is allowed.
- 3Check 1.0
The closing parenthesis excludes 1.0, so this value is not returned by
random.random().
0.0 and 0.42 are possible results; 1.0 is not.
Tracing a Repeated Call
A loop makes the behavior easier to observe because it calls random.random() once per iteration. The following generated example uses three iterations so that the sequence is easy to trace.
import random
for iteration in range(3):
value = random.random()
print(value)- 1At the first iteration,
random.random()returns the next value determined by the current internal state. - 2At the second iteration, another call returns the next value in the sequence.
- 3At the third iteration, a third call returns the next value in the sequence.
- 4The loop does not reuse one stored result; it calls the function again on every iteration.
- The random module is imported.
- The loop performs three iterations.
- Each iteration makes a new call to
random.random(). - The returned float is printed.
Three pseudorandom floats are printed, one per iteration. The exact values vary with the random module's internal state.The important state change is inside the random module. Each call advances the module's internal state, and that changed state determines the next value. The function itself does not remember the previous value; the random module maintains the state used to produce the next one.
What do you think happens?
A loop calls random.random() three times. How many pseudorandom floats will it print?
Reveal answer
Three
The function is called once during each of the three loop iterations, so the loop prints three values. Their exact numeric values are not fixed unless the random sequence is reproduced with the same seed and call history.
Reproducible and Variable Sequences
The sequence is pseudorandom rather than truly unpredictable in the programming sense. Each call returns the next value in a deterministic sequence based on the random module's internal state. However, different runs produce different sequences unless random.seed() is set before the calls.
| Setup | Observed behavior |
|---|---|
| No seed is set before the calls | Different runs produce different sequences. |
| The same seed is set before both runs | Both runs produce identical sequences. |
| The seed or number of earlier calls differs | The internal state differs, so the later sequence can differ. |
The seed and call history affect which part of the deterministic sequence is reached.
This example sets a seed before the loop. The source material does not specify the numeric output for seed 7, so the important result here is reproducibility: running the same setup again with the same seed produces the same sequence, provided the calls before and inside the loop are the same.
Finding the Divergence Point
When actual output differs from an expected sequence, inspect the calls to random.random() first. The divergence occurs at the call that generates the different value, not somewhere later in the printing or loop structure.
Comparing Expected and Actual Values
Suppose five generated values were expected to be [0.1, 0.2, 0.3, 0.4, 0.5], but the program produced [0.7, 0.8, 0.9, 0.6, 0.5]. Where did the sequences first diverge?
- 1Compare the first values
The expected first value is 0.1, while the actual first value is 0.7.
- 2Locate the first differing call
The first call to
random.random()produced a different value, so that is the first divergence point. - 3Interpret the cause
The random module's internal state was different. Possible reasons include not setting the seed, using a different seed, or making a different number of random calls before this sequence.
The divergence occurred at the first call to random.random(), not later in the output process.
Mistakes Beginners Make
Common mistake Treating 1.0 as a possible result.
What it looks likeAssuming that [0.0, 1.0) includes both endpoints.
Why it failsThe closing parenthesis excludes 1.0.
Do this insteadRemember that 0.0 is included and 1.0 is excluded.
Common mistake Expecting the same sequence every time without setting a seed.
What it looks likeRunning the same loop twice without random.seed().
Why it failsDifferent runs can begin with different internal states.
Do this insteadSet the same seed before the calls when reproducibility is required.
Common mistake Searching for the divergence after the random value has already been generated.
What it looks likeBlaming print() because an output differs from an expected random value.
Why it failsThe divergence begins at the
random.random()call that returned the unexpected value.Do this insteadCompare values in call order and inspect the seed and earlier random calls.
Common mistake Assuming the function repeats its previous result.
What it looks likeExpecting every loop iteration to print the same float.
Why it failsEach call returns the next value in the sequence determined by the changing internal state.
Do this insteadTreat every call as a separate event that advances the random module's state.
Practice the Trace
Consider a loop that calls random.random() once per iteration for four iterations. Describe how many floats are printed, the allowed range of every value, and what happens to the random module's internal state after each call. Then explain what you would check first if your actual first value differs from an expected first value.
Hints
- Count the number of loop iterations.
- Use the notation [0.0, 1.0) to identify the allowed values.
- The first divergence is located at the call that generated the first unexpected value.
- Check whether the seed and the number of earlier random calls match the expected setup.
Practice Answer
Answer the four-iteration trace question.
- 1Count outputs
There is one call in each of four iterations, so four floats are printed.
- 2Check the range
Every returned value is in [0.0, 1.0): 0.0 is possible, and 1.0 is excluded.
- 3Track state
Each call advances the random module's internal state, which determines the next value.
- 4Debug the mismatch
If the first actual value differs from the expected first value, the divergence occurs at the first
random.random()call. Check the seed and any earlier calls.
Four calls produce four pseudorandom floats, each call advances internal state, and the first unexpected value identifies the first divergence.
Key Takeaways
random.random()returns a pseudorandom float in the half-open range [0.0, 1.0).- The lower bound 0.0 is included, while the upper bound 1.0 is excluded.
- Each call returns the next value in a deterministic sequence based on the random module's internal state.
- A loop calling
random.random()once per iteration produces one new float per iteration and advances the internal state each time. - Use
random.seed()to reproduce a sequence, and identify the first unexpectedrandom.random()result as the divergence point when debugging.