Computing sales taxes

R

Roedy Green

If you use double to compute sales taxes, and round to the nearest
penny, there is a gotcha. You are supposed to round a precise half
penny up. This won't work properly for percentage like 6% (0.06) (of
$0.75) which is not precise in binary.

There a number of ways to avoid problem. Which would you use?
 
A

Arne Vajhøj

If you use double to compute sales taxes, and round to the nearest
penny, there is a gotcha. You are supposed to round a precise half
penny up. This won't work properly for percentage like 6% (0.06) (of
$0.75) which is not precise in binary.

There a number of ways to avoid problem. Which would you use?

BigDecimal should be able to mimic the rules out of the box.

Integers (long or int) could be made to mimic the rules.

And as a general rule there is death penalty for using
floating point for amounts.

Arne
 
L

Lew

If you use double to compute sales taxes, and round to the nearest
penny, there is a gotcha. You are supposed to round a precise half
penny up. This won't work properly for percentage like 6% (0.06) (of
$0.75) which is not precise in binary.

In what jurisdictions? That's not the rule in the parts of the U.S. with
which I'm familiar. Sales tax rounds up, not to the nearest.
There a number of ways to avoid problem. Which would you use?

I'd conform to the law.
 
A

Arne Vajhøj

In what jurisdictions? That's not the rule in the parts of the U.S. with
which I'm familiar. Sales tax rounds up, not to the nearest.

Give that Roedy is Canadian then I would assume Canada.
I'd conform to the law.

And use something else than double.

Arne
 
A

Arved Sandstrom

Lew said:
In what jurisdictions? That's not the rule in the parts of the U.S.
with which I'm familiar. Sales tax rounds up, not to the nearest.


I'd conform to the law.

I'd use software that someone else wrote who had lots more time to
devote to the problem of sales tax arithmetic legalities than I do.

AHS
 
T

Tom Anderson

If you use double to compute sales taxes, and round to the nearest
penny, there is a gotcha. You are supposed to round a precise half
penny up. This won't work properly for percentage like 6% (0.06) (of
$0.75) which is not precise in binary.

There a number of ways to avoid problem. Which would you use?

I'd start off working in thousandths-of-a-penny using integers (or longs
if i thought i might have to deal with amounts above 20 000 dollars).
Multiplying by 6% looks like:

int salesTaxInPercent = 6;
int taxableAmount = ...;
int tax = (salesTaxInPercent * taxableAmount) / 100;

If that got awkward (and it would, after about three minutes), i'd wrap
all amounts in an Amount class that hides all the storage and scaling and
so on. When that in turn got awkward, i'd switch to using BigDecimal
inside the Amount class.

My gut feeling is to keep away from BigDecimal as far as possible, because
it adds a lot of complexity you don't need for this. That feeling could
well be wrong.

tom
 
A

Arved Sandstrom

Tom said:
I'd start off working in thousandths-of-a-penny using integers (or longs
if i thought i might have to deal with amounts above 20 000 dollars).
Multiplying by 6% looks like:

int salesTaxInPercent = 6;
int taxableAmount = ...;
int tax = (salesTaxInPercent * taxableAmount) / 100;

If that got awkward (and it would, after about three minutes), i'd wrap
all amounts in an Amount class that hides all the storage and scaling
and so on. When that in turn got awkward, i'd switch to using BigDecimal
inside the Amount class.

My gut feeling is to keep away from BigDecimal as far as possible,
because it adds a lot of complexity you don't need for this. That
feeling could well be wrong.

tom
I'm the other way - I'd go to BigDecimal right away. Like I said
already, I wouldn't tackle this problem at all, because presumably
thousands of North American vendors already have. But if I had no choice
about tackling this problem, I'd have no qualms about using BigDecimal -
let someone else dick around with the rounding rules and the scaling. My
clients don't pay me nice hourly rates so I can waste time
re-implementing something as basic as this.

I think the real answer here lies in who you answer to. If your time is
your own and it strikes your fancy to re-invent the wheel, I'd go with
Tom's middle suggestion.

AHS
 
A

