【问题标题】:Equivalent matlab function mod in numpy or pythonnumpy或python中的等效matlab函数mod
【发布时间】:2019-07-17 23:17:05
【问题描述】:

我正在将一些代码从 Matlab 转换为 Python。

在matlab中有一个函数mod,它给出了模运算。

例如以下示例显示了 matlab mod 和等效的 numpy remainder 操作之间的不同结果:

Matlab:

>> mod(6, 0.05)

ans =

     0

麻木:

np.remainder(6, 0.05) 
0.04999999999999967

np.mod(6, 0.05)
0.04999999999999967

Python 取模运算符给出与 numpy 相同的结果。

6%0.05
0.04999999999999967

python 中有什么东西可以提供与 Matlab 中相同的 mod 操作吗?最好可以在numpy 2d/3d 数组上操作。

numpy documentation 表示numpy.mod 等价于matlab mod

【问题讨论】:

  • documentation,计算与floor_divide 函数互补的余数。 np.floor_divide(6, 0.05)=119.0119.0*.05=5.95 的值。因此,你得到的余数是0.04999999999999967
  • @Aditya 但不应该6//0.05 == 120
  • 6//0.05 == 119.0。它将数字四舍五入到较低的值。

标签: python matlab numpy floating-point


【解决方案1】:

这是问题的核心,在python中:

>>> 6/0.05 == 120
True

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

6/0.05 的浮点结果足够接近 120(即在双精度分辨率范围内),它被舍入到 120.0。但是,它比 120 略小,因此显式地板除法会将该数字截断为 119,然后才能标准化为 120.0。

一些证据:

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

第一个数字是您首先使用 6/0.05 得到的数字,但数字 119.9999999999999933386618522 会四舍五入到可以用双精度表示的最接近的数字,即 120。很容易证明这两个数字确实是双精度内相同:

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

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

现在这是来自 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.

这表明当x/y 接近一个整数时,它首先被四舍五入,而不是像在 python 中那样被截断。因此,MATLAB 不遗余力地对浮点结果施展魔法。

最简单的解决方案是自己对数字进行四舍五入(除非您可以使用 decimal.Decimal 之类的东西,但这意味着您应该完全放弃本机双精度数,包括文字)并以这种方式重现 MATLAB 的 mod,假设这是有道理的适合您的用例。

【讨论】:

  • 谢谢,我听从了您的建议,自己对数字进行了四舍五入。 np.round(6/array, decimals=3)*array - 6 3 个小数点是我的数据集中的准确性限制。检查是否没有剩余我做了np.isclose(np.round(6/array, decimals=3)*array - 6, 0)
  • @KhalilAlHooti 这或多或少是我所做的 :) 由于 MATLAB 是做一些奇怪的事情的人,你必须弄乱isclose 之类的东西来重现他们的行为。至少您拥有的小数点后 3 位精度使它相当稳健,这将是我主要关心的问题。
  • 再次感谢,我相信numpy 的开发人员不应该声明他们的mod 函数等同于Matlab 的mod 函数。
  • @KhalilAlHooti 确切的措辞是“与 np.remainder 等效的 MATLAB 函数是 mod”,它没有明确声明它们完全相同(即返回确切的相同输入的相同输出),但我可以看到它是如何暗示的。一个人的“等效”里程可能会有所不同。您可以将其提升为 an issue with numpy,它可能会被更改(不是行为,而是文档中的措辞)。
【解决方案2】:

这是一种解决方法。它基本上将分母四舍五入到它的 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.  ]]))

【讨论】:

  • 非常感谢你,它确实像一个魅力。但我发现按照@Andras Deak 的建议,将数字四舍五入更容易更快
猜你喜欢
  • 2016-07-27
  • 2021-09-10
  • 2014-05-31
  • 1970-01-01
  • 2014-04-04
  • 2021-04-22
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多