This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: float loses precision when passed to str()
Type: behavior Stage:
Components: Documentation Versions: Python 2.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: docs@python Nosy List: docs@python, mark.dickinson, pitrou, r.david.murray, serhiy.storchaka, sleepycal
Priority: low Keywords:

Created on 2012-12-04 19:03 by sleepycal, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (11)
msg176930 - (view) Author: Cal Leeming (sleepycal) Date: 2012-12-04 19:03
Hello,

Today I came up against a strange problem where collisions were being encountered after less than 1mil iterations when attempting to use random.random().

After much digging, the problem was because I was casting my float to a string, and this was automatically rounding it.

Some explanation is given [1], but it still leaves me with questions.

>>> import random
>>> random.random()
0.33885573194811902
>>> x = random.random()
>>> x
0.88022393777095409
>>> print x
0.880223937771
>>> str(x)
'0.880223937771'
>>> print str(x)
0.880223937771
>>> repr(x)
'0.88022393777095409'
>>> str(repr(x))
'0.88022393777095409'

After painstakingly searching through documentation (including the lengthy one about floating points arithmetic), I was unable to find any explanation behind why the float is automatically rounded if str() is called on it.

Although I doubt this behavior would ever be changed, it would be nice to update the documentation to reflect this. I'm thinking a note underneath random.random() explaining that you have to use repr() and not str() in order to maintain floating point precision.

Thoughts?

Cal

[1] http://stackoverflow.com/questions/3481289/converting-a-python-float-to-a-string-without-losing-precision
msg176933 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2012-12-04 19:17
http://docs.python.org/2/tutorial/floatingpoint.html
msg176934 - (view) Author: Cal Leeming (sleepycal) Date: 2012-12-04 19:21
As stated before, I have already read this document.

This ticket is specifically about making users aware of this behaviour in the form of a documentation update on the random.random() docs.

The link you provided does not exactly make this very clear.
msg176941 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2012-12-04 19:54
The `random` module docs are not the right place to add notes about general floating-point arithmetic behaviour.
msg176942 - (view) Author: Cal Leeming (sleepycal) Date: 2012-12-04 19:57
Normally I would concur, but casting random.random() to a string is commonly used, and people aren't going to read the entire floating point arithmetic page to figure this out. And even if they do, that page still doesn't make it entirely obvious at first read.

Hopefully if anyone else is caught out by this, then they will see this thread at least :X
msg176943 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012-12-04 20:00
In fact it has been changed.  In Python3 you get:

>>> x = 0.88022393777095409
>>> x
0.8802239377709541
>>> str(x)
'0.8802239377709541'

Even in 2.7 you would get the above repr, not the one you showed.  This is because 2.7 and 3.3 use the "shortest repr" described in the floating point document, but 2.7 still uses the old rounding as the default str representation (for backward compatibility reasons).

While you could still make an argument for updating the 2.7 docs, I'm not sure it is worth it.  If you (or anyone) want to propose a patch, I would suggest that instead of adding a note to the random docs, that a glossary entry be added for 'floating point' which mentions it as a 2.7 limitation, and a link to that glossary entry from the random docs.
msg176944 - (view) Author: Cal Leeming (sleepycal) Date: 2012-12-04 20:05
Many thanks for your lengthy response David.

Sorry, my initial bug report stated it was Python 2.7. The tests I performed were actually on Python 2.6.6.

I will take a look at how to contribute documentation updates, and once I've familiarized myself with it I'll submit a patch for review.

Thanks again
msg176945 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2012-12-04 20:06
It is notable that this behaviour isn't described anywhere that I can find in the library manual or the reference manual.  As David says, it applies only to 2.7;  in 3.2 and later, `str` and `repr` are identical.

> a glossary entry be added for 'floating point' which mentions it as a
> 2.7 limitation

That could work.  I *really* don't think it should be linked to from the random docs, though;  this has absolutely nothing to do with the random module, except that the random module happens to contain functions that can produce floats.  Many other modules do that, too.

Another option would be to add the information somewhere in

http://docs.python.org/2/library/stdtypes.html#numeric-types-int-float-long-complex
msg176949 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012-12-04 20:21
That's why I suggested a glossary entry.  The relevant function description *does* contain the phrase "floating point", so a glossary link there would be reasonably natural.
msg176952 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-12-04 20:29
I agree with Mark here. This isn't specific to random.random() and it's already covered elsewhere in the documentation.

Furthermore, I don't know why you're using str() on random.random(). There are better ways to get random strings, such as random.getrandbits() or os.urandom().

Recommend closing.
msg176953 - (view) Author: Cal Leeming (sleepycal) Date: 2012-12-04 20:33
Actually, you do have a good point, this should have been using random.getrandbits really.
History
Date User Action Args
2022-04-11 14:57:39adminsetgithub: 60813
2012-12-08 05:30:50terry.reedysetstatus: pending -> closed
2012-12-04 20:37:58sleepycalsetstatus: open -> pending
2012-12-04 20:33:40sleepycalsetstatus: pending -> open

messages: + msg176953
2012-12-04 20:29:05pitrousetstatus: open -> pending

nosy: + pitrou
messages: + msg176952

resolution: not a bug
2012-12-04 20:21:29r.david.murraysetmessages: + msg176949
2012-12-04 20:11:16mark.dickinsonsettitle: random.random() / float() loses precision when passed to str() -> float loses precision when passed to str()
2012-12-04 20:06:35mark.dickinsonsetmessages: + msg176945
2012-12-04 20:05:50sleepycalsetmessages: + msg176944
2012-12-04 20:00:29r.david.murraysetpriority: normal -> low

type: behavior
assignee: docs@python
components: + Documentation, - Interpreter Core

nosy: + r.david.murray, docs@python
messages: + msg176943
2012-12-04 19:57:57sleepycalsetmessages: + msg176942
2012-12-04 19:54:43mark.dickinsonsetnosy: + mark.dickinson
messages: + msg176941
2012-12-04 19:21:11sleepycalsetstatus: pending -> open
resolution: not a bug -> (no value)
messages: + msg176934
2012-12-04 19:17:54serhiy.storchakasetstatus: open -> pending

nosy: + serhiy.storchaka
messages: + msg176933

resolution: not a bug
2012-12-04 19:03:07sleepycalcreate