【问题标题】:Modulus operation with negatives values - weird thing?负值的模运算 - 奇怪的事情?
【发布时间】:2008-09-04 13:36:46
【问题描述】:

你能告诉我(-2) % 5 多少钱吗? 根据我的 Python 解释器是 3,但是你对此有一个明智的解释吗?

我已经读到,在某些语言中,结果可能取决于机器,但我不确定。

【问题讨论】:

  • 您可以使用 math.fmod 获得与 C 或 Java 中相同的行为。

标签: python math modulo


【解决方案1】:

顺便说一句:大多数编程语言不同意 Python 并给出结果-2。根据模数的解释,这是正确的。然而,最一致的数学定义表明 ab 的模数是除法的(严格正数)余数 r a / b。更准确地说,根据定义,0 r b。

【讨论】:

    【解决方案2】:

    对负数进行取模运算的结果似乎取决于编程语言,这里有一个清单http://en.wikipedia.org/wiki/Modulo_operation

    【讨论】:

      【解决方案3】:

      您的 Python 解释器是正确的。 计算模数的一种(愚蠢的)方法是减去或添加模数,直到结果值介于 0 和 (modulus − 1) 之间。

      例如: 13 mod 5 = (13 - 5) mod 5 = (13 - 10) mod 5 = 3

      或者在你的情况下:-2 mod 5 = (-2 + 5) mod 5 = 3

      【讨论】:

      • 这取决于整数除法是如何定义的。如果除法向 0 舍入,则余数应与商具有相同的符号,因此 b * (a/b) + a%b == a。如果除法向负无穷大取整(如在 Python 中),则余数应始终为正数。
      【解决方案4】:

      正如Binary arithmetic operations 中的文档所述,Python 保证:

      整数除法和模运算符通过以下标识连接:x == (x/y)*y + (x%y)。整数除法和取模也与内置函数 divmod() 连接:divmod(x, y) == (x/y, x%y)

      真的,

      >>> divmod(-2, 5)
      (-1, 3).
      

      另一种可视化这种方法一致性的方法是计算一个小的数字序列的divmod

      >>> for number in xrange(-10, 10):
      ...     print divmod(number, 5)
      ...
      (-2, 0)
      (-2, 1)
      (-2, 2)
      (-2, 3)
      (-2, 4)
      (-1, 0)
      (-1, 1)
      (-1, 2)
      (-1, 3)
      (-1, 4)
      (0, 0)
      (0, 1)
      (0, 2)
      (0, 3)
      (0, 4)
      (1, 0)
      (1, 1)
      (1, 2)
      (1, 3)
      (1, 4)
      

      【讨论】:

        【解决方案5】:

        嗯,0 % 5 应该是 0,对吧?

        -1 % 5 应该是 4,因为这是下一个允许的反向数字(即,它不能是 5,因为它超出了范围)。

        按照这个逻辑,-2 必须是 3。

        思考它如何工作的最简单方法是不断加或减 5,直到数字落在 0(含)和 5(不含)之间。

        我不确定机器依赖性 - 我从未见过这样的实现,但我不能说它从未完成过。

        【讨论】:

          【解决方案6】:

          正如其他答案中所解释的,负值的模运算有很多选择。一般来说,不同的语言(和不同的机器架构)会给出不同的结果。

          根据Python reference manual

          模运算符总是产生与第二个操作数相同符号的结果(或零);结果的绝对值严格小于第二个操作数的绝对值。

          是 Python 的选择。基本上定义了模数,因此它始终成立:

          x == (x/y)*y + (x%y)
          

          所以 (-2)%5 = -2 - (-2/5)*5 = 3 是有道理的

          【讨论】:

            【解决方案7】:

            嗯,-2 除以 5 将是 0,余数为 3。我不认为这应该非常依赖于平台,但我见过奇怪的事情。

            【讨论】:

            • 您的意思肯定是:“-2 除以 5 将是 -1 余数为 3”,对吧?无论如何,这就是 Python 所做的。
            • 在某些系统中,-2 除以 5 为 0,余数为 -2。在其他情况下,它是 -1,余数为 3。只是口味问题,没有“正确”答案。
            【解决方案8】:

            确实是 3。在modular arithmetic 中,模数只是除法的余数,-2 除以 5 的余数是 3。

            【讨论】:

            • 在表达式c = a%b中,b是模数,而不是c
            【解决方案9】:

            结果取决于语言。 Python 返回除数的符号,例如 c# 返回被除数的符号(即 -2 % 5 在 c# 中返回 -2)。

            【讨论】:

              【解决方案10】:

              一种解释可能是使用2's complement 存储负数。当 python 解释器尝试进行模运算时,它会转换为无符号值。因此,它实际上不是执行 (-2) % 5 而是计算 0xFFFF_FFFF_FFFF_FFFD % 5 ,即 3。

              【讨论】:

                【解决方案11】:

                注意不要在所有操作系统和架构上依赖 C/C++ 中的这种 mod 行为。如果我没记错的话,我尝试依赖 C/C++ 代码,例如

                float x2 = x % n;
                

                将 x2 保持在 0 到 n-1 的范围内,但当我在一个操作系统上编译时会出现负数,但在另一个操作系统上会正常工作。这使得调试时间很糟糕,因为它只发生了一半!

                【讨论】:

                  【解决方案12】:

                  “模数”和“余数”这两个术语似乎很容易混淆。

                  在数学中,余数应该总是定义为与商一致,这样如果a / b == c rem d 那么(c * b) + d == a。根据您对商的四舍五入方式,您会得到不同的余数。

                  但是,模数应该始终给出结果0 <= r < divisor,只有在允许负整数的情况下才与四舍五入到负无穷大的除法一致。如果除法向零舍入(这很常见),则模和余数仅对非负值等价。

                  某些语言(尤其是 C 和 C++)没有定义所需的舍入/余数行为,% 是模棱两可的。许多人将舍入定义为接近零,但在余数更正确的情况下使用术语模数。 Python 相对不寻常,因为它舍入到负无穷大,所以模和余数是等价的。

                  Ada 向零 IIRC 舍入,但同时具有 modrem 运算符。

                  C 策略旨在允许编译器为机器选择最有效的实现,但 IMO 是一种错误的优化,至少现在是这样。一个好的编译器可能能够在不能出现负数的情况下使用等价进行优化(几乎可以肯定,如果您使用无符号类型)。另一方面,在可能出现负数的情况下,您几乎肯定会关心细节——出于可移植性的原因,您必须使用非常精心设计的过度复杂算法和/或检查,以确保无论四舍五入和余数如何都能得到您想要的结果行为。

                  换句话说,这种“优化”的收益大部分(如果不总是)是一种错觉,而在某些情况下会有非常实际的成本 - 所以这是一种错误的优化。

                  【讨论】:

                    猜你喜欢
                    • 2020-11-18
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-11-25
                    • 2013-02-27
                    • 1970-01-01
                    相关资源
                    最近更新 更多