0

As far as I've read, best practice with managing money in Javascript is to represent all values scaled to the lowest possible denomination (e.g. $12.45 is scaled by 100 and represented as 1245 in our code, not 12.45), and then round values to the nearest whole number when calculating.

However, we still run into problems when doing calculations on our values.

For example: a user pays $28.75, but uses a 30% discount.

We deal with this like so: Math.round(2875 * .7). But this calculates a result of 2012 (incorrect). This is because:

  • In real life, 2875 * .7 = 2012.5, which rounds to 2013
  • In Javascript, 2875 * .7 = 2012.4999999999998, which rounds to 2012

What is the best way of preventing this kind of error?

otajor
  • 953
  • 1
  • 7
  • 20
  • 1
    There are issues with floating values in JS. Instead, try `2875 * 70 / 100` – Rajesh Nov 29 '17 at 11:14
  • Possible duplicate of [How to deal with floating point number precision in JavaScript?](https://stackoverflow.com/questions/1458633/how-to-deal-with-floating-point-number-precision-in-javascript) – Razzildinho Nov 29 '17 at 11:15
  • "2012.5 ... rounds to 2013"? What is the rounding rule you are using and are you sure it is the right one? There are various rounding techniques. If it is the fair [banker's rounding](https://en.wikipedia.org/wiki/Rounding#Round_half_to_even), the rounded result should be 2012. In real financial applications, the rounding mode is sometimes specified by law - check your programing goal specifications. – chux - Reinstate Monica Nov 29 '17 at 14:04
  • Note that the default rounding mode used in [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754), would round 2012.5 to 2012. – chux - Reinstate Monica Nov 29 '17 at 14:12

1 Answers1

1

The problem here is not floating point but fixed precision. You can see this because the same problem occurs with integer arithmetic. Any fractions with integer arithmetic also result in errors.

The solution is that you need to design each operation correctly, with knowledge of exactly what it is doing. This is because it is impossible to correctly compute general mathematical operations with only fixed precision, regardless of whether it is fixed or floating. There is no general one-size-fits-all solution, so you must design solutions for your particular needs.

In the case of applying a discount, one approach is to use knowledge of the domain of discount values to scale the numbers by a factor that will avoid fractions until preparing the final result. For example, if all discounts are a whole number percentage (30%, 17%, etc., but not 33.33%), then you can mutiply by 100 to make them integers (30, 17,…) instead of fractions (.30, .17,…). Then multuply by the integer. At the end, divide by the multiplier (with rounding as desired).

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312