4 ms·
> No, I think all customers care about penny precision when you are talking about money they have or owe. That wasn't my personal experience working on a fixed
by smallnamespace 8y ago
> No, I think all customers care about penny precision when you are talking about money they have or owe.
That wasn't my personal experience working on a fixed income desk. We regularly interacted with CFOs and corporate treasurers and the 'bills' were in the millions. And why would they? As they say, 'penny wise, pound foolish'.
> No, you're generally not throwing out precision when you round in this case. You're throwing out error.
That's not always true from a numerical analysis standpoint. By the way, I highly recommend this old but still useful doc which goes through the math carefully:
https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html#1405 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.h...
Rounding can introduce up to 0.5 ulp (unit in the last place) of error, where ulp here is the precision that you round to. This is pretty easy to show:
let intSum = 0;
let floatSum = 0;
let roundedFloatSum = 0;
for (let i = 0; i < 100; i++) {
// Generate numbers up to 1000, with up to 3 decimals
const randInt = Math.floor(Math.random() * 100 * 1000);
const randFloat = randInt / 1000;
intSum += randInt; // Sum in exact precision, scaled by 1000
floatSum += randFloat; // Sum using full FP precision
// Sum while rounding to 2 decimals along the way
roundedFloatSum += randFloat;
roundedFloatSum = Math.round(roundedFloatSum * 100) / 100;
}
intSum /= 1000;
console.log(intSum, floatSum, roundedFloatSum);
console.log(Math.abs(intSum - floatSum), Math.abs(roundedFloatSum - intSum))
Here we're generating some 3-fig decimal numbers and summing them up, once in exact precision, once with floats, and once with intermediate rounding to the 2nd decimal place.
On the last run, this outputs:
5567.347 5567.347000000001 5567.39
9.094947017729282e-13 0.0430000000005748
'Rounding as you go' for your intermediate results here introduced an unnecessary 0.043 of absolute error.
Every guide to numerical analysis I've ever seen recommends keeping all calculations in the same format (whether fixnums or floats) all the way through, then only doing rounding at the very end, for this very reason.
In fact, we can prove that on reasonable accounting inputs and simple calculations, doing everything using doubles and then rounding at the very end gives you the _exact_ result.
Let's assume the numbers you're summing, multiplying, etc. remain bounded under <$1 mm, and you're manipulating at most 1 million of those numbers.
1. Doubles have 52-bits, or about 15 decimal digits of precision
2. Basic arithmetic operations (addition, subtraction, multiplication, division) introduce at most 0.5 ulp of error per operation. Using our assumptions, each decimal number is accurate to at least the billionth (9th digit) place, whereas we only need accuracy to the hundredths.
3. The cumulative error of a chain of a million operations, each with an error in the 9th digit place, can at most only affect the 3rd decimal digit. The 2nd decimal will always be correct
> No, you're generally not throwing out precision when you round in this case. You're throwing out error.
Floating point calculations round to the available precision after every operation. If introducing extraneous rounding to a much lower precision magically 'fixed' errors, then how could long floating point calculations themselves be inaccurate? In fact, there are algorithms that lower overall error by carefully shepherding the low-order digits, e.g. https://en.wikipedia.org/wiki/Kahan_summation_algorithm https://en.wikipedia.org/wiki/Kahan_summation_algorithm
Rounding is often appropriate if the rounded value is the actual source of truth, e.g. if, after some long sequence of calculations, you've told the customer that they have $10.15 in the bank, then you should try to store that value rather than the raw float result. Even that's pretty subtle though -- e.g. if their account balance is a result of interest payments, one can show that you will introduce more error in the total interest paid over time if you discard lower order digits rather than reusing them for the next interest calculation.
One last thing: When you hand your exact precision results to an accountant, auditor, or customer, Excel's a pretty common tool that they use for basically everything right? It must be sporting some fancy arbitrary precision or decimal machinery under the hood, right?
Nope, just floats all the way down! https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft_Excel https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft...
I think you should be strongly questioning your assumption that floats aren't 'good enough' if the very first thing every customer you interact with does is cast your results into a floats to do their own calcs.
- kbenson 8y ago> > No, you're generally not throwing out precision when you round in this case. You're throwing out error. > That's not always true from a numerical analysis standpoint. This isn't about numerical analysis, which is what you seem to not be getting. It's about the medium have specific attributes, and floats being incapable of perfectly representing the value. With respect to the currency being tracked, any difference smaller than one hundredth of a full unit (depending on currency) that results from simple addition or subtraction of accurate values is an error because it's not possible in reality. > 3. The cumulative error of a chain of a million operations, each with an error in the 9th digit place, can at most only affect the 3rd decimal digit. The 2nd decimal will always be correct Cumulative error is irrelevant. It only takes a single error that causes a value to be less than the correct value by a very small amount and then if there's any place where it exits the system without rounding, that error may be increased to a full minimum difference of the medium ($0.01 in this case). > If introducing extraneous rounding to a much lower precision magically 'fixed' errors, then how could long floating point calculations themselves be inaccurate? By nature of the actual thing being represented by a the floating point value. There is no point talking about floating point without talking about what it's representing. In this case, it's currency, which has very specific characteristics. You can argue that a sphere is the best container shape because it maximizes volume to surface area all you like, that doesn't mean it's the best container shape when what you are storing is shoe boxes. > Rounding is often appropriate if the rounded value is the actual source of truth Yes, nobody is arguing that you shouldn't round floats in this case. I'm arguing you shouldn't use floats so you don't have to round at all. > Excel's a pretty common tool that they use for basically everything right? It must be sporting some fancy arbitrary precision or decimal machinery under the hood, right? ... Nope, just floats all the way down! Excel is a system to represent values of all types. Their requirements necessitate an amount of flexibility that makes Floats a good choice. Even then, they will be handling all the rounding and representation automatically for you. When you use excel, you aren't using floats, you're using an excel numeric type which is implemented underneath using floats and some very specific behavior. The fact that it automatically deals with floating point errors and rounding is what makes it not a float. In the case we are discussing, the same requirements are not present. We don't have to worry about representing any conceivable value, just the ones allowed by the type. A float provides more flexibility than we need, and at the cost of error that needs to be cleaned up at all the edges of the system. Again, I ask you, why should we choose an underlying type that doesn't fit the needs as well as another option? In all aspects, integer containers either have a less problematic error case or do not suffer the same problem.