Refine underflow check in QLocaleData::convertDoubleToFloat()
A string can parse as a non-zero double that's smaller than the smallest float yet be a faithful representation of the smallest float. So rather than testing for non-zero doubles less than the smallest float, test for non-zero doubles that cast to float zero; these underflow. This means small values close below the smallest float shall round up to it, rather than down to zero, requiring a tweak to an existing test. Added a test for the boundary case (and tidied the test data). Fixes: QTBUG-74833 Change-Id: I4cb30b3c0e54683574b98253505607caaf88fbfb Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
e453222414
commit
954b73445c
@ -252,10 +252,8 @@ public:
|
||||
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 (d != 0 && float(d) == 0) {
|
||||
// Values that underflow double already failed. Match them:
|
||||
if (ok != 0)
|
||||
*ok = false;
|
||||
return 0;
|
||||
|
@ -952,29 +952,42 @@ void tst_QLocale::stringToDouble()
|
||||
|
||||
void tst_QLocale::stringToFloat_data()
|
||||
{
|
||||
using Bounds = std::numeric_limits<float>;
|
||||
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;
|
||||
const QString C(QStringLiteral("C"));
|
||||
if (Bounds::has_infinity) {
|
||||
double huge = Bounds::infinity();
|
||||
QTest::newRow("C inf") << C << QString("inf") << true << huge;
|
||||
QTest::newRow("C +inf") << C << QString("+inf") << true << +huge;
|
||||
QTest::newRow("C -inf") << 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;
|
||||
QTest::newRow("C big") << C << QString("3.5e38") << false << huge;
|
||||
QTest::newRow("C -big") << 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;
|
||||
QTest::newRow("C huge") << C << QString("2e308") << false << huge;
|
||||
QTest::newRow("C -huge") << 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());
|
||||
if (Bounds::has_quiet_NaN)
|
||||
QTest::newRow("C qnan") << C << QString("NaN") << true << double(Bounds::quiet_NaN());
|
||||
|
||||
// Minimal float: shouldn't underflow
|
||||
QTest::newRow("C float min")
|
||||
<< C << QLocale::c().toString(Bounds::denorm_min()) << true << double(Bounds::denorm_min());
|
||||
QTest::newRow("C float -min")
|
||||
<< C << QLocale::c().toString(-Bounds::denorm_min()) << true << -double(Bounds::denorm_min());
|
||||
|
||||
// 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.;
|
||||
QTest::newRow("C small") << C << QString("7e-46") << false << 0.;
|
||||
QTest::newRow("C -small") << C << QString("-7e-46") << false << 0.;
|
||||
using Double = std::numeric_limits<double>;
|
||||
QTest::newRow("C double min")
|
||||
<< C << QLocale::c().toString(Double::denorm_min()) << false << 0.0;
|
||||
QTest::newRow("C double -min")
|
||||
<< C << QLocale::c().toString(-Double::denorm_min()) << false << 0.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.;
|
||||
QTest::newRow("C tiny") << C << QString("2e-324") << false << 0.;
|
||||
QTest::newRow("C -tiny") << C << QString("-2e-324") << false << 0.;
|
||||
}
|
||||
|
||||
void tst_QLocale::stringToFloat()
|
||||
|
Loading…
Reference in New Issue
Block a user