Search code examples
floating-pointprecisioncurrencyfloating-accuracy

How to round micros?


In JavaScript, Python, and possibly other languages, if you round the value 37.305 to 2 decimal places, you get the wrong value:

Number(37.305).toFixed(2) => 37.30 // Should be 37.31

One solution to the precision problems when representing money is to use micros. That is, $1.00 => 1,000,000 micros.

My question is: how could I round the value representing $37.305 in micros (37305000) to 2 decimal places (where the result should be 37.31?


Solution

  • To round a representation (in micros) R to n decimal places (in the represented value):

    • Let m be 106−n. This gives us the position value where we round for n decimal places.
    • Let r be the residue of R modulo m. For example, when rounding 37305000 micros to two decimal places, m is 10000, and r is 5000.
    • Let s be 0 or m according to the desired rounding rule (which is not stated in the question). For example, for round-to-nearest, if r < m/2, let s be 0 (round down). If r > m/2, let s be m (round up). If r = m/2, use the desired rule for breaking ties. This might be to round up, to round down, or to round depending on the next higher digit of m. For example, if the rule is to round ties to even, examine the last digit of R/m truncated to an integer. If it is even, set s to 0. If it is odd, set s to m.
    • The desired rounded result is Rr+s.

    The above suffices for non-negative R. To support negative numbers, adjustments may be needed for selecting the residue and applying the rounding rule to select s. These are fairly simple but depend on what residue or remainder operations are convenient in the programming language being used and on what rounding rule is desired.