If you do, in fact, need to worry about floating point error, then there is not some magical "it will never happen if you have this much precision and use this neat algorithm". Heck, even fixed/decimal/rational numbers aren't perfect solutions, they just make it easier to tell if you're staying within your precision.
Without infinite storage, you can't retain infinite precision, so the only real question is how much error you are willing to tolerate. And that depends very much on what you're doing - I can tolerate a lot more error in rolls on a MMO than in my bank account balance...
Yes. Similarly, if you design something with total disregard to optimization, it will likely need optimization.
YAGNI is a prediction, not a rule. Just like premature optimization, alternatives to floating point - or using longer floating point types - have real costs, which must be balanced against the needed precision.
Well, his final example suggests otherwise, but I kind of suspect that there must be something else going on there (that I'm too lazy to try to track down). Still, while fixing most floating point errors seem like rearranging the deck chairs on the titanic, if there's one algorithm that's 99.999% accurate and another that's only 99.9% accurate, might as well use and be aware of the more accurate one.
The error in the 'Variance calculated using Statistics::Descriptive' is ~0.0002% of the mean (and of each value).
As the OP says: "One saving grace of the real world is the fact that a given variable is unlikely to contain values with such an extreme range"
My point is that 99.999% algorithm is going to have a cost over the 99.9% algorithm (more complex code, more resource usage), and depending on what you're doing, you may have to consider that cost.
double fsum(const double *p, size_t n) {
size_t i;
double s;
for (s = i = 0; i < n; ++i) s += p[i];
return s;
}
Add one line of code and it not only becomes numerically stable but benchmarks faster too.
double fsum(const double *p, size_t n) {
size_t i;
double s;
if (n > 8) return fsum(p, n / 2) + fsum(p + n / 2, n - n / 2);
for (s = i = 0; i < n; ++i) s += p[i];
return s;
}
Losers always whine about how their laziness and ignorance is a calculated tradeoff.
What we need to consider is that sometimes there is no tradeoff.
That depends to an extreme degree on your environment, your language, your compiler... etc. What you need to consider is that tradeoffs have two sides.
Because it reduces worst case roundoff errors from being linear to logarithmic. Why is that the case? Best intuitive explanation I can think of is that floating point behaves more like VHS than DVD. If you wanted to bootleg a thousand copies of Titanic, then would you have each copy be made from the previous copy? No. It'd look terrible. You would instead have a stack of VCRs where the copies could be made in a hierarchical way that minimizes the critical path of copies. The overall number of operations may be the same, but if we consider that errors get worse the more errorful something becomes then it should be simple to understand why divide and conquer improves numerical stability.
If you do, in fact, need to worry about floating point error, then there is not some magical "it will never happen if you have this much precision and use this neat algorithm". Heck, even fixed/decimal/rational numbers aren't perfect solutions, they just make it easier to tell if you're staying within your precision.
Without infinite storage, you can't retain infinite precision, so the only real question is how much error you are willing to tolerate. And that depends very much on what you're doing - I can tolerate a lot more error in rolls on a MMO than in my bank account balance...