diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2014-11-12 12:22:55 +0900 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2014-11-20 05:46:18 +0100 |
commit | 8153386397087ce4f5c8997992edf5c1fd38b8db (patch) | |
tree | 889ec6c5b867202dd86053ac9c4169ec9a5e11f9 /src/corelib/kernel | |
parent | 2810d7ee10c59b0486c12744a2bdf22856bfb81e (diff) |
Enhance precision of the FP conversion to strings in QVariant
This now guarantees that doing a round-trip from an FP number to string
and back to number results in the same number. This change is required
because DBL_DIG and FLT_DIG don't have the meaning that we were
expecting them to, here: they mean the minimum number of digits of
precision in decimal (i.e., changing the last decimal will always cause
the FP number to change). We need the maximum number: there is one
change in the last decimal place that causes the FP number to change.
IEEE 754 single-precision has 24 binary digits and double precision has
53 binary digits in their mantissa. To convert that to decimal, multiply
by the number of decimal digits a binary digit represents (log2(10) =
0.3), then add one for the rounding and one more digit for the actual
precision we want. That is, for floats we now ask for 9 digits and for
double, 17 decimal digits.
Task-number: QTBUG-42574
Change-Id: Ic78beb60a218f75322f832d33d63fd84e7a65b65
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com>
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 2ac1bb11fb..73a951c39b 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -69,13 +69,18 @@ QT_BEGIN_NAMESPACE -#ifndef DBL_DIG -# define DBL_DIG 10 +#ifndef DBL_MANT_DIG +# define DBL_MANT_DIG 53 #endif -#ifndef FLT_DIG -# define FLT_DIG 6 +#ifndef FLT_MANT_DIG +# define FLT_MANT_DIG 24 #endif +const int log10_2_10000 = 30103; // log10(2) * 100000 +// same as C++11 std::numeric_limits<T>::max_digits10 +const int max_digits10_double = (DBL_MANT_DIG * log10_2_10000) / 100000 + 2; +const int max_digits10_float = (FLT_MANT_DIG * log10_2_10000) / 100000 + 2; + namespace { class HandlersManager { @@ -355,10 +360,10 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *str = QString::number(qMetaTypeUNumber(d)); break; case QMetaType::Float: - *str = QString::number(d->data.f, 'g', FLT_DIG); + *str = QString::number(d->data.f, 'g', max_digits10_float); break; case QVariant::Double: - *str = QString::number(d->data.d, 'g', DBL_DIG); + *str = QString::number(d->data.d, 'g', max_digits10_double); break; #if !defined(QT_NO_DATESTRING) case QVariant::Date: @@ -535,10 +540,10 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *ba = v_cast<QString>(d)->toUtf8(); break; case QVariant::Double: - *ba = QByteArray::number(d->data.d, 'g', DBL_DIG); + *ba = QByteArray::number(d->data.d, 'g', max_digits10_double); break; case QMetaType::Float: - *ba = QByteArray::number(d->data.f, 'g', FLT_DIG); + *ba = QByteArray::number(d->data.f, 'g', max_digits10_float); break; case QMetaType::Char: case QMetaType::SChar: |