Dear all, I encountered the following puzzling behaviour of the modulo operator %: In [1]: import Numeric In [2]: print Numeric.__version__ 23.8 In [3]: x=Numeric.arange(10.0) In [4]: print x%4 [ 0. 1. 2. 3. 0. 1. 2. 3. 0. 1.] In [5]: print 3.0%4 3.0 In [6]: print (-x)%4 [-0. -1. -2. -3. -0. -1. -2. -3. -0. -1.] # <====== In [7]: print (-3.0)%4 # vs. 1.0 # <====== (OK) In [8]: print Numeric.fmod(x,4) [ 0. 1. 2. 3. 0. 1. 2. 3. 0. 1.] In [9]: print Numeric.fmod(-x,4) [-0. -1. -2. -3. -0. -1. -2. -3. -0. -1.] So it seems that for arrays % behaves like fmod! This seems in contrast to what one finds in the python 2.3 documentation: "5.6. Binary arithmetic operations" """The % (modulo) operator yields the remainder from the division of the first argument by the second. [...] The arguments may be floating point numbers, e.g., 3.14%0.7 equals 0.34 (since 3.14 equals 4*0.7 + 0.34.) The modulo operator always yields a result with the same sign as its second operand (or zero); the absolute value of the result is strictly smaller than the absolute value of the second operand.""" I am presently teaching a course on computational physics with python and the students have huge difficulties with % behaving differently for arrays and scalars. I am aware that (according to Kernighan/Ritchie) the C standard does not define the result of % when any of the operands is negative. So can someone help me: is the different behaviour of % for scalars and arrays a bug, a feature, or what should I tell my students ? ;-). Many thanks, Arnd P.S.: BTW: the documentation for fmod and remainder is pretty short on this: In [3]:fmod? Type: ufunc String Form: <ufunc 'fmod'> Namespace: Interactive Docstring: fmod(x,y) is remainder(x,y) In [4]:remainder? Type: ufunc String Form: <ufunc 'remainder'> Namespace: Interactive Docstring: returns remainder of division elementwise Are contributions of more detailed doc-strings welcome ? P.P.S.: for numarray one gets even less information: In [1]: import numarray In [2]: numarray.fmod? Type: _BinaryUFunc Base Class: <class 'numarray.ufunc._BinaryUFunc'> String Form: <UFunc: 'remainder'> Namespace: Interactive Docstring: Class for ufuncs with 2 input and 1 output arguments In [3]: numarray.remainder? Type: _BinaryUFunc Base Class: <class 'numarray.ufunc._BinaryUFunc'> String Form: <UFunc: 'remainder'> Namespace: Interactive Docstring: Class for ufuncs with 2 input and 1 output arguments In [4]: print numarray.__version__ 1.1.1 P^3.S: scipy's mod seems to be an alternative: In [1]: import scipy In [2]: scipy.mod? Type: function Base Class: <type 'function'> String Form: <function mod at 0x40383994> Namespace: Interactive File: /usr/lib/python2.3/site-packages/scipy_base/function_base.py Definition: scipy.mod(x, y) Docstring: x - y*floor(x/y) For numeric arrays, x % y has the same sign as x while mod(x,y) has the same sign as y. In [3]: x=-scipy.arange(10) In [4]: x%4 Out[4]: array([ 0, -1, -2, -3, 0, -1, -2, -3, 0, -1]) In [5]: scipy.mod(x,4) Out[5]: array([ 0., 3., 2., 1., 0., 3., 2., 1., 0., 3.]) In [6]: scipy.mod?? Type: function Base Class: <type 'function'> String Form: <function mod at 0x40383994> Namespace: Interactive File: /usr/lib/python2.3/site-packages/scipy_base/function_base.py Definition: scipy.mod(x, y) Source: def mod(x,y): """ x - y*floor(x/y) For numeric arrays, x % y has the same sign as x while mod(x,y) has the same sign as y. """ return x - y*Numeric.floor(x*1.0/y)
participants (1)
-
Arnd Baecker