First of all - Zak, thank you for your opinion and your efforts to back it with data - you obviously spend much time and effort on it. The only thing that I would ask of you is to add a little more brevity into your arguments. Thanks.
About the matter at hand. When I see something like this.: val = 999999.9 print(PySideLocale().toString(val, 'f', 2)) #999 999,88 print(PyQtLocale().toString(val, 'f', 2)) #999 999,90 print(str(val)) #999999.9 .I will inevitably arrive to a conclusion that PySide's behavior is inconsistent with that of the language it's written for and of the library it tries to imitate. You see, maybe you are completely right about rounding, conversions, math etc and PySide is really giving correct/reasonable results. But people doing software development need consistency and predictability. And in this particular case PySide fails to deliver both. From: Zak [mailto:[email protected]] Sent: Sunday, April 14, 2013 11:36 PM To: Alexey Vihorev Cc: [email protected]; [email protected] Subject: Re: [PySide] Strange behaviour of QLocale.toString() 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 """
_______________________________________________ PySide mailing list [email protected] http://lists.qt-project.org/mailman/listinfo/pyside
