How to get locale-specific number string with high precision?
-
Hi,
I would like to represent numbers in locale-specific format and I useQLocalefor this task. But I see it has low precision (I assume becuase of 32-bit float usage under the hood). Here is an example:from PySide6.QtCore import QLocale a = 196015.260 b = 1234567890.123456789 print(f"Value 1: {a:.2f}") print(f"Value 2: {QLocale().toString(a, 'f', 2)}") print(f"Value 3: {b:.6f}") print(f"Value 4: {QLocale().toString(b, 'f', 6)}")that provides this output:
Value 1: 196015.26 Value 2: 196 015,27 Value 3: 1234567890.123457 Value 4: 1 234 567 936,000000As you may see
QLocale.toString()method handles only about 7 digits correctly (that is expected precision for float32).Is there a way to make
toString()more precise? Or is there an alternative way to convert a number string '1234567890.123456789' into locale-specific representation without losing precision? -
Hi,
I would like to represent numbers in locale-specific format and I useQLocalefor this task. But I see it has low precision (I assume becuase of 32-bit float usage under the hood). Here is an example:from PySide6.QtCore import QLocale a = 196015.260 b = 1234567890.123456789 print(f"Value 1: {a:.2f}") print(f"Value 2: {QLocale().toString(a, 'f', 2)}") print(f"Value 3: {b:.6f}") print(f"Value 4: {QLocale().toString(b, 'f', 6)}")that provides this output:
Value 1: 196015.26 Value 2: 196 015,27 Value 3: 1234567890.123457 Value 4: 1 234 567 936,000000As you may see
QLocale.toString()method handles only about 7 digits correctly (that is expected precision for float32).Is there a way to make
toString()more precise? Or is there an alternative way to convert a number string '1234567890.123456789' into locale-specific representation without losing precision? -
@JonB, I probably missed something... but I thought that Qt uses native
strin Python instead ofQString. May you advise me how to importQStringproperly if I'm wrong? -
@JonB, I probably missed something... but I thought that Qt uses native
strin Python instead ofQString. May you advise me how to importQStringproperly if I'm wrong?@StarterKit
Would depend on PySide/PyQt, and I don't know. I'm trying to find an alternative toQLocale().toString(). It is not clear whether this is aQLocale()issue or a floating point perhapsfloat/doubleissue between Python and Qt/C++. I am guessing/presumingb = 1234567890.123456789fits into adoubleand that is what Python uses? I wouldn't know if Python uses more precision than that. -
@StarterKit
Would depend on PySide/PyQt, and I don't know. I'm trying to find an alternative toQLocale().toString(). It is not clear whether this is aQLocale()issue or a floating point perhapsfloat/doubleissue between Python and Qt/C++. I am guessing/presumingb = 1234567890.123456789fits into adoubleand that is what Python uses? I wouldn't know if Python uses more precision than that.@JonB, I use PySide, but either not sure is there any difference with PyQt or not.
I would suspect somefloat/doubleissue between Python and Qt/C++ becase if we look at QLocale Class description we see 2 different methods:QString toString(double f, char format = 'g', int precision = 6) const QString toString(float f, char format = 'g', int precision = 6) constBut instead of
float/doublePython has only onefloattype that is effectivelydoublein C++. So I may suspect that a call oftoString()method from Python is mapped to
QString toString(float f, char format = 'g', int precision = 6) const
instead of
QString toString(float f, char format = 'g', int precision = 6) const -
@JonB, I use PySide, but either not sure is there any difference with PyQt or not.
I would suspect somefloat/doubleissue between Python and Qt/C++ becase if we look at QLocale Class description we see 2 different methods:QString toString(double f, char format = 'g', int precision = 6) const QString toString(float f, char format = 'g', int precision = 6) constBut instead of
float/doublePython has only onefloattype that is effectivelydoublein C++. So I may suspect that a call oftoString()method from Python is mapped to
QString toString(float f, char format = 'g', int precision = 6) const
instead of
QString toString(float f, char format = 'g', int precision = 6) const@StarterKit
I am aware of this. [Your "instead of" example should be using thedoubleoverload rather than the samefloatone.] That is why I was asking you to find some Qt call other thanQLocale().toString(), which is acceptable to PySide so notQString, where we can (try to) test whether it behaves the same or differently wrt the precision and the possiblefloat/doubleissue. -
@JonB, I use PySide, but either not sure is there any difference with PyQt or not.
I would suspect somefloat/doubleissue between Python and Qt/C++ becase if we look at QLocale Class description we see 2 different methods:QString toString(double f, char format = 'g', int precision = 6) const QString toString(float f, char format = 'g', int precision = 6) constBut instead of
float/doublePython has only onefloattype that is effectivelydoublein C++. So I may suspect that a call oftoString()method from Python is mapped to
QString toString(float f, char format = 'g', int precision = 6) const
instead of
QString toString(float f, char format = 'g', int precision = 6) const@StarterKit
I can only test with the following: Linux, Qt 5.12, PySide2-5.13, PyQt 5.14, Python 3.8.10.With PySide2 I get the same as you (PySide6):
Value 1: 196015.26 Value 2: 196,015.27 Value 3: 1234567890.123457 Value 4: 1,234,567,936.000000However, same code, with PyQt5 I get:
Value 1: 196015.26 Value 2: 196,015.26 Value 3: 1234567890.123457 Value 4: 1,234,567,890.123457That tells you that Qt's (C++)
QLocale()is looking good. (I didn't test it in C++, but I think we can assume it works fine.) PyQt5 gets the right values too no problem. So the Python version is not an issue an either.Which leaves us specifically with PySide, 2 or 6, and however it binds to the Qt call. Which does a bit
float-y rather thandouble-y. Which, if I may say so, is familiarly depressing. After a long time of being out, PySide is still full of holes and not as robust as PyQt. TQtC have had a lot of time to make it as good, and claim to support Python alongside C++, but in practice I have only ever seen Python/PySide as a second-class citizen.Now, here is an interesting addition to your test code with PySide:
print(f"toDouble(): {QLocale().toDouble(str(b))}") # Output: toDouble(): (1234567890.1234567, True)This shows (a)
QLocaleis handling doubles again correctly and (b) PySide2 seems here to correctly pass back adouble, e.g. it does not automatically convertdoubles tofloats or similar.I am unable to spot a different function which might take a double and produce a locale-string from it. So unless someone else can, that leaves you with possibly reporting it as a PySide6 bug and see what happens when?
Maybe as a workaround you do not need to use Qt's
QLocalefor this? The rest of your code is Python-only, not Qt. Python has its own locale-strings handling, perhaps you could use that instead of the brokenQLocaleone? -
@StarterKit
I can only test with the following: Linux, Qt 5.12, PySide2-5.13, PyQt 5.14, Python 3.8.10.With PySide2 I get the same as you (PySide6):
Value 1: 196015.26 Value 2: 196,015.27 Value 3: 1234567890.123457 Value 4: 1,234,567,936.000000However, same code, with PyQt5 I get:
Value 1: 196015.26 Value 2: 196,015.26 Value 3: 1234567890.123457 Value 4: 1,234,567,890.123457That tells you that Qt's (C++)
QLocale()is looking good. (I didn't test it in C++, but I think we can assume it works fine.) PyQt5 gets the right values too no problem. So the Python version is not an issue an either.Which leaves us specifically with PySide, 2 or 6, and however it binds to the Qt call. Which does a bit
float-y rather thandouble-y. Which, if I may say so, is familiarly depressing. After a long time of being out, PySide is still full of holes and not as robust as PyQt. TQtC have had a lot of time to make it as good, and claim to support Python alongside C++, but in practice I have only ever seen Python/PySide as a second-class citizen.Now, here is an interesting addition to your test code with PySide:
print(f"toDouble(): {QLocale().toDouble(str(b))}") # Output: toDouble(): (1234567890.1234567, True)This shows (a)
QLocaleis handling doubles again correctly and (b) PySide2 seems here to correctly pass back adouble, e.g. it does not automatically convertdoubles tofloats or similar.I am unable to spot a different function which might take a double and produce a locale-string from it. So unless someone else can, that leaves you with possibly reporting it as a PySide6 bug and see what happens when?
Maybe as a workaround you do not need to use Qt's
QLocalefor this? The rest of your code is Python-only, not Qt. Python has its own locale-strings handling, perhaps you could use that instead of the brokenQLocaleone?Hi @JonB, thank your very much for your tests and inputs!
I mostly agree with everything you wrote. A couple more commens:- about this part
Maybe as a workaround you do not need to use Qt's QLocale for this? The rest of your code is Python-only, not Qt. Python has its own locale-strings handling, perhaps you could use that instead of the broken QLocale one?
Yes, I thought about it and indeed Python is able to do the job. Maybe I didn't dig deep enough but I found a way how to do it only via switching of locale back and forth. And Python manuals are strongly against it - they warn of various side effects that happens with locale switching and advise not to do it this way.
- About workaround itself - it appears that for my needs everything is related with
QLocale().decimalPoint()andQLocale().groupSeparator()so I think I'll be able to make proper replacements with my own Python code. - I'll try to report this as a bug, but a bit later, when I'll have some spare time for it.