We do in fact support 'F' format for floating-point values

Update docs and add tests.

[ChangeLog][QtCore] Documented existing support for 'F' format when
converting floating-point numbers to strings in QLocale::toString(),
hence equally for QString's floating-point formatting. Previously it
was supported but the documentation neglected to mention it; it only
differs from 'f' for infinities and NaN.

Change-Id: Ic946c0f7b9e86fdf512daa3124bea57fc664b34b
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
bb10
Edward Welbourne 2021-07-30 15:26:28 +02:00
parent 2e044791b8
commit 9e1a2b4603
3 changed files with 114 additions and 11 deletions

View File

@ -2646,22 +2646,24 @@ static bool qIsUpper(char c)
\row \li \c 'e' \li format as [-]9.9e[+|-]999
\row \li \c 'E' \li format as [-]9.9E[+|-]999
\row \li \c 'f' \li format as [-]9.9
\row \li \c 'F' \li same as \c 'f' except for INF and NAN (see below)
\row \li \c 'g' \li use \c 'e' or \c 'f' format, whichever is more concise
\row \li \c 'G' \li use \c 'E' or \c 'f' format, whichever is more concise
\row \li \c 'G' \li use \c 'E' or \c 'F' format, whichever is more concise
\endtable
For the \c 'e', \c 'E', and \c 'f' formats, the \a precision represents the
number of digits \e after the decimal point. For the \c 'g' and \c 'G'
formats, the \a precision represents the maximum number of significant
digits (trailing zeroes are omitted). The special \a precision value
QLocale::FloatingPointShortest selects the shortest representation that,
when read as a number, gets back the original floating-point value. Aside
from that, any negative \a precision is ignored in favor of the default, 6.
For the \c 'e', \c 'E', \c 'f' and \c 'F' formats, the \a precision
represents the number of digits \e after the decimal point. For the \c 'g'
and \c 'G' formats, the \a precision represents the maximum number of
significant digits (trailing zeroes are omitted). The special \a precision
value QLocale::FloatingPointShortest selects the shortest representation
that, when read as a number, gets back the original floating-point
value. Aside from that, any negative \a precision is ignored in favor of the
default, 6.
For the \c 'e', \c 'f' and \c 'g' formats, positive infinity is represented
as "inf", negative infinity as "-inf" and floating-point NaN (not-a-number)
values are represented as "nan". For the \c 'E' and \c 'G' formats, "INF"
and "NAN" are used instead. This does not vary with locale.
values are represented as "nan". For the \c 'E', \c 'F' and \c 'G' formats,
"INF" and "NAN" are used instead. This does not vary with locale.
\sa toDouble(), numberOptions(), exponential(), decimalPoint(), zeroDigit(),
positiveSign(), percent(), toCurrencyString(), formattedDataSize(),

View File

