Skip to content

Conversation

@Cai-Huayi
Copy link

@Cai-Huayi Cai-Huayi commented Nov 21, 2024

The documentation for random.uniform(a, b) currently states that the function returns a random floating point number N such that a <= N <= b.

However, due to the implementation (a + (b - a) * random()), the value b is not included in the possible return values. This PR updates the documentation to clarify that the function returns values in the half-open interval [a, b).

A note has also been added to explain this behavior for users who might expect the value b to be included.


📚 Documentation preview 📚: https://cpython-previews--127087.org.readthedocs.build/

@ghost
Copy link

ghost commented Nov 21, 2024

All commit authors signed the Contributor License Agreement.
CLA signed

@bedevere-app bedevere-app bot added docs Documentation in the Doc dir skip news awaiting review labels Nov 21, 2024
@Cai-Huayi
Copy link
Author

This PR updates the documentation for random.uniform and does not resolve any existing issue. Could you please add the skip issue label? Thank you!

@skirpichev
Copy link
Contributor

Sorry, but I don't think your addition is correct. Consider this example:

>>> import math
>>> import random
>>> a = 0.0
>>> b = math.nextafter(0, 1, steps=2)
>>> for _ in range(5):
...     print(random.uniform(a, b))
...     
1e-323
5e-324
1e-323
0.0
5e-324
>>> b
1e-323

@Cai-Huayi
Copy link
Author

Thank you for your thoughtful example and feedback!

After reviewing your example and performing additional tests, I believe that the observed behavior of random.uniform(a, b) returning a value equal to b can be explained by Python's floating-point precision limitations.

For example, even if two manually defined values differ beyond the effective precision of IEEE 754 double-precision floats, they may still be considered equal:

a = 0.11111111111111111111111110
b = 0.11111111111111111111111111
print(f"{a == b}")

@skirpichev
Copy link
Contributor

skirpichev commented Nov 21, 2024

can be explained by Python's floating-point precision limitations.

No. It's just how floating-point arithmetic works (assuming it's conforms to IEEE 754, i.e. operations are correctly rounded, etc).

Docstring says: "Get a random number in the range [a, b) or [a, b] depending on rounding." I think that on IEEE systems - only later variant is possible. Both docstring and sphinx docs looks correct for me.

even if two manually defined values differ beyond the effective precision of IEEE 754 double-precision floats, they may still be considered equal

No. In your example different decimal literals just define same binary floating-point number:

>>> (0.11111111111111111111111110).hex()
'0x1.c71c71c71c71cp-4'
>>> (0.11111111111111111111111111).hex()
'0x1.c71c71c71c71cp-4'

This can be even if decimal literal has 15-17 significant digits, e.g.:

>>> (0.1).hex()
'0x1.999999999999ap-4'
>>> (0.10000000000000001).hex()
'0x1.999999999999ap-4'

See https://docs.python.org/3/tutorial/floatingpoint.html#tut-fp-issues.

@Cai-Huayi
Copy link
Author

thanks for the explanation !

@skirpichev
Copy link
Contributor

Thanks for the pr, but I'm closing this. There is no issue to fix.

For a bit of history, documentation was improved in #50510. See also relevant discussion in mail list: https://mail.python.org/pipermail/python-list/2009-June/539862.html

Note, that implementation is just a + (b - a) * self.random(). And for random() it's true, that return value belongs to semi-open interval (1 not included). (Actually, on IEEE system it misses much more values, which never can be produced.)

Given this, it's not hard to provide an example (with catastrophic cancellation), where b can't be included to the output:

>>> a = -1e100
>>> b = 1.0
>>> a < b
True
>>> a + (b - a)*1.0
0.0
>>> _ == b
False
>>> import math
>>> a + (b - a)*math.nextafter(1.0, 0.0)
-1.942668892225729e+84

@skirpichev skirpichev closed this Nov 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting review docs Documentation in the Doc dir skip news

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

2 participants