diff options
-rw-r--r-- | src/qml/jsruntime/qv4numberobject.cpp | 38 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 17 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 16 |
3 files changed, 32 insertions, 39 deletions
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index d26e888069..13f6912371 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -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)); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 13244fdd95..424103cb08 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -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) diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index aaaaf09925..f849403cd8 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -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" |