From: Tom Anderson on
On Sat, 8 May 2010, Roedy Green wrote:

> 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

--
I have often thought that the questions which we were unable to ask and
the speeches that we never had a chance to deliver were probably the
best ones. -- John Wilkinson MP, on Parliament
From: Arne Vajhøj on
On 09-05-2010 07:22, Tom Anderson wrote:
> On Sat, 8 May 2010, Roedy Green wrote:
>> 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.

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

From: Jim Janney on
Roedy Green <see_website(a)mindprod.com.invalid> writes:

> 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)

--
Jim Janney
From: Lew on
Arne Vajhøj wrote:
> 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>

Roedy?

--
Lew
From: Arne Vajhøj on
On 09-05-2010 12:49, Lew wrote:
> Arne Vajhøj wrote:
>> 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