0

I have an e-commerce site with digital products (no inventory, only reporting features).

And sometimes i get weird results with customers account balances:

e.g. customer has 30 on his balance and after purchasing a product for 29.95 i see in admin panel that his balance is 0.050000000000001 not 0.05 as expected.

Or sometimes i see 520.949999999999 instead of 520.95.

Why is this happening?

Site runs on PHP and interacts with mongo though YiiMongoDbSuite

rinchik
  • 2,642
  • 8
  • 29
  • 46
  • Could it be related to http://stackoverflow.com/questions/588004/is-javascripts-floating-point-math-broken – Orangepill May 31 '13 at 16:43
  • No, if he is not using JS to insert then that is not related, are you formatting the numbers before resaving them? If not then that is actually the reason; you need to tell PHP how you wanna save them – Sammaye May 31 '13 at 16:44
  • I was confusing yii with yui. – Orangepill May 31 '13 at 16:47
  • @Sammaye I just do something like `$userCollection->balance -= 29.95; $userCollection->save()`. Which should pretty much do the trick. But it doesn't. – rinchik May 31 '13 at 16:55
  • 3
    yea that won't, PHP can change the precision to what it wants, use `number_format` – Sammaye May 31 '13 at 16:59

1 Answers1

0

Using double or floats is not advisable for any sort of currency math where precise calculations are vital. This question goes into great detail on the subject. A better alternative would be to track these values with integers, where 1 is the smallest unit of currency (cent in this case), and work from there.

Depending on how you do the math on floating points (saving exact values, the result of subtraction, or using the $inc operator), you're likely to end up with mixed results:

> 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 }

If you're set on using floating points and doing the math in PHP (i.e. not using $inc in the update query), consider using round() with a set precision, which should yield results similar to the first example above. number_format() is fine for display, but be careful not to use it when updating the document, since it returns a string.

Community
  • 1
  • 1
jmikola
  • 6,892
  • 1
  • 31
  • 61