Take care, it's Floating Point Arithmetic
thelimbeck.wordpress.com
thelimbeck.wordpress.com
(Standards-conformant) floating-point addition and multiplication absolutely are commutative up to NaN encodings. This follows trivially from the fact that they are basic operations (and hence correctly rounded), combined with the fact that the corresponding operations on real numbers are commutative.
Feel free to ask other questions about floating-point superstitions, and I’ll do my best.
The rest of the article is great, and really hits at how to deal with mixing floating point arithmetic with really small and really large numbers. Start small so the partial sum remains as accurately as possible, since any exponential corrections will result in shedding some significant digits. Then again, if this is the point at which you start nit-picking about commutativity, you should probably use a higher precision floating point representation, or look towards "infinite" precision numerical libraries.
EDIT: found it http://en.wikipedia.org/wiki/Kahan_summation_algorithm
[1] www-2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps
Thanks.
http://blogs.msdn.com/b/ericlippert/archive/2005/01/20/fun-w...
The first answer here: http://stackoverflow.com/questions/5007400/is-multiplication...
http://boards.straightdope.com/sdmb/showthread.php?t=535330
Page 4 of http://www.cs.uiuc.edu/class/fa07/cs498mjg/notes/floating-po...
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.ht...
> Floating point arithmetic is not arithmetic we learnt in school.
This is certainly true ... > It's not commutative ...
Hmm. Is it not commutative?But if you do: 2^-25 + 2^-25 ... (2^25 times) + 1 it will give you 2.
A more simplified version of what you say is that:
1 + x + x + x + x != x + x + x + x + 1
when x is suitably small. But to convert one into the other requires both associativity and commutativity: (((1 + x) + x) + x) + x
-> (((x + 1) + x) + x) + x using commutativity
-> ((x + (1 + x)) + x) + x using associativity
-> ((x + (x + 1)) + x) + x using commutativity
-> (((x + x) + 1) + x) + x using associativity
-> ((x + x) + (1 + x)) + x using associativity
-> ((x + x) + (x + 1)) + x using commutativity
-> (((x + x) + x) + 1) + x using associativity
-> ((x + x) + x) + (1 + x) using associativity
-> ((x + x) + x) + (x + 1) using commutativity
-> (((x + x) + x) + x) + 1 using associativity
If you write Y as x+x+x+x, then 1+Y == Y+1.It's the associativity that fails.
I'd like to learn more, but searches are failing to turn up anything specific and detailed. In particular, the usual reference - http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.ht... - doesn't seem to mention commutativity.
Thanks.
"The normal comparison operations however treat NaNs as unordered and compare −0 and +0 as equal."
http://newsgroups.derkeiler.com/Archive/Comp/comp.lang.funct...
Oh, of course: for non-NaNs, correctly implemented IEEE
arithmetic is "exactly rounded". So addition of non-NaNs
must be commutative for any given rounding rule, ..."Python 2.7.2 (default, Jun 20 2012, 16:23:33) [GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin"
http://i.imgur.com/2B4T0nn.png
the first 2 outputs are the same, demonstrating that commutative property holds. the next pair of outputs seems to indicate that commutative is failing (but this may be associative in the background). The third pair of outputs reveals explicitly that associative fails. So it's the 2nd pair that is probably causing the confusion in understanding since a lack of parenthesis seems to imply that we aren't looking at some sort of associativity when we really are.
Now, if we go to code bin and run the same test:
There is no discrepancy, and that's because of rounding.
Now it is clear to me the confusion, and I hope that helps illustrate some of the issues for others!
Obviously, it's a known old issue, since the IEEE folks point out that their standard produces an error (NaN) to indicate data loss if you add things with too small and too big a magnitude together. Not all floating point is IEEE, some implementations just give you their best estimate, throwing away the little bits.
And, please, DON'T use floating point to work with currency, ever. http://roboprogs.com/devel/2010.02.html
(2) Adding values of varying magnitude does not produce NaN results in IEEE-754 arithmetic. The only addition that produces a NaN is +Infinity + -Infinity, which have equal magnitude.
Go with what I know, then: add the small numbers first (sort the addends in increasing absolute magnitude)
Natural := Zero | Succ of Natural
Integer := Positive of Natural | Negative of Natural
## Negative(0) |=> error in constructor
Rational := {num:Integer, denom:Integer}
## denom <= 0 || gcd(num, denom) != 1 |=> error in const.
Real := (Rational, () => Real)
## Lazy Cauchy Sequence-- user is responsible for convergence.
Complex := {re:Real, im:Real}
Quaternion := {re: Real, i:Real, j:Real, k:Real}
Octonion := ... ## NOW we can use FP because octonions
## are non-associative anyway!
Example usage (still pseudocode): $ realMath.sqrt(Positive(Succ(Succ(Zero)))
-> (Rational{num = Positive(Succ(Succ(Zero)))
denom = Positive(Succ(Zero))},
#<fn () => Real@f73d>) ## function produces (3/2, fn)
## Of course, with a proper type system, we'd never let sqrt return a Real! Sorry.
## It should be List[Complex], like so.
$ realMath.sqrt(Negative(Succ(Zero))
-> Cons(Complex{re = (Rational{num = Positive(Zero),
denom = Positive(Succ(Zero))},
#<fn ...>,
im = (Rational{num = Negative(Succ(Zero)),
denom = Positive(Succ(Zero))},
#<fn ...>)},
Cons(Complex{...}, ## The other root...
Nil))Next you'll be telling me that different polynomials in P matter, like O(n^27) is too slow or at least requires attention to constants and scale.
This construction also solves the divide-by-zero problem very elegantly. When we promote Natural Zero to Real, we make sure that it's something like:
(1, λ_:Unit. (1/2, λ_:Unit. (1/3, λ...)))
This makes division by zero a legal operation (pointwise division of sequences) if we extend our tolerance to sequences without the Cauchy property (and why not? It's just bits).Also, comparison is also undecideable, and that's pretty certainly an operation you want to have at times.
For strict equality, if two reals have the same symbolic simplification, they are equal, otherwise, not. For greater than or less than comparisons (on possibly a "tolerant" form of equality), but if you can't resolve the comparison symbolicly using a set of guaranteed-to-terminate operations, you can resort to calculating floating point approximations of the reals and then comparing those. You might even have "exact" comparison operations that throw an exception if they can't be resolved without resorting to floating point approximations, and "tolerant" comparisons that allow approximations.
There are some cases where your system provides better results, comparing two equal irrational numbers for example, but I can't think of a use case for that.
I was trying to (provide a user option to) rule out "unknown" as an answer. Though, you can do that with your method, too (with the same kind of risk of error that you'd have with resort to floating point approximation, so in that regard its no worse than my method.)
> There are some cases where your system provides better results, comparing two equal irrational numbers for example, but I can't think of a use case for that.
I suspect that doing symbolic calculations with a standard set of reduction rules may be more efficient over multiple manipulations involving irrational numbers than manipulating them in lazy Cauchy sequence form, at least when you actually need at some point to do comparisons or numerical approximations (and, certainly, for display, either a more traditional symbolic form or a numerical approximation is going to be preferred to any kind of direct representation of a lazy Cauchy sequence.)
But that's just an intuition, and certainly not in an area that I am an expert in.
Of course.
> Also, comparison is also undecideable, and that's pretty certainly an operation you want to have at times.
Why?
More screwy are the sedenions (16 basis vectors) which also have zero divisors (i.e. xy = 0 does not imply x = 0 or y = 0).