summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@theqtcompany.com>2015-10-16 16:52:51 +0200
committerUlf Hermann <ulf.hermann@theqtcompany.com>2015-11-23 14:13:34 +0000
commit726fed0d67013cbfac7921d3d4613ca83406fb0f (patch)
treed8fd15a7d6416a91c150d6f2a3b0bdd98caa0d7f /src/corelib/tools
parent04695c7a91bf2b7372bb5de5f8e0b5d6f7278f67 (diff)
Interpret precision == -128 as "shortest" double conversion
Also use this for converting doubles with QVariant. We generally want exact results there, rather than adding rounding errors whenever we convert. [ChangeLog][QtCore][QLocale] Added special value for double conversion precision to get shortest accurate representation. Change-Id: I905b8a103f39adf31d24b6ce2c8a283cf271b597 Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/qlocale.cpp21
-rw-r--r--src/corelib/tools/qlocale.h4
-rw-r--r--src/corelib/tools/qlocale.qdoc17
-rw-r--r--src/corelib/tools/qlocale_tools.cpp30
-rw-r--r--src/corelib/tools/qlocale_tools_p.h4
5 files changed, 60 insertions, 16 deletions
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index dcb77a2c1b..072d62f5c2 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -2743,7 +2743,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
const QChar exponential, const QChar group, const QChar decimal,
double d, int precision, DoubleForm form, int width, unsigned flags)
{
- if (precision < 0)
+ if (precision != QLocale::FloatingPointShortest && precision < 0)
precision = 6;
if (width < 0)
width = 0;
@@ -2753,7 +2753,9 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
int decpt;
int bufSize = 1;
- if (form == DFDecimal) // optimize for numbers smaller than 512k
+ if (precision == QLocale::FloatingPointShortest)
+ bufSize += DoubleMaxSignificant;
+ else if (form == DFDecimal) // optimize for numbers between -512k and 512k
bufSize += ((d > (1 << 19) || d < -(1 << 19)) ? DoubleMaxDigitsBeforeDecimal : 6) +
precision;
else // Add extra digit due to different interpretations of precision. Also, "nan" has to fit.
@@ -2798,7 +2800,20 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
PrecisionMode mode = (flags & Alternate) ?
PMSignificantDigits : PMChopTrailingZeros;
- if (decpt != digits.length() && (decpt <= -4 || decpt > precision))
+ int cutoff = precision < 0 ? 6 : precision;
+ // Find out which representation is shorter
+ if (precision == QLocale::FloatingPointShortest && decpt > 0) {
+ cutoff = digits.length() + 4; // 'e', '+'/'-', one digit exponent
+ if (decpt <= 10) {
+ ++cutoff;
+ } else {
+ cutoff += decpt > 100 ? 2 : 1;
+ }
+ if (!always_show_decpt && digits.length() > decpt)
+ ++cutoff; // decpt shown in exponent form, but not in decimal form
+ }
+
+ if (decpt != digits.length() && (decpt <= -4 || decpt > cutoff))
num_str = exponentForm(_zero, decimal, exponential, group, plus, minus,
digits, decpt, precision, mode,
always_show_decpt);
diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h
index 729fd73a5d..f64a25bd00 100644
--- a/src/corelib/tools/qlocale.h
+++ b/src/corelib/tools/qlocale.h
@@ -848,6 +848,10 @@ public:
};
Q_DECLARE_FLAGS(NumberOptions, NumberOption)
+ enum FloatingPointPrecisionOption {
+ FloatingPointShortest = -128
+ };
+
enum CurrencySymbolFormat {
CurrencyIsoCode,
CurrencySymbol,
diff --git a/src/corelib/tools/qlocale.qdoc b/src/corelib/tools/qlocale.qdoc
index c87e67cf17..03095d88d2 100644
--- a/src/corelib/tools/qlocale.qdoc
+++ b/src/corelib/tools/qlocale.qdoc
@@ -941,6 +941,23 @@
*/
/*!
+ \enum QLocale::FloatingPointPrecisionOption
+
+ This enum defines constants that can be given as precision to QString::number(),
+ QByteArray::number(), and QLocale::toString() when converting floats or doubles,
+ in order to express a variable number of digits as precision.
+
+ \value FloatingPointShortest The conversion algorithm will try to find the
+ shortest accurate representation for the given number. "Accurate" means
+ that you get the exact same number back from an inverse conversion on
+ the generated string representation.
+
+ \sa toString(), QString, QByteArray
+
+ \since 5.7
+*/
+
+/*!
\enum QLocale::MeasurementSystem
This enum defines which units are used for measurement.
diff --git a/src/corelib/tools/qlocale_tools.cpp b/src/corelib/tools/qlocale_tools.cpp
index 18d1096c12..890f63af0a 100644
--- a/src/corelib/tools/qlocale_tools.cpp
+++ b/src/corelib/tools/qlocale_tools.cpp
@@ -114,10 +114,16 @@ void doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *
if (form == QLocaleData::DFExponent && precision >= 0)
++precision;
- double_conversion::DoubleToStringConverter::DoubleToAscii(d,
- form == QLocaleData::DFDecimal ? double_conversion::DoubleToStringConverter::FIXED :
- double_conversion::DoubleToStringConverter::PRECISION,
- precision, buf, bufSize, &sign, &length, &decpt);
+ double_conversion::DoubleToStringConverter::DtoaMode mode;
+ if (precision == QLocale::FloatingPointShortest) {
+ mode = double_conversion::DoubleToStringConverter::SHORTEST;
+ } else if (form == QLocaleData::DFSignificantDigits || form == QLocaleData::DFExponent) {
+ mode = double_conversion::DoubleToStringConverter::PRECISION;
+ } else {
+ mode = double_conversion::DoubleToStringConverter::FIXED;
+ }
+ double_conversion::DoubleToStringConverter::DoubleToAscii(d, mode, precision, buf, bufSize,
+ &sign, &length, &decpt);
#else // QT_NO_DOUBLECONVERSION || QT_BOOTSTRAPPED
// Cut the precision at 999, to fit it into the format string. We can't get more than 17
@@ -126,6 +132,8 @@ void doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *
// to honor higher precisions. We define that at more than 999 digits that is not the case.
if (precision > 999)
precision = 999;
+ else if (precision == QLocale::FloatingPointShortest)
+ precision = QLocaleData::DoubleMaxSignificant; // "shortest" mode not supported by snprintf
if (isZero(d)) {
// Negative zero is expected as simple "0", not "-0". We cannot do d < 0, though.
@@ -442,7 +450,7 @@ QString qlltoa(qlonglong l, int base, const QChar zero)
}
QString &decimalForm(QChar zero, QChar decimal, QChar group,
- QString &digits, int decpt, uint precision,
+ QString &digits, int decpt, int precision,
PrecisionMode pm,
bool always_show_decpt,
bool thousands_group)
@@ -459,11 +467,11 @@ QString &decimalForm(QChar zero, QChar decimal, QChar group,
if (pm == PMDecimalDigits) {
uint decimal_digits = digits.length() - decpt;
- for (uint i = decimal_digits; i < precision; ++i)
+ for (int i = decimal_digits; i < precision; ++i)
digits.append(zero);
}
else if (pm == PMSignificantDigits) {
- for (uint i = digits.length(); i < precision; ++i)
+ for (int i = digits.length(); i < precision; ++i)
digits.append(zero);
}
else { // pm == PMChopTrailingZeros
@@ -485,18 +493,18 @@ QString &decimalForm(QChar zero, QChar decimal, QChar group,
QString &exponentForm(QChar zero, QChar decimal, QChar exponential,
QChar group, QChar plus, QChar minus,
- QString &digits, int decpt, uint precision,
+ QString &digits, int decpt, int precision,
PrecisionMode pm,
bool always_show_decpt)
{
int exp = decpt - 1;
if (pm == PMDecimalDigits) {
- for (uint i = digits.length(); i < precision + 1; ++i)
+ for (int i = digits.length(); i < precision + 1; ++i)
digits.append(zero);
}
else if (pm == PMSignificantDigits) {
- for (uint i = digits.length(); i < precision; ++i)
+ for (int i = digits.length(); i < precision; ++i)
digits.append(zero);
}
else { // pm == PMChopTrailingZeros
@@ -534,7 +542,7 @@ QString qdtoa(qreal d, int *decpt, int *sign)
// Some versions of libdouble-conversion like an extra digit, probably for '\0'
char result[QLocaleData::DoubleMaxSignificant + 1];
- doubleToAscii(d, QLocaleData::DFSignificantDigits, QLocaleData::DoubleMaxSignificant, result,
+ doubleToAscii(d, QLocaleData::DFSignificantDigits, QLocale::FloatingPointShortest, result,
QLocaleData::DoubleMaxSignificant + 1, nonNullSign, length, nonNullDecpt);
// Skip trailing zeroes. The DoubleMaxSignificant precision is the worst case.
diff --git a/src/corelib/tools/qlocale_tools_p.h b/src/corelib/tools/qlocale_tools_p.h
index 840ae8f163..3ddf75d000 100644
--- a/src/corelib/tools/qlocale_tools_p.h
+++ b/src/corelib/tools/qlocale_tools_p.h
@@ -81,13 +81,13 @@ enum PrecisionMode {
};
QString &decimalForm(QChar zero, QChar decimal, QChar group,
- QString &digits, int decpt, uint precision,
+ QString &digits, int decpt, int precision,
PrecisionMode pm,
bool always_show_decpt,
bool thousands_group);
QString &exponentForm(QChar zero, QChar decimal, QChar exponential,
QChar group, QChar plus, QChar minus,
- QString &digits, int decpt, uint precision,
+ QString &digits, int decpt, int precision,
PrecisionMode pm,
bool always_show_decpt);