3

Note that I know there have been some other questions, but no real answer, on SO, regarding this issue.

So, what has been happening since the increment field value was implemented, is that when incrementing floating numbers, most of the time you'll get a dozen decimals instead of the actual number.

// incrementing 0, with 0.1, 11 times, returns 1.0999999999999999
Math.round( 1.0999999999999999 * 100 + Number.EPSILON ) / 100 

This returns the correct number ... so I wonder, can't this be implemented inside the method that deals with incrementing the actual value inside Firestore ?

Problem is, when I want to show numbers locale-based, I use the following:

number.toLocaleString( undefined, { minimumFractionDigits: 2 })

That would show 1.09 which is wrong, and customers get confused about their earnings.

What's to be done aside manipulating the data after receiving it client side?

Another side effect of this is that when using incrementing a big negative value, sometimes, for some reason, you get that +e inside your value in Firestore, and when fetching it server-side ( at least with the PHP Admin SDK ), the number ends up as a string, and not as an integer.

Eduard
  • 3,395
  • 8
  • 37
  • 62
  • I don't believe this is a duplicate question (as you're also asking about what mitigations firestore might do internally), but this should explain what is actually going on with the floating point math: https://stackoverflow.com/questions/588004/is-floating-point-math-broken and why it doesn't work as you expect. (FWIW, I would not expect firestore to mitigate this). This is one reason financial apps frequently use fixed point math. – robsiemb Oct 23 '19 at 14:58
  • 1
    If you are incrementing/decrementing financial decimals in Firestore, ie. taxes, you can consider converting values to pennies on the server-side. Just multiply '1.05' by 100 for the server increment. Then divide by 100 on the client-side when you go to show the customer. – Aaron Tomlinson May 14 '21 at 23:44

1 Answers1

2

According to the documentation, Cloud Firestore stores floating point numbers in IEEE 754 format. Please take some time to understand what this format implies. Basically, you can't count on floating point number to retain exactly the accuracy that you've specified, as the format can't possibly do that for some numbers. You can expect some small variation when the number is stored. A good summary of this type of behavior can already be found here on Stack Overflow:

If you must retain numerical accuracy, look into using a library that will help load and store numbers that have the accuracy you need. Pretty much all financial application will do something like this, as IEEE 754 can effectively lose data in order to compress the data down to a small size.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441