Double rounding error in MongoDB with Group()
-
27-05-2021 - |
Domanda
I'm new to MongoDB and trying out some fundamentals, but this astonished me. I'm guessing I misunderstand some core concept, but can anyone tell me what's going on here?
Using the official MongoDB C# drive, I've inserted 10,0000 of these docs into a db collection called '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));
...
I tried this in the shell because I didn't believe what I was seeing in the C# driver, but the result is the same;
db.lots.group({key:{"glossary.GlossDiv.title":true}, reduce:function(obj,out){out.total+=obj.glossary.GlossDiv.price;}, initial:{total:0} }) [ { "glossary.GlossDiv.title" : "S", "total" : 299899.99999995757 } ]
Correct me if I'm wrong but shouldn't 29.99*10000 == 299900 ?
Soluzione
Correct me if I'm wrong but shouldn't 29.99*10000 == 299900 ?
Your data didn't contain 29.99. Look here:
const double price = 29.99;
That sets price
equal to the double
value which is closest to 29.99. That's not 29.99. To be exact, your value is 29.989999999999998436805981327779591083526611328125.
This is only tangentially to do with Mongo - it's fundamental to using binary floating point. If Mongo supports decimal
, you should use that for any financial values instead. I can't see anything like BsonDecimal
which is what I'd have expected - if you can't do that, you may well want to store your values as scaled integers instead - e.g. storing the number of cents instead of the number of dollars.
See my articles on binary floating point and decimal floating point for more information.