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