diff options
-rw-r--r-- | src/corelib/tools/qbytearray.cpp | 3 | ||||
-rw-r--r-- | src/corelib/tools/qlocale.cpp | 18 | ||||
-rw-r--r-- | src/corelib/tools/qlocale_p.h | 11 | ||||
-rw-r--r-- | src/corelib/tools/qstring.cpp | 6 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qlocale/tst_qlocale.cpp | 42 |
5 files changed, 60 insertions, 20 deletions
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 1b7a4366c7..2a97fa50a9 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -3899,7 +3899,8 @@ double QByteArray::toDouble(bool *ok) const /*! Returns the byte array converted to a \c float value. - Returns 0.0 if the conversion fails. + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for other reasons (e.g. underflow). If \a ok is not \c nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 8f9fb3de2d..417b1e41f6 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -1353,8 +1353,10 @@ qulonglong QLocale::toULongLong(const QString &s, bool *ok) const } /*! - Returns the float represented by the localized string \a s, or 0.0 - if the conversion failed. + Returns the float represented by the localized string \a s. + + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for any other reason (e.g. underflow). If \a ok is not \c nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. @@ -1522,8 +1524,10 @@ qulonglong QLocale::toULongLong(const QStringRef &s, bool *ok) const } /*! - Returns the float represented by the localized string \a s, or 0.0 - if the conversion failed. + Returns the float represented by the localized string \a s. + + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for any other reason (e.g. underflow). If \a ok is not \c nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. @@ -1696,8 +1700,10 @@ qulonglong QLocale::toULongLong(QStringView s, bool *ok) const } /*! - Returns the float represented by the localized string \a s, or 0.0 - if the conversion failed. + Returns the float represented by the localized string \a s. + + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for any other reason (e.g. underflow). If \a ok is not \c nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index 6669ae7c8b..deca671627 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -249,7 +249,16 @@ public: if (std::fabs(d) > std::numeric_limits<float>::max()) { if (ok != 0) *ok = false; - return 0.0f; + const float huge = std::numeric_limits<float>::infinity(); + return d < 0 ? -huge : huge; + } + if (std::fabs(d) >= std::numeric_limits<double>::min() // i.e. d != 0 + && std::fabs(d) < std::numeric_limits<float>::min()) { + // Values smaller than std::numeric_limits<double>::min() have + // failed already; match them. + if (ok != 0) + *ok = false; + return 0; } return float(d); } diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 1381e8c11c..94b1784202 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -7208,7 +7208,8 @@ double QString::toDouble(bool *ok) const /*! Returns the string converted to a \c float value. - Returns 0.0 if the conversion fails. + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for other reasons (e.g. underflow). If \a ok is not \c nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. @@ -11821,7 +11822,8 @@ double QStringRef::toDouble(bool *ok) const /*! Returns the string converted to a \c float value. - Returns 0.0 if the conversion fails. + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for other reasons (e.g. underflow). If \a ok is not \c nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. diff --git a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp index 7bf6d1327e..b8f1cc568a 100644 --- a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp @@ -877,6 +877,28 @@ void tst_QLocale::stringToDouble() void tst_QLocale::stringToFloat_data() { toReal_data(); + if (std::numeric_limits<float>::has_infinity) { + double huge = std::numeric_limits<float>::infinity(); + QTest::newRow("C inf") << QString("C") << QString("inf") << true << huge; + QTest::newRow("C +inf") << QString("C") << QString("+inf") << true << +huge; + QTest::newRow("C -inf") << QString("C") << QString("-inf") << true << -huge; + // Overflow float, but not double: + QTest::newRow("C big") << QString("C") << QString("3.5e38") << false << huge; + QTest::newRow("C -big") << QString("C") << QString("-3.5e38") << false << -huge; + // Overflow double, too: + QTest::newRow("C huge") << QString("C") << QString("2e308") << false << huge; + QTest::newRow("C -huge") << QString("C") << QString("-2e308") << false << -huge; + } + if (std::numeric_limits<float>::has_quiet_NaN) + QTest::newRow("C qnan") << QString("C") << QString("NaN") << true << double(std::numeric_limits<float>::quiet_NaN()); + + // Underflow float, but not double: + QTest::newRow("C small") << QString("C") << QString("1e-45") << false << 0.; + QTest::newRow("C -small") << QString("C") << QString("-1e-45") << false << 0.; + + // Underflow double, too: + QTest::newRow("C tiny") << QString("C") << QString("2e-324") << false << 0.; + QTest::newRow("C -tiny") << QString("C") << QString("-2e-324") << false << 0.; } void tst_QLocale::stringToFloat() @@ -904,24 +926,24 @@ void tst_QLocale::stringToFloat() QCOMPARE(ok, good); } - if (ok) { + if (ok || std::isinf(fnum)) { // First use fuzzy-compare, then a more precise check: QCOMPARE(f, fnum); - float diff = f - fnum; - if (diff < 0) - diff = -diff; - QVERIFY(diff <= MY_FLOAT_EPSILON); + if (std::isfinite(fnum)) { + float diff = f > fnum ? f - fnum : fnum - f; + QVERIFY(diff <= MY_FLOAT_EPSILON); + } } f = locale.toFloat(num_strRef, &ok); QCOMPARE(ok, good); - if (ok) { + if (ok || std::isinf(fnum)) { QCOMPARE(f, fnum); - float diff = f - fnum; - if (diff < 0) - diff = -diff; - QVERIFY(diff <= MY_FLOAT_EPSILON); + if (std::isfinite(fnum)) { + float diff = f > fnum ? f - fnum : fnum - f; + QVERIFY(diff <= MY_FLOAT_EPSILON); + } } #undef MY_FLOAT_EPSILON } |