How to get locale-specific number string with high precision?
-
Hi,
I would like to represent numbers in locale-specific format and I useQLocale
for 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,000000
As 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 useQLocale
for 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,000000
As 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
str
in Python instead ofQString
. May you advise me how to importQString
properly if I'm wrong? -
@JonB, I probably missed something... but I thought that Qt uses native
str
in Python instead ofQString
. May you advise me how to importQString
properly 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
/double
issue between Python and Qt/C++. I am guessing/presumingb = 1234567890.123456789
fits into adouble
and 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
/double
issue between Python and Qt/C++. I am guessing/presumingb = 1234567890.123456789
fits into adouble
and 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
/double
issue 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) const
But instead of
float
/double
Python has only onefloat
type that is effectivelydouble
in 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
/double
issue 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) const
But instead of
float
/double
Python has only onefloat
type that is effectivelydouble
in 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 thedouble
overload rather than the samefloat
one.] 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
/double
issue. -
@JonB, I use PySide, but either not sure is there any difference with PyQt or not.
I would suspect somefloat
/double
issue 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) const
But instead of
float
/double
Python has only onefloat
type that is effectivelydouble
in 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.000000
However, 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.123457
That 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)
QLocale
is handling doubles again correctly and (b) PySide2 seems here to correctly pass back adouble
, e.g. it does not automatically convertdouble
s tofloat
s 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
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 brokenQLocale
one? -
@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.000000
However, 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.123457
That 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)
QLocale
is handling doubles again correctly and (b) PySide2 seems here to correctly pass back adouble
, e.g. it does not automatically convertdouble
s tofloat
s 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
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 brokenQLocale
one?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.