Ошибка двойного округления в MongoDB с Group () - PullRequest
1 голос
/ 29 марта 2012

Я новичок в MongoDB и пробую некоторые основы, но это меня удивило.Полагаю, я неправильно понял некоторую базовую концепцию, но кто-нибудь может сказать мне, что здесь происходит?

Используя официальный диск MongoDB C #, я вставил 10,0000 этих документов в коллекцию БД под названием 'Lots'.'.

         // Insert some test data
         const double price = 29.99;
         var bsonDoc = new BsonDocument { 
            {"glossary", new BsonDocument {
                    {"title", "example glossary"},
                    {"GlossDiv", new BsonDocument {
                        {"title", "S"},
                        {"price", new BsonDouble(price)},
                ...
                /* full doc chunk removed here for brevity */
                ...
            };
            ...
                         const int numObjects = 10000;
         for (int i = 0; i < numObjects; i++)
             col.Insert(new BsonDocument(bsonDoc));

            ...

Я пробовал это в оболочке, потому что не верил тому, что видел в драйвере C #, но результат тот же;

дБ.lots.group ({key: {"glossary.GlossDiv.title": true}, уменьшите: function (obj, out) {out.total + = obj.glossary.GlossDiv.price;}, начальный: {total: 0}}) [{"glossary.GlossDiv.title": "S", "total": 299899.99999995757 }]

Исправьте меня, если я ошибаюсь, но не следует 29.99 *10000 == 299900 ?

1 Ответ

3 голосов
/ 29 марта 2012

Поправь меня, если я ошибаюсь, но не должен 29.99 * 10000 == 299900?

Ваши данные не содержали 29,99. Смотрите здесь:

const double price = 29.99;

Это устанавливает price равным значению double, которое ближайший к 29,99. Это , а не 29,99. Если быть точным, ваше значение равно 29,989999999999998436805981327779591083526611328125.

Это только косвенно связано с Mongo - это фундаментально для использования двоичной плавающей запятой. Если Mongo поддерживает decimal, вы должны использовать это для любых финансовых значений. Я не могу видеть что-то вроде BsonDecimal, что я и ожидал - если вы не можете этого сделать, вы можете вместо этого сохранить ваши значения как масштабированные целые числа - например хранение количества центов вместо количества долларов.

См. Мои статьи о двоичной с плавающей запятой и десятичной с плавающей запятой для получения дополнительной информации.

...