Matlab和Numpy以及Python的'round`函数之间的差异

Ahm*_*sih 5 python matlab numerical numpy rounding

简化的问题

我可以让Numpy同意Matlab和Python round吗?

Matlab 2013a:

>> round(-0.5)
ans =
    -1
Run Code Online (Sandbox Code Playgroud)

Python(使用Numpy数组,或只是一个标量,相同的结果):

>>> import numpy
>>> round(numpy.array(-0.5))
-1.0
Run Code Online (Sandbox Code Playgroud)

Numpy,奇怪的是:

>>> import numpy
>>> numpy.round(numpy.array(-0.5))
-0
Run Code Online (Sandbox Code Playgroud)

圆形平台的这种差异是否依赖?

原始问题

Matlab附带一个包含一些音频数据的文件"handel.mat":

>> which handel.mat
C:\Program Files\MATLAB\R2013a\toolbox\matlab\audiovideo\handel.mat
>> load handel
>> soundsc(y) % play the short audio clip
Run Code Online (Sandbox Code Playgroud)

我想在Python中使用这些数据,所以我使用scipy.io.loadmat[1].具体来说,我想缩放音频的值以跨越16位有符号整数的整个范围,即,音频信号的最小值被映射到-2 ^ 15,最大的值被映射到2 ^ 15-1.在Matlab中执行此操作时,我感到惊讶的是给出了与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
Run Code Online (Sandbox Code Playgroud)

蟒蛇:

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)
Run Code Online (Sandbox Code Playgroud)

实际上有1231个样本(总共73113个),其中Python和Matlab有所不同.我认为我对我的类型很谨慎,但实际上,这里出现的类型错误的错误表面非常少:loadmat应该从MAT文件中推断出类型,并且int16在两个系统之间的差别不大.

添加interp/interp1dcommands 的输出的第一个元素都是-0.5(在Python和Matlab中将其打印到第100个小数位确认了这一点),但是Numpy(np.round)中的舍入产生0,而Matlab将其舍入为-1.这是Matlab舍入语义的问题吗?此外, Python的内置非Numpy roundfor -0.5给了我-1!Numpy和Python的round功能之间存在这种差异吗?Python round总是与Matlab相匹配吗?

Windows64,Matlab 8.1(2013a),Python 2.7.4.

[1] http://docs.scipy.org/doc/scipy/reference/generated/scipy.io.loadmat.html

Vee*_*rac 1

numpy.round,也称为numpy.around,四舍五入到最接近的半整数偶数值。这与平台无关,而是有目的的实现细节。

如果您想在不使用 Python 的情况下快速进行一轮,请参阅此答案

总结是,有一个依赖于平台的 hack 可以使用fesetroundvia设置舍入ctypes。来自帖子:

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
Run Code Online (Sandbox Code Playgroud)

  • 不,他们只是使用不同的方法。Numpy 使用半舍入到偶数,Python 使用半舍入到零。第一个对于统计更有用,第二个更通用。 (2认同)
  • @Veedrac:实际上,Python 的内置“round”从零开始*远离*。 (2认同)