4 ms·
> Of course it is. The point of the computation is to get the correct result. Numerical analysis hints at whether your computation will give you the right answe
by kbenson 8y ago
> Of course it is. The point of the computation is to get the correct result. Numerical analysis hints at whether your computation will give you the right answer or not.
In this case, we're comparing a representation which is exact, compared to one which is approximate. The numerical analysis which you are quoting tells you how close (if not exact) your (approximate* representation is. It's irrelevant when compared to exact, because as long as the other benefits you gain (much larger and smaller numbers) aren't needed, that's all downside.
> Your system does not magically become 'safe by design' simply because you use ints everywhere, you still need to put in the extra work to make sure your numeric range is always sufficient—at which point you're doing numerical analysis, whether you choose to call it that or not.
You have to do that work with floating point numbers as well, you just also have to make sure there's not error that needs to be rounded. There is not advantage to floats here, but there is one less thing to worry about with integer values.
> repeatedly make untrue claims about FP calculations
I have made no untrue claims that I'm aware, and I haven't noted you pointing out a specific claim as untrue with evidence that I didn't later point out that you were misinterpreting me on. Please feel free to provide evidence though.
> then wave off the entire subbranch of CS that studies how numbers are represented on computers and how those calculations can go wrong as being entirely irrelevant.
As noted above, it's irrelevant when compared to a representation with no error of the same type. Please stop inflating my assertions to cover more than they directly claimed. This is a straw man argument, please stop.
> As soon as you actually do any 'complicated' math (take a square root or a log), your result is no longer exactly representable, because your results aren't decimals or even rationals, but irrationals.
Care must always be taken with moving between a real currency amount and an interim amount. It makes sense to switch representations at that point, and deal with the amount with a representation that is appropriate for partial values (floating point may be appropriate here). At the point it's stored again, it should be converted to an exact representation again. Partial cents are not valid amounts of currency to have, so it makes sense to deal with the difference before it is represented as a currency again.
> You're contradicting yourself here. All Excel does is 1) compute using floats (doubles) everywhere and 2) round the result before showing it.
I'm saying that Excel isn't only interested in representing currency. If they were, they may have chosen a different representation. Since their constraints are that they also need to be able to accurately represent 0.00001, they are going to choose the best hardware supported representation that support all their needs. That ends up being floating point. For a currency, quite a few of those requirements are no longer needed, so a different trade off is possible.
> That's exactly what I'm advocating. Whether you choose to wrap it into a special Numeric or Money class doesn't change your answer.
> Look, here's C#'s decimal class: https://docs.microsoft.com/en-us/dotnet/csharp/language-refe.. https://docs.microsoft.com/en-us/dotnet/csharp/language-refe....
> Must use some fancy arbitrary precision arithmetic right? No, it's just a floating point number—just a particularly wide (128-bit) type.
That's not all it is. It's decimal floating point, not binary floating point, meaning it can exactly represent all the base 10 values in it's range. That is fundamentally different than binary floating point, and the fact they chose this representation is what "makes it appropriate for financial and monetary calculations" in their words, illustrates my point.
- deleted 8y ago[deleted]
- smallnamespace 8y ago> At the point it's stored again, it should be converted to an exact representation again. Partial cents are not valid amounts of currency to have, so it makes sense to deal with the difference before it is represented as a currency again. Exact decimal representation doesn't prevent rounding errors from accumulating over a chain of computations because oftentimes the correct value cannot be represented as an exact decimal. Forcing it by repeatedly rounding to the nearest currency unit, which is what you're proposing above, compounds the problem by needlessly throwing away available precision. Simple example is paying interest on a bank account. If you insist on only storing account balances as an exact 2-digit decimal number, then any compound interest computation will quickly accumulate large errors, e.g.: // $100 in 'exact' integer form let float_balance = 10000 let rounded_balance = 10000 const daily_interest = 0.10 / 365 // 10% rate, compounded daily // Pay interest for 5 years for (let i = 0; i < 365 * 5; i++) { float_balance *= (1 + daily_interest) // This number goes into my DB, so I always round to the nearest penny!!! rounded_balance = Math.round(rounded_balance * (1 + daily_interest)) } console.log(Math.round(rounded_balance) / 100) // 163.74 console.log(Math.round(float_balance) / 100) // 164.86 console.log('missing interest: $' + Math.round(float_balance - rounded_balance) / 100) // missing interest: $1.12 'Exact representation' does not ensure that your computation remains free from roundoff error, and sometimes makes it much worse. If you really insist on 'only storing as many digits as there exist in the currency' in your DB, then you will systematically underpay interest to all your customers... in this example, you'll actually start shortchanging your customer in just a few weeks. It's your extra forced rounding to pennies that introduces the error: in reality, you really do owe fractional cents before they tick over into the next penny, even if you don't show it in the bank statement. The easiest way to solve the issue here is to store the account balances as floats, which keep track of the 'fractional pennies' which you claim are meaningless. Or forget about floats -- just use fixnums, but keep are the lower digits rather than discarding them upon storage. By the way, this is the whole point of numerical analysis — you cannot blindly assert that 'if my numerical representation is exact, then my computation will always be correct / minimize total errors'. Yes, the logic is simple and seductive. The conclusion is also completely, utterly, stupendously, insidiously wrong. I hope you don't actually work in a financial context, because this will bite you in the ass someday if you lean hard on it. I don't really like to appeal to authority, but it was literally my day job for a few years to make sure the numbers were right. Half my team were physics PhDs, and the rest were usually math PhDs or MFEs. We didn't use floats because we were sloppy, we used them because they typically were the most reliable way to get the most accurate result, in a domain where most numbers represented currency or money. Only when you are actually sending or receiving money from the outside world (e.g. on an invoice, wire transfer, or transaction) should you rounding to the nearest decimal, and at that point, it might be appropriate to use a decimal or fixnum type to exactly represent the monetary value that was actually moved, but again this is typically overkill since you can always just store the rounded amount as a float. This is safe because rounding is idempotent: round(round(float)) = round(float) But internal monetary calculations are best kept in the same type with enough extra precision to do computations, and floats are often the correct choice here, with no forced intermediate rounding. If you need 2 accurate decimal digits and you insist on using fixnums rather than floats, then you should be passing around at least micros ($1e-6).