Json writer, emit full precision for floating point Number types

Previously Qt JSON writer would only emit 6 digits of precision as this
is the default with the formatter.

However with testing against NodeJS JSON.stringify() this behavior is
inconsistent with the defacto standard JSON implementation and conveys
a loss of precision.

Change-Id: Ie1845a6e0ee0b4c05f63ec0062f372e891855f0b
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Darryl L. Miles 2013-02-10 09:02:00 +00:00 committed by The Qt Project
parent e2d614b6a9
commit 6348de8737
3 changed files with 55 additions and 2 deletions

View File

@ -63,6 +63,7 @@
#include <qnumeric.h>
#include <limits.h>
#include <limits>
QT_BEGIN_NAMESPACE

View File

@ -171,8 +171,8 @@ static void valueToJson(const QJsonPrivate::Base *b, const QJsonPrivate::Value &
break;
case QJsonValue::Double: {
const double d = v.toDouble(b);
if (qIsFinite(d))
json += QByteArray::number(d);
if (qIsFinite(d)) // +2 to format to ensure the expected precision
json += QByteArray::number(d, 'g', std::numeric_limits<double>::digits10 + 2); // ::digits10 is 15
else
json += "null"; // +INF || -INF || NaN (see RFC4627#section2.4)
break;

View File

@ -96,6 +96,7 @@ private Q_SLOTS:
void toJson();
void toJsonSillyNumericValues();
void toJsonLargeNumericValues();
void fromJson();
void fromJsonErrors();
void fromBinary();
@ -1110,6 +1111,57 @@ void tst_QtJson::toJsonSillyNumericValues()
QCOMPARE(json, expected);
}
void tst_QtJson::toJsonLargeNumericValues()
{
QJsonObject object;
QJsonArray array;
array.append(QJsonValue(1.234567)); // actual precision bug in Qt 5.0.0
array.append(QJsonValue(1.7976931348623157e+308)); // JS Number.MAX_VALUE
array.append(QJsonValue(5e-324)); // JS Number.MIN_VALUE
array.append(QJsonValue(std::numeric_limits<double>::min()));
array.append(QJsonValue(std::numeric_limits<double>::max()));
array.append(QJsonValue(std::numeric_limits<double>::epsilon()));
array.append(QJsonValue(std::numeric_limits<double>::denorm_min()));
array.append(QJsonValue(0.0));
array.append(QJsonValue(-std::numeric_limits<double>::min()));
array.append(QJsonValue(-std::numeric_limits<double>::max()));
array.append(QJsonValue(-std::numeric_limits<double>::epsilon()));
array.append(QJsonValue(-std::numeric_limits<double>::denorm_min()));
array.append(QJsonValue(-0.0));
object.insert("Array", array);
QByteArray json = QJsonDocument(object).toJson();
QByteArray expected =
"{\n"
" \"Array\": [\n"
" 1.234567,\n"
" 1.7976931348623157e+308,\n"
// ((4.9406564584124654e-324 == 5e-324) == true)
// I can only think JavaScript has a special formatter to
// emit this value for this IEEE754 bit pattern.
" 4.9406564584124654e-324,\n"
" 2.2250738585072014e-308,\n"
" 1.7976931348623157e+308,\n"
" 2.2204460492503131e-16,\n"
" 4.9406564584124654e-324,\n"
" 0,\n"
" -2.2250738585072014e-308,\n"
" -1.7976931348623157e+308,\n"
" -2.2204460492503131e-16,\n"
" -4.9406564584124654e-324,\n"
" 0\n"
" ]\n"
"}\n";
QCOMPARE(json, expected);
QJsonDocument doc;
doc.setObject(object);
json = doc.toJson();
QCOMPARE(json, expected);
}
void tst_QtJson::fromJson()
{
{