Unify and fix number to string conversion with radix
Previously, the loop that generated the string could fail to terminate with certain numbers as input. Also, the algorithm was duplicated in two places. Change-Id: Ie2075148d931e7cfcedb5bcd23af61e2e8afc232 Fixes: QTBUG-73999 Reviewed-by: Robert Loehning <robert.loehning@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
cdb8eb988e
commit
b959074afb
|
@ -223,41 +223,9 @@ ReturnedValue NumberPrototype::method_toString(const FunctionObject *b, const Va
|
|||
return v4->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix").arg(radix));
|
||||
}
|
||||
|
||||
if (std::isnan(num)) {
|
||||
return Encode(v4->newString(QStringLiteral("NaN")));
|
||||
} else if (qt_is_inf(num)) {
|
||||
return Encode(v4->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity")));
|
||||
}
|
||||
|
||||
if (radix != 10) {
|
||||
QString str;
|
||||
bool negative = false;
|
||||
if (num < 0) {
|
||||
negative = true;
|
||||
num = -num;
|
||||
}
|
||||
double frac = num - std::floor(num);
|
||||
num = Value::toInteger(num);
|
||||
do {
|
||||
char c = (char)std::fmod(num, radix);
|
||||
c = (c < 10) ? (c + '0') : (c - 10 + 'a');
|
||||
str.prepend(QLatin1Char(c));
|
||||
num = std::floor(num / radix);
|
||||
} while (num != 0);
|
||||
if (frac != 0) {
|
||||
str.append(QLatin1Char('.'));
|
||||
do {
|
||||
frac = frac * radix;
|
||||
char c = (char)std::floor(frac);
|
||||
c = (c < 10) ? (c + '0') : (c - 10 + 'a');
|
||||
str.append(QLatin1Char(c));
|
||||
frac = frac - std::floor(frac);
|
||||
} while (frac != 0);
|
||||
}
|
||||
if (negative)
|
||||
str.prepend(QLatin1Char('-'));
|
||||
return Encode(v4->newString(str));
|
||||
}
|
||||
QString str;
|
||||
RuntimeHelpers::numberToString(&str, num, radix);
|
||||
return Encode(v4->newString(str));
|
||||
}
|
||||
|
||||
return Encode(Value::fromDouble(num).toString(v4));
|
||||
|
|
|
@ -298,13 +298,22 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
|
|||
|
||||
if (frac != 0) {
|
||||
result->append(QLatin1Char('.'));
|
||||
double magnitude = 1;
|
||||
double next = frac;
|
||||
do {
|
||||
frac = frac * radix;
|
||||
char c = (char)::floor(frac);
|
||||
next *= radix;
|
||||
const int floored = ::floor(next);
|
||||
char c = char(floored);
|
||||
c = (c < 10) ? (c + '0') : (c - 10 + 'a');
|
||||
result->append(QLatin1Char(c));
|
||||
frac = frac - ::floor(frac);
|
||||
} while (frac != 0);
|
||||
magnitude /= radix;
|
||||
frac -= double(floored) * magnitude;
|
||||
next -= double(floored);
|
||||
|
||||
// The next digit still makes a difference
|
||||
// if a value of "radix" for it would change frac.
|
||||
// Otherwise we've reached the limit of numerical precision.
|
||||
} while (frac > 0 && frac - magnitude != frac);
|
||||
}
|
||||
|
||||
if (negative)
|
||||
|
|
|
@ -362,6 +362,7 @@ private slots:
|
|||
void hugeObject();
|
||||
void templateStringTerminator();
|
||||
void arrayAndException();
|
||||
void numberToStringWithRadix();
|
||||
|
||||
private:
|
||||
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
|
||||
|
@ -8878,6 +8879,21 @@ void tst_qqmlecmascript::arrayAndException()
|
|||
QVERIFY(value.isError());
|
||||
}
|
||||
|
||||
void tst_qqmlecmascript::numberToStringWithRadix()
|
||||
{
|
||||
QJSEngine engine;
|
||||
{
|
||||
const QJSValue value = engine.evaluate(".5.toString(5)");
|
||||
QVERIFY(!value.isError());
|
||||
QVERIFY(value.toString().startsWith("0.2222222222"));
|
||||
}
|
||||
{
|
||||
const QJSValue value = engine.evaluate(".05.toString(5)");
|
||||
QVERIFY(!value.isError());
|
||||
QVERIFY(value.toString().startsWith("0.01111111111"));
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmlecmascript)
|
||||
|
||||
#include "tst_qqmlecmascript.moc"
|
||||
|
|
Loading…
Reference in New Issue