2013-05-31 2 views
0

У меня есть сайт электронной коммерции с цифровыми продуктами (без инвентаря, только функции отчетности).mongoDB странные результаты после математических операций

И иногда я получаю странные результаты с клиентами остатки на счетах:

например у клиента есть 30 на его балансе и после покупки продукта за 29,95 я вижу в админ-панели, что его остаток 0.050000000000001 не 0.05, как ожидалось.

Или иногда я вижу 520.949999999999 вместо 520.95.

Почему это происходит?

Сайт работает на PHP и взаимодействует с Монго хотя YiiMongoDbSuite

+0

Не может быть связано с http://stackoverflow.com/questions/588004/is-javascripts-floating-point-math-broken – Orangepill

+0

Нет, если он не использует JS для вставки, то это не связано, вы форматирование номеров перед их сохранением? Если нет, это на самом деле причина; вам нужно сказать PHP, как вы хотите их сохранить. – Sammaye

+0

Я смутил yii с yui. – Orangepill

ответ

0

Использование двойной или поплавки не рекомендуется для любого вида валюты по математике, где точные расчеты имеют жизненно важное значение. This question подробно описывает эту тему. Лучшей альтернативой было бы отслеживать эти значения целыми числами, где 1 является наименьшей единицей валюты (в данном случае, в данном случае) и работает оттуда.

В зависимости от того, как вы делаете математику с плавающей точки (сохранение точных значений, результат вычитания, или с помощью оператора $inc), вы, вероятно, в конечном итоге со смешанными результатами:

> db.foo.insert({ _id: 'value', x: 0.05 }) 
> db.foo.insert({ _id: 'subtraction', x: 30 - 29.95 }) 
> db.foo.insert({ _id: 'decrement', x: 30 }) 
> db.foo.update({ _id: 'decrement' }, { $inc: { x: -29.95 }}) 
> db.foo.find() 
{ "_id" : "value", "x" : 0.05 } 
{ "_id" : "subtraction", "x" : 0.05000000000000071 } 
{ "_id" : "decrement", "x" : 0.05000000000000071 } 

Если вы используете использование плавающих точек и выполняете математику в PHP (т. е. не используете $inc в запросе на обновление), рассмотрите возможность использования round() с заданной точностью, что должно привести к результатам, аналогичным первому приведенному выше примеру. number_format() отлично подходит для отображения, но будьте осторожны, чтобы не использовать его при обновлении документа, так как он возвращает строку.