|
|
|
|
|
by tzs
2309 days ago
|
|
> Or just work in floats and round as the last step That's not as easy to get right as one might like. Let's say we have an amount in dollars, represented as an IEEE 754 double, and a tax rate, also represented as a double. Let's assume that the amount is always some integer multiple of 0.01, and the tax rate is always some integer multiple of 0.00001. Let's say we want the tax in cents. A first try might be: unsigned long tax_in_cents(double subtotal, double rate)
{
return (unsigned long)round(subtotal * rate * 100);
}
(Doing tax in cents because C/C++ doesn't seem to have a standard variant of round() that lets you say to round to the nearest 0.01. It only rounds to integers).That will sometimes fail. The problem is it is rounding at the wrong place. It's logically rounding to the nearest multiple of 0.01, which is too crude. The rounding has to be much farther to the right. This will do the trick: unsigned long tax_in_cents(double amt, double rate)
{
const unsigned long M = 100 * 100000;
return (unsigned long)round((round(amt * rate * M) / (M/100)));
}
That will work for all rates from 0 to 1 that are integer multiple of 0.00001, and all amounts from 0 to 10000 that are integer multiples of 0.01, in all IEEE rounding modes. I've verified this via brute force. I'm not sure how high the amount can go before it breaks down.I'm not at all sure that if I had come across that first try in real life I would have noticed that it is not adequate. |
|