@ -90,6 +90,7 @@ private slots:
void long_long_conversion_data();
void long_long_conversion();
void long_long_conversion_extra();
void infNaN();
void fpExceptions();
void negativeZero_data();
void negativeZero();
@ -1408,6 +1409,101 @@ void tst_QLocale::long_long_conversion_extra()
QCOMPARE(l.toString((qulonglong)12345), QString("12,345"));
}
void tst_QLocale::infNaN()
{
// TODO: QTBUG-95460 -- could support localized forms of inf/NaN
const QLocale c(QLocale::C);
QCOMPARE(c.toString(qQNaN()), u"nan");
QCOMPARE(c.toString(qQNaN(), 'e'), u"nan");
QCOMPARE(c.toString(qQNaN(), 'f'), u"nan");
QCOMPARE(c.toString(qQNaN(), 'g'), u"nan");
QCOMPARE(c.toString(qQNaN(), 'E'), u"NAN");
QCOMPARE(c.toString(qQNaN(), 'F'), u"NAN");
QCOMPARE(c.toString(qQNaN(), 'G'), u"NAN");
QCOMPARE(c.toString(qInf()), u"inf");
QCOMPARE(c.toString(qInf(), 'e'), u"inf");
QCOMPARE(c.toString(qInf(), 'f'), u"inf");
QCOMPARE(c.toString(qInf(), 'g'), u"inf");
QCOMPARE(c.toString(qInf(), 'E'), u"INF");
QCOMPARE(c.toString(qInf(), 'F'), u"INF");
QCOMPARE(c.toString(qInf(), 'G'), u"INF");
// Precision is ignored for inf and NaN:
QCOMPARE(c.toString(qQNaN(), 'g', 42), u"nan");
QCOMPARE(c.toString(qQNaN(), 'G', 42), u"NAN");
QCOMPARE(c.toString(qInf(), 'g', 42), u"inf");
QCOMPARE(c.toString(qInf(), 'G', 42), u"INF");
// Case is ignored when parsing inf and NaN:
bool ok = false;
QCOMPARE(c.toDouble("inf", &ok), qInf());
QVERIFY(ok);
QCOMPARE(c.toDouble("INF", &ok), qInf());
QVERIFY(ok);
QCOMPARE(c.toDouble("Inf", &ok), qInf());
QVERIFY(ok);
QCOMPARE(c.toDouble("+inf", &ok), qInf());
QVERIFY(ok);
QCOMPARE(c.toDouble("+INF", &ok), qInf());
QVERIFY(ok);
QCOMPARE(c.toDouble("+inF", &ok), qInf());
QVERIFY(ok);
QCOMPARE(c.toDouble("-inf", &ok), -qInf());
QVERIFY(ok);
QCOMPARE(c.toDouble("-INF", &ok), -qInf());
QVERIFY(ok);
QCOMPARE(c.toDouble("-iNf", &ok), -qInf());
QVERIFY(ok);
QCOMPARE(c.toDouble("nan", &ok), qQNaN());
QVERIFY(ok);
QCOMPARE(c.toDouble("NaN", &ok), qQNaN());
QVERIFY(ok);
QCOMPARE(c.toDouble("NAN", &ok), qQNaN());
QVERIFY(ok);
QCOMPARE(c.toDouble("nAn", &ok), qQNaN());
QVERIFY(ok);
// Sign is invalid for NaN:
QCOMPARE(c.toDouble("-nan", &ok), 0.0);
QVERIFY(!ok);
QCOMPARE(c.toDouble("+nan", &ok), 0.0);
QVERIFY(!ok);
// Case is ignored when parsing inf and NaN:
QCOMPARE(c.toFloat("inf", &ok), float(qInf()));
QVERIFY(ok);
QCOMPARE(c.toFloat("INF", &ok), float(qInf()));
QVERIFY(ok);
QCOMPARE(c.toFloat("Inf", &ok), float(qInf()));
QVERIFY(ok);
QCOMPARE(c.toFloat("+inf", &ok), float(qInf()));
QVERIFY(ok);
QCOMPARE(c.toFloat("+INF", &ok), float(qInf()));
QVERIFY(ok);
QCOMPARE(c.toFloat("+inF", &ok), float(qInf()));
QVERIFY(ok);
QCOMPARE(c.toFloat("-inf", &ok), -float(qInf()));
QVERIFY(ok);
QCOMPARE(c.toFloat("-INF", &ok), -float(qInf()));
QVERIFY(ok);
QCOMPARE(c.toFloat("-iNf", &ok), -float(qInf()));
QVERIFY(ok);
QCOMPARE(c.toFloat("nan", &ok), float(qQNaN()));
QVERIFY(ok);
QCOMPARE(c.toFloat("NaN", &ok), float(qQNaN()));
QVERIFY(ok);
QCOMPARE(c.toFloat("NAN", &ok), float(qQNaN()));
QVERIFY(ok);
QCOMPARE(c.toFloat("nAn", &ok), float(qQNaN()));
QVERIFY(ok);
// Sign is invalid for NaN:
QCOMPARE(c.toFloat("-nan", &ok), 0.0f);
QVERIFY(!ok);
QCOMPARE(c.toFloat("+nan", &ok), 0.0f);
QVERIFY(!ok);
}
void tst_QLocale::fpExceptions()
{
// Check that double-to-string conversion doesn't throw floating point

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Copyright (C) 2020 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
@ -6430,6 +6430,11 @@ void tst_QString::nanAndInf()
QCOMPARE(form.arg(-qInf(), 6, 'f', 3, '0'), u"00-inf");
QCOMPARE(form.arg(-qInf(), -6, 'f', 3, '0'), u"-inf00");
QCOMPARE(form.arg(qQNaN(), -5, 'f', 3, '0'), u"nan00");
QCOMPARE(form.arg(qInf(), 5, 'F', 3, '0'), u"00INF");
QCOMPARE(form.arg(qInf(), -5, 'F', 3, '0'), u"INF00");
QCOMPARE(form.arg(-qInf(), 6, 'F', 3, '0'), u"00-INF");
QCOMPARE(form.arg(-qInf(), -6, 'F', 3, '0'), u"-INF00");
QCOMPARE(form.arg(qQNaN(), -5, 'F', 3, '0'), u"NAN00");
QCOMPARE(form.arg(qInf(), 5, 'e', 3, '0'), u"00inf");
QCOMPARE(form.arg(qInf(), -5, 'e', 3, '0'), u"inf00");
QCOMPARE(form.arg(-qInf(), 6, 'e', 3, '0'), u"00-inf");