简体   繁体   English

numpy或python中的等效matlab函数mod

[英]Equivalent matlab function mod in numpy or python

I was converting some codes from Matlab to Python. 我正在将一些代码从Matlab转换为Python。

In matlab there is the function mod which gives the modulo operation. 在matlab中有函数mod ,它给出了模运算。

For example the following example shows different results between the matlab mod and the equivalent numpy remainder operation: 例如,以下示例显示了matlab mod和等效numpy remainder操作之间的不同结果:

Matlab: Matlab的:

>> mod(6, 0.05)

ans =

     0

Numpy: NumPy的:

np.remainder(6, 0.05) 
0.04999999999999967

np.mod(6, 0.05)
0.04999999999999967

Python modulus operator gives the same results as numpy. Python模运算符给出与numpy相同的结果。

6%0.05
0.04999999999999967

Is there anything in python which gives the same mod operation as the one in Matlab? python中有没有提供与Matlab相同的mod操作? preferably can be operated on numpy 2d/3d arrays. 优选地,可以在numpy 2d / 3d阵列上操作。

numpy documentation says that numpy.mod is equivalent to matlab mod . numpy 文档numpy.mod相当于matlab mod

This is the core of the problem, in python: 这是问题的核心,在python中:

>>> 6/0.05 == 120
True

>>> 6//0.05 == 120  # this is 119 instead
False

The floating-point result of 6/0.05 is close enough to 120 (ie within the resolution of double precision) that it gets rounded to 120.0. 6/0.05的浮点结果足够接近120(即在双精度的分辨率内),它被舍入到120.0。 However, it's ever so slightly smaller than 120, so explicit floor division will truncate that number to 119 before it could be normalized to 120.0. 但是,它比120略小,因此明确的分区将在将其标准化为120.0之前将该数字截断为119。

Some proof: 一些证据:

>>> from decimal import Decimal
... print(6/Decimal(0.05))  # exactly approximate
... print(6/Decimal('0.05'))  # exact
119.9999999999999933386618522
1.2E+2

The first number is what you'd first get with 6/0.05 , but the number 119.9999999999999933386618522 gets rounded to the nearest number representable with double precision, and this is 120. One can easily prove that these two numbers are indeed the same within double precision: 第一个数字是你最初得到的6/0.05 ,但数字119.9999999999999933386618522四舍五入到最接近的数字,用双精度表示,这是120.可以很容易地证明这两个数字在双精度内确实是相同的:

>>> print(6/Decimal('0.05') - 6/Decimal(0.05))
6.6613381478E-15

>>> 120 - 6.6613381478E-15 == 120
True

Now here's help mod from MATLAB: 现在来自MATLAB的help mod

    MOD(x,y) returns x - floor(x./y).*y if y ~= 0, carefully computed to
    avoid rounding error. If y is not an integer and the quotient x./y is
    within roundoff error of an integer, then n is that integer.

This suggests that when x/y is close to an integer then it's rounded first, rather than being truncated like in python. 这表明当x/y接近整数时,它首先舍入,而不是像python中那样被截断。 So MATLAB goes out of its way to do some magic with the floating-point results. 所以MATLAB不遗余力地利用浮点结果做一些魔术。

The simplest solution would be to round your numbers yourself (unless you can use something like decimal.Decimal , but this means you should forgo native doubles entirely, including literals) and reproduce MATLAB's mod that way, assuming that makes sense for your use cases. 最简单的解决方案是自己舍入你的数字(除非你可以使用像decimal.Decimal这样的decimal.Decimal ,但这意味着你应该完全放弃原生双打,包括文字)并以这种方式重现MATLAB的mod ,假设对你的用例有意义。

Here is a workaround. 这是一个解决方法。 It basically rounds the denominator to its str representation and from there does integer arithmetic: 它基本上将分母舍入到它的str表示,并从那里进行整数运算:

import numpy as np
import decimal

def round_divmod(b,a):
     n,d = np.frompyfunc(lambda x:decimal.Decimal(x).as_integer_ratio(),1,2)(a.astype('U'))
     n,d = n.astype(int),d.astype(int)
     q,r = np.divmod(b*d,n)
     return q,r/d

a = np.round(np.linspace(0.05,1,20),2).reshape(4,5)
a
# array([[0.05, 0.1 , 0.15, 0.2 , 0.25],
#        [0.3 , 0.35, 0.4 , 0.45, 0.5 ],
#        [0.55, 0.6 , 0.65, 0.7 , 0.75],
#        [0.8 , 0.85, 0.9 , 0.95, 1.  ]])
round_divmod(6,a)
# (array([[120,  60,  40,  30,  24],
#        [ 20,  17,  15,  13,  12],
#        [ 10,  10,   9,   8,   8],
#        [  7,   7,   6,   6,   6]]), array([[0.  , 0.  , 0.  , 0.  , 0.  ],
#        [0.  , 0.05, 0.  , 0.15, 0.  ],
#        [0.5 , 0.  , 0.15, 0.4 , 0.  ],
#        [0.4 , 0.05, 0.6 , 0.3 , 0.  ]]))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM