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)