summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qbytearray.cpp3
-rw-r--r--src/corelib/tools/qlocale.cpp18
-rw-r--r--src/corelib/tools/qlocale_p.h11
-rw-r--r--src/corelib/tools/qstring.cpp6
-rw-r--r--tests/auto/corelib/tools/qlocale/tst_qlocale.cpp42
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
}