Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do tax rates need to be stored as integers?

I understand that monetary values should be stored and processed as integers due to rounding error problems. That makes sense to me and I get it (I think).

But what about tax rates? Is there any reason a tax rate (not tax amount, tax rate, like 6.5 or 8.125) needs to be stored as an integer as opposed to a decimal?

And if I do store a tax rate as an integer, how do I apply the tax rate to the dollar amount in the transaction? If I do 10000 * 1.065 ($100.00 * 1.065) for a 6.5% tax rate, what would be the benefit of having stored that 6.5% in the database as 6500 as opposed to 6.500? I don't believe that multiplying or dividing a number by 100 one time is something that's susceptible to rounding errors.

Does it matter how I store tax rates?

like image 417
Jason Swett Avatar asked Oct 11 '25 23:10

Jason Swett


1 Answers

First, it's not that you shouldn't use decimals. It's that you shouldn't use floating point where you want to have an exact value. Not all decimals are floating point; see the decimal datatype in C# or java.math.BigDecimal in Java.

Second, powers of 10 are especially susceptible to weird floating point issues because the way that floating point is implemented results in infinitely repeating decimals for division by powers of 10. See this question. Here's a trivial example:

groovy:000> f = 0.1F // make a floating point number
===> 0.1
groovy:000> f * 100 
===> 10.000000149011612

This happens because the representation of 0.1 is a repeating decimal that gets truncated. Here the REPL lied, what is really in f isn't 0.1, it's 0.100000001490116119384765625.

You could round this and go on, there's an argument for doing that:

To resolve this issue, you need to provide appropriate rounding. With money this is easy as you know how many decimal places are appropriate and unless you have $70 trillion you won't get a rounding error large enough you cannot correct it.

But using BigDecimals:

groovy:000> d = new BigDecimal("0.1")
===> 0.1
groovy:000> d * 100
===> 10.0

Use a fixed point decimal so you know exactly what number you have. If your language doesn't have fixed decimals (like Javascript), you may have to fall back on integers.

like image 166
Nathan Hughes Avatar answered Oct 16 '25 13:10

Nathan Hughes