Can I make Numpy agree with Matlab and Python's round?
Matlab 2013a:
>> round(-0.5)
ans =
    -1
Python (using a Numpy array, or just a scalar, same result):
>>> import numpy
>>> round(numpy.array(-0.5))
-1.0
Numpy, the odd one out:
>>> import numpy
>>> numpy.round(numpy.array(-0.5))
-0
Is this difference in round platform dependent?
Matlab comes with a file "handel.mat" containing some audio data:
>> which handel.mat
C:\Program Files\MATLAB\R2013a\toolbox\matlab\audiovideo\handel.mat
>> load handel
>> soundsc(y) % play the short audio clip
I want to work with this data in Python so I use scipy.io.loadmat [1]. Specifically, I want to scale the audio's values to span the entire range of 16-bit signed integer, i.e., the smallest value of the audio signal gets mapped to -2^15 and the largest one to 2^15-1. I was surprised when doing this in Matlab gave me different results than Python:
Matlab:
>> load handel
>> int16(round(interp1([min(y), max(y)], [-2^15, 2^15-1], y(1:10))))
ans =
     -1              %%% <-- Different from Python
   -253
  -3074
  -1277
    252
   1560
    772
  -1025
  -1277
  -3074
Python:
In [1]: import numpy as np
In [2]: import scipy.io as io
In [3]: mat = io.loadmat('handel.mat')
In [4]: np.int16(np.round(np.interp(mat['y'][:10], [mat['y'].min(), mat['y'].max()], [-2.0**15, 2.0**15-1.0])))
Out[4]:
array([[    0],      ### <-- Different from Matlab
       [ -253],
       [-3074],
       [-1277],
       [  252],
       [ 1560],
       [  772],
       [-1025],
       [-1277],
       [-3074]], dtype=int16)
There are actually 1231 samples (out of 73113 total) where the Python and Matlab differ. I think I'm being careful with my types, but really, there's very little error surface for type bugs to creep in here: loadmat should infer the types from the MAT file, and int16 can't differ that much between the two systems.
Added The first element of the output of the interp/interp1d commands are both -0.5 (printing it to the 100th decimal place in both Python and Matlab confirms this), but rounding in Numpy (np.round) yields 0, while Matlab rounds it to -1. Is this a matter of Matlab rounding semantics? Furthermore Python's built-in non-Numpy round for -0.5 gives me -1! Whence this difference between Numpy's and Python's round functions? And will Python's round always match Matlab's?
Windows64, Matlab 8.1 (2013a), Python 2.7.4.
[1] http://docs.scipy.org/doc/scipy/reference/generated/scipy.io.loadmat.html
I think you can take advantage of numpy.vectorize to create a custom numpy round function using standard python round function:
>>> import numpy as np
>>> myround = np.vectorize(lambda x: round(x))
>>> a = np.array([-0.5, 0.5, -1.5, 1.5, -2.5, 2.5, 3.5, -3.5])
>>> print myround(a)
 [-1.  1. -2.  2. -3.  3.  4. -4.]
Which is the same result that shows Matlab:
>> a = [-1.  1. -2.  2. -3.  3.  4. -4.];
>> round(a)
 ans =
    -1     1    -2     2    -3     3     4    -4
                        numpy.round, also known as numpy.around, rounds to the nearest even value for half-integers. This is not platform dependent, but a purposeful implementation detail.
If you wish to have a quick round without using Python, see this answer.
The summary is that there's a platform dependant hack to set rounding using fesetround via ctypes. From the post:
import numpy as np
import ctypes
FE_TONEAREST = 0x0000
FE_DOWNWARD = 0x0400
FE_UPWARD = 0x0800
FE_TOWARDZERO = 0x0c00
libc = ctypes.CDLL('libc.dylib')
v = 1. / (1<<23)
print repr(np.float32(1+v) - np.float32(v/2)) # prints 1.0
libc.fesetround(FE_UPWARD)
print repr(np.float32(1+v) - np.float32(v/2)) # prints 1.0000002
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With