[PySide] Strange behaviour of QLocale.toString()

Tim Doty thoromyr at mac.com
Mon Apr 15 03:14:02 CEST 2013


On Apr 14, 2013, at 6:30 PM, Algis Kabaila <akabaila at pcug.org.au> wrote:

> Just to add a little fuel to this fire:
>  
> First, by hand try to convert the "exact" 0.1 then 0.01 decimal to their binary equivalent. Send to this list the binary value.  Is it exact?
>  
> Second, who would care about 1 cent in $10 000 ?

people who are stealing money :) Its been some years, but taking the roundings has actually been done. It has always amused me when people insist on using float for "dollars" rather than tracking cents exactly.


>  
> Al.
>  
> On Sunday 14 April 2013 16:04:15 Tim Doty wrote:
> > On Apr 14, 2013, at 3:35 PM, Zak <pyside at m.allo.ws> wrote:
> > > My original email was correct, let me provide proof and explain
> > > further.
> > > 
> > > 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.
> > As I said, I don't know the PySide internals. I referred to the
> > published documentation which implies that floats are being coerced
> > into integers due to lack of a float overload. Apparently the docs are
> > wrong… go figure.
> > 
> > Interestingly, if you drop the millions (e.g., 999999.62) you can see
> > the rounding in action. I'm not going to dredge through a wall of text
> > looking for a point in the preceding post, but -- as it so happens --
> > the example I give above outputs correctly making it seem as if there
> > is inconsistent precision. But it is an accident. 999999.65 also prints
> > as 999999.62 while 999999.66 prints as 999999.69
> > 
> > So it is just an artifact of 32-bit precision float representations.
> > Now, why it is being constrained to a 32-bit float on a 64-bit
> > architecture is a different conversation and, while I recognize there
> > would be disagreement, I call that a bug on its face and the fact that
> > the sibling implementation uses 64-bit precision underscores the point.
> > 
> > Tim Doty
> > 
> > > 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
> > > 
> > > """
> > > 
> > > <num_print.py>
> > 
> > _______________________________________________
> > PySide mailing list
> > PySide at qt-project.org
> > http://lists.qt-project.org/mailman/listinfo/pysidea




More information about the PySide mailing list