[PySide] Strange behaviour of QLocale.toString()
Zak
pyside at m.allo.ws
Sun Apr 14 22:35:40 CEST 2013
My original email was correct, let me provide proof and explain further.
The proof is attached as a Python script, you can run it yourself. I ran
it on Mac OS X and also on Windows 7, and I ran it with both 32-bit and
64-bit versions of PySide and PyQt (and matching 32- or 64-bit versions
of the Python interpreter). The results were as follows:
1. PySide uses 32-bit floating points. It does not matter whether PySide
was compiled in 32-bit or 64-bit mode (x86 or x64).
2. PyQt uses 64-bit floating points. It does not matter whether PyQt was
compiled in 32-bit or 64-bit mode.
PyQt has better precision than PySide, because PyQt uses 64-bit floats
(just like Python itself). However, both PyQt and PySide are internally
representing the numbers as binary floating point numbers.
Let me address a few specific points:
Tim Doty wrote:
> For the PySide what is really happening is not a rounding
> error/precision as suggested, but printing an integer with floating
> point notation. When the floating point is converted to an integer
> it is rounded. To satisfy yourself that this is in fact happening
> change the number to be printed (e.g., 9999999.5 vs 9999999.4).
This is incorrect, what is happening is a rounding error. The number is
being rounded to fit in a 32 bit piece of memory. The counter-example
above is misleading because it uses bad values. Try the values 1.4 and
1.6 instead. These values are used in the attached Python script.
The number is not at any point represented as an integer (data
structure), it is always a floating point. Even if the number's value is
a whole number, it is represented as a floating point. For instance,
Python interprets '1.0' as a floating point literal. A mathematician
would say 1.0 is an integer, but computer science uses different
terminology. In computer science, in the language Python, '1' is an
integer and '1.0' is a floating point, and they are equal in numerical
value. They are represented differently in memory.
Alexey Vihorev wrote:
> Two considerations:
> 1. No rounding should take place in this case - the decimal precision
of the
> input and output is exactly the same.
> 2. In PyQt it *does* work correctly, so fundamental lows of computer
science
> are certainly not the reason.
In response to 1: That is just your opinion. You do not want rounding to
take place. The designers of Python and Qt had a different opinion. To
make things faster, they decided to round numbers so that they can fit
in either 32 or 64 bits of memory. If you want to use larger chunks of
memory and keep higher precision, then you should use the Python
standard library 'decimal', as I said before. Using decimal.Decimal
objects, you can set the precision yourself. Because you are not using
this library, Python, PySide, and PyQt are making a decision about how
to round the number. PySide chose 32 bits, PyQt chose 64 bits. The
Python language itself chose 64 bits, so PySide and PyQt cannot possibly
choose higher precision, the extra bits have already been thrown away.
In response to 2: You are using incorrect logic. As you can see from my
example, PyQt also suffers rounding errors, they just occur around 15 to
17 digits. You didn't use that many digits so you didn't see the
rounding error.
Zak Fallows
# File: num_print.py
from PyQt4.QtCore import QLocale as PyQtLocale
from PySide.QtCore import QLocale as PySideLocale
def pb(num):
"""pb stands for Print Both"""
print "Original: " + num
flt = eval(num)
print " PyQt: ",
print PyQtLocale().toString(flt, 'f', 6)
print " PySide: ",
print PySideLocale().toString(flt, 'f', 6)
print ''
test_list = [
'1.4',
'1.6',
'1000.4',
'1000.6',
'10**6 + .4',
'10**6 + .6',
'10**7 + .4',
'10**7 + .6',
'10**8 + .4',
'10**8 + .6',
'10**9 + .4',
'10**9 + .6',
'10**14 + .4',
'10**14 + .6',
'10**15 + .4',
'10**15 + .6',
'10**16 + .4',
'10**16 + .6',
'10**17 + .4',
'10**17 + .6',
]
for num in test_list:
pb(num)
"""
#======================== How to Check Version Numbers
========================#
PyQt:
PyQt4.QtCore.PYQT_VERSION_STR
PySide:
PySide.__version__
#=============================== Sample Output
================================#
Here is some sample output from running the program:
#---------------------------------- Mac OS X
----------------------------------#
Mac OS X 10.8.3
Python 2.7.3, 64-bit, from Python.org
PySide 1.1.1, 64-bit
PyQt 4.9.4, 64-bit
>>> import num_print
Original: 1.4
PyQt: 1.400000
PySide: 1.400000
Original: 1.6
PyQt: 1.600000
PySide: 1.600000
Original: 1000.4
PyQt: 1,000.400000
PySide: 1,000.400024
Original: 1000.6
PyQt: 1,000.600000
PySide: 1,000.599976
Original: 10**6 + .4
PyQt: 1,000,000.400000
PySide: 1,000,000.375000
Original: 10**6 + .6
PyQt: 1,000,000.600000
PySide: 1,000,000.625000
Original: 10**7 + .4
PyQt: 10,000,000.400000
PySide: 10,000,000.000000
Original: 10**7 + .6
PyQt: 10,000,000.600000
PySide: 10,000,001.000000
Original: 10**8 + .4
PyQt: 100,000,000.400000
PySide: 100,000,000.000000
Original: 10**8 + .6
PyQt: 100,000,000.600000
PySide: 100,000,000.000000
Original: 10**9 + .4
PyQt: 1,000,000,000.400000
PySide: 1,000,000,000.000000
Original: 10**9 + .6
PyQt: 1,000,000,000.600000
PySide: 1,000,000,000.000000
Original: 10**14 + .4
PyQt: 100,000,000,000,000.406250
PySide: 100,000,000,376,832.000000
Original: 10**14 + .6
PyQt: 100,000,000,000,000.593750
PySide: 100,000,000,376,832.000000
Original: 10**15 + .4
PyQt: 1,000,000,000,000,000.375000
PySide: 999,999,986,991,104.000000
Original: 10**15 + .6
PyQt: 1,000,000,000,000,000.625000
PySide: 999,999,986,991,104.000000
Original: 10**16 + .4
PyQt: 10,000,000,000,000,000.000000
PySide: 10,000,000,272,564,224.000000
Original: 10**16 + .6
PyQt: 10,000,000,000,000,000.000000
PySide: 10,000,000,272,564,224.000000
Original: 10**17 + .4
PyQt: 100,000,000,000,000,000.000000
PySide: 99,999,998,430,674,944.000000
Original: 10**17 + .6
PyQt: 100,000,000,000,000,000.000000
PySide: 99,999,998,430,674,944.000000
#--------------------------------- Windows 7
----------------------------------#
Windows 7, 64-bit
Python 2.7.3, 32-bit, from Python.org
PySide 1.1.1, 32-bit
PyQt 4.10, 32-bit
>>> import num_print
Original: 1.4
PyQt: 1.400000
PySide: 1.400000
Original: 1.6
PyQt: 1.600000
PySide: 1.600000
Original: 1000.4
PyQt: 1,000.400000
PySide: 1,000.400024
Original: 1000.6
PyQt: 1,000.600000
PySide: 1,000.599976
Original: 10**6 + .4
PyQt: 1,000,000.400000
PySide: 1,000,000.375000
Original: 10**6 + .6
PyQt: 1,000,000.600000
PySide: 1,000,000.625000
Original: 10**7 + .4
PyQt: 10,000,000.400000
PySide: 10,000,000.000000
Original: 10**7 + .6
PyQt: 10,000,000.600000
PySide: 10,000,001.000000
Original: 10**8 + .4
PyQt: 100,000,000.400000
PySide: 100,000,000.000000
Original: 10**8 + .6
PyQt: 100,000,000.600000
PySide: 100,000,000.000000
Original: 10**9 + .4
PyQt: 1,000,000,000.400000
PySide: 1,000,000,000.000000
Original: 10**9 + .6
PyQt: 1,000,000,000.600000
PySide: 1,000,000,000.000000
Original: 10**14 + .4
PyQt: 100,000,000,000,000.406250
PySide: 100,000,000,376,832.000000
Original: 10**14 + .6
PyQt: 100,000,000,000,000.593750
PySide: 100,000,000,376,832.000000
Original: 10**15 + .4
PyQt: 1,000,000,000,000,000.375000
PySide: 999,999,986,991,104.000000
Original: 10**15 + .6
PyQt: 1,000,000,000,000,000.625000
PySide: 999,999,986,991,104.000000
Original: 10**16 + .4
PyQt: 10,000,000,000,000,000.000000
PySide: 10,000,000,272,564,224.000000
Original: 10**16 + .6
PyQt: 10,000,000,000,000,000.000000
PySide: 10,000,000,272,564,224.000000
Original: 10**17 + .4
PyQt: 100,000,000,000,000,000.000000
PySide: 99,999,998,430,674,944.000000
Original: 10**17 + .6
PyQt: 100,000,000,000,000,000.000000
PySide: 99,999,998,430,674,944.000000
"""
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/pyside/attachments/20130414/2f05f52f/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: num_print.py
Type: text/x-python-script
Size: 4991 bytes
Desc: not available
URL: <http://lists.qt-project.org/pipermail/pyside/attachments/20130414/2f05f52f/attachment.bin>
More information about the PySide
mailing list