[Armin] > Thanks for the clarification. Yes, it makes sense that __mod__, > __divmod__ and __floordiv__ on float and decimal would eventually follow > the same path as for complex (where they make even less sense and > already raise a DeprecationWarning).
This truly has nothing to do with complex. All meanings for "mod" (whether in Python, IEEE-754, C89, C99, or IBM's proposed decimal standard) are instances of this mathematical schema: [1] x%y = x - R(x/y)*y by definition, where R(z) is a specific way of rounding z to an exact mathematical ("infinite precision") integer. For int, long, and float, Python uses R=floor (and again it's important to note that these are mathematical statements, not statements about computer arithmetic). For ints, longs, and (mathematical) reals, that's the usual "number-theoretic" definition of mod, as, e.g., given by Knuth: mod(x, y) = x - floor(x/y)*y It's the only definition of all those mentioned here that guarantees the result is non-negative when the modulus (y) is positive, and that's a very nice property for integers. It's /also/ the only definition off all those mentioned here where the exact mathematical result may /not/ be exactly representable as a computer float when x and y are computer floats. It's that last point that makes it a poor definition for working with computer floats: for any other plausible way of defining "mod", the exact result /is/ exactly representable as a computer float. That makes reasoning much easier, just as you don't have to think twice about seeing abs() or unary minus applied to a float. No information is lost, and you can rely on expected invariants like [2] 0 <= abs(x%y) < abs(y) if y != 0 and finite provided one of the non- R=floor definitions of mod is used for computer floats. For complex, Python uses R(z) = floor(real_part_of(z)). AFAICT, Python just made that up out of thin air. There are no known use cases, and it's bizarre. For example, [2] isn't even approximately reliable: >>> x = 5000 + 100j >>> y = 1j >>> x % y (5000+0j) >>> print abs(x%y), abs(y) 5000.0 1.0 In short, while Python "does something" for complex % complex, what it does seems more-than-less arbitrary. That's why it was deprecated years ago, and nobody complained. But for computer floats, there are ways to instantiate R in [1] that work fine, returning a result that is truly (exactly) congruent to x modulo y, even though x, y and the result are all computer floats. Two of those ways: The C89 fmod = C99 fmod = C99 integral "%" = IBM spec "remainder" picks R(z) = round z to the closest integer in the direction of 0. The C99 "remainder" = IBM spec "remainder-near" = IEEE-754 REM picks R(z) = round z to the nearest integer, or if z is exactly halfway between integers to the nearest even integer. This one has the nice property (for floats!) that [2] can be strengthened to: 0 <= abs(x%y) <= abs(y)/2 That's often useful for argument reduction of periodic functions, which is an important use case for a floating-point mod. You typically don't care about the sign of the result in that case, but do want the absolute value as small as possible. That's probably why this was the only definition standardized by 754. In contrast, I don't know of any use for complex %. _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com