Arne Vajhøj

I'd start off working in thousandths-of-a-penny using integers (or longs
if i thought i might have to deal with amounts above 20 000 dollars).
Multiplying by 6% looks like:

int salesTaxInPercent = 6;
int taxableAmount = ...;
int tax = (salesTaxInPercent * taxableAmount) / 100;

If that got awkward (and it would, after about three minutes), i'd wrap
all amounts in an Amount class that hides all the storage and scaling
and so on. When that in turn got awkward, i'd switch to using BigDecimal
inside the Amount class.

My gut feeling is to keep away from BigDecimal as far as possible,
because it adds a lot of complexity you don't need for this. That
feeling could well be wrong.

BigDecimal is basicly a wrapped BigInteger with a bunch of
already implemented rounding rules.

Including ROUND_HALF_UP which seems to be what Roedy wants.

Arne
 
J

Jim Janney

Roedy Green said:
If you use double to compute sales taxes, and round to the nearest
penny, there is a gotcha. You are supposed to round a precise half
penny up. This won't work properly for percentage like 6% (0.06) (of
$0.75) which is not precise in binary.

There a number of ways to avoid problem. Which would you use?

Use BigDecimal for anything involving money. I've heard the excuses
for using double and they're all lame. And whatever you do, don't write

new BigDecimal(0.06)
 
A

Arne Vajhøj

Arne said:
BigDecimal is basic[al]ly a wrapped BigInteger with a bunch of
already implemented rounding rules.

Including ROUND_HALF_UP which seems to be what Roedy wants.

I wonder why he doesn't want accounting rounding.
<http://java.sun.com/javase/6/docs/api/java/math/RoundingMode.html#HALF_EVEN>

I don't know about Canada. Maybe Canada does stuff like that the US way.
Or maybe not.

In other parts of the world the HALF_EVEN is a "rounding error"
in software made in the US.

It is not a universal rule.

Arne
 
A

Andreas Leitgeb

Jim Janney said:
Use BigDecimal for anything involving money. I've heard the excuses
for using double and they're all lame. And whatever you do, don't write
new BigDecimal(0.06)

nor (of course) new BigDecimal(1./100) which is the same bad.

No matter how much the lack of overloaded operators for BigDecimal
may tempt one to do such things...
 
J

Jeffrey H. Coffield

Arne said:
BigDecimal should be able to mimic the rules out of the box.

Integers (long or int) could be made to mimic the rules.

And as a general rule there is death penalty for using
floating point for amounts.

Arne

There are systems that I maintain that were developed on 16 bit
minicomputers (DEC PDP-11/70) that used doubles for amounts but the
amounts were always in pennies, not dollars, so every amount was always
a whole number.

Jeff Coffield
 
R

Roedy Green

I'm the other way - I'd go to BigDecimal right away. Like I said
already, I wouldn't tackle this problem at all, because presumably
thousands of North American vendors already have.

I already tackled it, released the program years ago but only
recently discovered this failing. To my knowledge, my solution is the
only free one.

It is a horrible sort of app to write. I wish I had never started it.
It requires collecting data that hard to find, badly formatted, not
designed to be computer readable, constantly changing.

Collecting data is enough to make one vote for the Tea Party. Yet
American law theoretically requires every vendor to know it all.
It is insane. There are so many simpler ways to collect taxes.
 
A

Arne Vajhøj

There are systems that I maintain that were developed on 16 bit
minicomputers (DEC PDP-11/70) that used doubles for amounts but the
amounts were always in pennies, not dollars, so every amount was always
a whole number.

Don't worry I will not go and find my executioners axe.

:)

Two notes:
- this sound not really as being floating point but using
floating point as integers because no sufficiently big
integer were available
- I believe that some PDP-11's had a socalled "Commercial
Instruction Set" to handle this better

Arne
 
A

Arne Vajhøj

I already tackled it, released the program years ago but only
recently discovered this failing. To my knowledge, my solution is the
only free one.

I am surprised that you have not gotten into trouble with
floating point earlier.

And using BigDecimal instead of double is free (for license fees).

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top