diff options
author | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-10-16 16:52:51 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-11-23 14:13:34 +0000 |
commit | 726fed0d67013cbfac7921d3d4613ca83406fb0f (patch) | |
tree | d8fd15a7d6416a91c150d6f2a3b0bdd98caa0d7f /src/corelib/tools | |
parent | 04695c7a91bf2b7372bb5de5f8e0b5d6f7278f67 (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.cpp | 21 | ||||
-rw-r--r-- | src/corelib/tools/qlocale.h | 4 | ||||
-rw-r--r-- | src/corelib/tools/qlocale.qdoc | 17 | ||||
-rw-r--r-- | src/corelib/tools/qlocale_tools.cpp | 30 | ||||
-rw-r--r-- | src/corelib/tools/qlocale_tools_p.h | 4 |
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); |