📜  带有负结果的编程中的模运算

📅  最后修改于: 2021-04-17 17:11:51             🧑  作者: Mango

在编程中,在将一个整数除以另一个整数后,取模运算给出除法的余数或有符号余数。它是编程中最常用的运算符之一。本文讨论了何时以及为什么取模运算会产生否定结果。

例子:

  • 在C中, 3%2返回1 。但是, -3%2-1,3%-21
  • 在Python, -3%21,3%-2-1

因此,很明显,在不同的编程语言中, -3%2的相同表达式给出不同的结果。这个结果与数学而不是编程更相关。这里提到的数学将有助于更轻松地理解问题。
要理解为什么会发生这种情况,需要对欧几里得除法有一点了解,并需要与模块化算术有关的一些知识。

欧几里德除法(Euclidean Division) 在算术中,欧几里德除法或除以除数是将一个整数(被除数)除以另一个(除数)的过程,其方式是产生商 和一个 余数小于除数。

给定两个整数ab (其中b≠0 ),则存在唯一的整数qr ,使得:

在上式中,四个整数中的每个都有其自己的名称,即

  • a称为红利
  • b称为除数
  • q称为
  • r称为余数

例如:

  • 如果a = 9且b = 4,则q = 2且r = 1,因为9 = 4×2 +1。
  • 如果a = -9和b = 4,则q = -3且r = 3,因为-9 = 4×-3 + 3。
  • 如果a = 9且b = -4,则q = -2且r = 1,因为9 = -4×-2 + 1。
  • 如果a = -9和b = -4,则q = 3且r = 3,因为-9 = -4×3 + 3。

以上示例的说明:

  • 第一个例子不言自明,因为9/4给出2和余数1。
  • 第二个示例(-9/4)给出-3而不是-2 。发生这种情况是因为,如果我们以-2商,-9 = 4×-2 +(-1) 。剩余的-1不能满足欧几里得除法的条件。它不会使-9/4 = -2错误,这不是我们在这种情况下所需要的。

模数运算在数学中,模数运算是一种用于整数的算术系统,其中,数字在达到一定值(称为模数)时会“环绕”。

同余:给定任何整数N (称为模数),如果两个整数ab在除以N时产生相同的余数,则称它们为N的模余。

同余模N表示为a≡b(mod N)
其中括号表示(mod N)适用于整个方程,而不仅适用于右侧(在此为b )。

例子:

  • -5≡2(mod 7)
  • -14≡19(mod 11)

分析第一个例子。 -5 = 7×-1 + 22 = 7×0 + 2 。当被7除时, -52保留相同的余数2 。因此,它们彼此一致。
同样, -14 = 11×-2 + 819 = 11×1 + 8-1419在除以11时会保留相同的余数8 。因此,它们彼此一致。

同余类假设当除以满足条件0≤r <| N |的N时,模N留下余数r 。与mod N相等的所有整数的集合称为整数mod N的一致性类。例如:

  • 3 mod 2的全等类为{…,-5,-3,-1、1、3、5、7…}。
  • 7 mod 4的全等类为{…,-9,-5,-1、3、7、11…}。

从整数N的同余类中选择任何整数作为该类的代表。在数学中,选择属于该类别的最小正残数,最小非负整数作为代表。例如:

  • 同余类3 mod 2的代表是1。
  • 同等类7 mod 4的代表是3。

选择最小的正残基是因为它是欧几里得分裂后产生的剩余残基。

代表由编程语言选择:

  • 如果aN均为正,则在所有编程语言中,模N是欧几里得除法的余数。但是,当aN为负或两者均为负时,会观察到结果的差异。然后, mod N的答案取决于编程语言所使用的mod N的实现。所有编程语言产生的余数的确遵循特定标准,即| r |。 <| N |
  • 但是,如果余数不为零,这仍然会产生符号歧义,然后会出现两种可能的余数选择:一个负数( mod N的同余类的最大负数)和另一个正数(最小正数)模N的同余类的定义。其他元素不满足| r |的条件<| N |
  • 这就是为什么在CPython执行-3 mod 2会有不同的结果的原因。他们两个都产生正确的结果。他们只是不输出数学上代表mod N的代表。
  • C中-3 mod 2返回-1 ,这是-3 mod 2的成员类。但是, Python返回1 ,它再次是-3 mod 2的成员类。同样,两个答案都返回以满足| r |的给定条件。 <| N |

编程语言中%的实现诸如CC++JavaJavaScript之类的许多编程语言都使用类似于以下给出的一种实现。其余部分根据等式返回

下面是上述说明的实现:

C++14
// C++14 program to illustrate modulo
// operations using the above equation
#include 
using namespace std;
 
// Function to calculate and
// return the remainder of a % n
int truncMod(int a, int n)
{
     
    // (a / n) implicitly gives
    // the truncated result
    int q = a / n;
 
    return a - n * q;
}
 
// Driver Code
int main()
{
    int a, b;
 
    // Modulo of two positive numbers
    a = 9;
    b = 4;
    cout << a << " % "
         << b << " = "
         << truncMod(a, b) << endl;
 
    // Modulo of a negative number
    // by a positive number
    a = -9;
    b = 4;
    cout << a << " % "
         << b << " = "
         << truncMod(a, b) << endl;
 
    // Modulo of a positive number
    // by a negative number
    a = 9;
    b = -4;
    cout << a << " % "
         << b << " = "
         << truncMod(a, b) << endl;
 
    // Modulo of two negative numbers
    a = -9;
    b = -4;
    cout << a << " % "
         << b << " = "
         << truncMod(a, b) << endl;
}
 
// This code is contributed by mohit kumar 29


Java
// Java program to illustrate modulo
// operations using the above equation
class GFG {
 
    // Function to calculate and
    // return the remainder of a % n
    static int truncMod(int a, int n)
    {
        // (a / n) implicitly gives
        // the truncated result
        int q = a / n;
 
        return a - n * q;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int a, b;
 
        // Modulo of two positive numbers
        a = 9;
        b = 4;
        System.out.println(a + " % " + b + " = "
                           + truncMod(a, b));
 
        // Modulo of a negative number
        // by a positive number
        a = -9;
        b = 4;
        System.out.println(a + " % " + b + " = "
                           + truncMod(a, b));
 
        // Modulo of a positive number
        // by a negative number
        a = 9;
        b = -4;
        System.out.println(a + " % " + b + " = "
                           + truncMod(a, b));
 
        // Modulo of two negative numbers
        a = -9;
        b = -4;
        System.out.println(a + " % " + b + " = "
                           + truncMod(a, b));
    }
}


Python3
# Python3 program to illustrate modulo
# operations using the above equation
 
# Function to calculate and
# return the remainder of a % n
def truncMod(a, n):
   
    # (a / n) implicitly gives
    # the truncated result
    q = a // n
    return a - n * q
 
# Driver Code
if __name__ == '__main__':
   
    # Modulo of two positive numbers
    a = 9
    b = 4
    print(a,"%",b,"=",truncMod(a, b))
 
    # Modulo of a negative number
    # by a positive number
    a = -9
    b = 4
    print(a,"%",b,"=",truncMod(a, b))
 
    # Modulo of a positive number
    # by a negative number
    a = 9
    b = -4
    print(a,"%",b,"=",truncMod(a, b))
 
    # Modulo of two negative numbers
    a = -9
    b = -4
    print(a,"%",b,"=",truncMod(a, b))
     
    # This code is contributed by SURENDRA_GANGWAR.


C#
// C# program for the above approach
using System;
public class GFG
{
 
  // Function to calculate and
  // return the remainder of a % n
  static int truncMod(int a, int n)
  {
     
    // (a / n) implicitly gives
    // the truncated result
    int q = a / n;
    return a - n * q;
  }
 
  // Driver Code
  static public void Main()
  {
 
    int a, b;
 
    // Modulo of two positive numbers
    a = 9;
    b = 4;
    Console.WriteLine(a + " % " + b + " = "
                      + truncMod(a, b));
 
    // Modulo of a negative number
    // by a positive number
    a = -9;
    b = 4;
    Console.WriteLine(a + " % " + b + " = "
                      + truncMod(a, b));
 
    // Modulo of a positive number
    // by a negative number
    a = 9;
    b = -4;
    Console.WriteLine(a + " % " + b + " = "
                      + truncMod(a, b));
 
    // Modulo of two negative numbers
    a = -9;
    b = -4;
    Console.WriteLine(a + " % " + b + " = "
                      + truncMod(a, b));
  }
}
 
// This code is contributed by snjoy_62.


C++
// C++ program to illustrate modulo
// operations using the above equation
#include 
using namespace std;
 
// Function to calculate and
// return the remainder of a % n
int floorMod(int a, int n)
{
     
    // Type casting is necessary
    // as (int) / (int) will give
    // int result, i.e. -3 / 2
    // will give -1 and not -1.5
    int q = (int)floor((double)a / n);
 
    // Return the resultant remainder
    return a - n * q;
}
 
// Driver Code
int main()
{
    int a, b;
 
    // Modulo of two positive numbers
    a = 9;
    b = 4;
    cout << a << " % " << b
         << " = " << floorMod(a, b) << "\n";
 
    // Modulo of a negative number
    // by a positive number
    a = -9;
    b = 4;
    cout << a << " % " << b
         << " = " << floorMod(a, b) << "\n";
 
    // Modulo of a positive number
    // by a negative number
    a = 9;
    b = -4;
    cout << a << " % " << b
         << " = " << floorMod(a, b) << "\n";
 
    // Modulo of two negative numbers
    a = -9;
    b = -4;
    cout << a << " % " << b
         << " = " << floorMod(a, b) << "\n";
 
    return 0;
}
 
// This code is contributed by Kingash


Java
// Java program to illustrate modulo
// operations using the above equation
public class GFG {
 
    // Function to calculate and
    // return the remainder of a % n
    static int floorMod(int a, int n)
    {
        // Type casting is necessary
        // as (int) / (int) will give
        // int result, i.e. -3 / 2
        // will give -1 and not -1.5
        int q = (int)Math.floor((double)a / n);
 
        // Return the resultant remainder
        return a - n * q;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int a, b;
 
        // Modulo of two positive numbers
        a = 9;
        b = 4;
        System.out.println(a + " % " + b + " = "
                           + floorMod(a, b));
 
        // Modulo of a negative number
        // by a positive number
        a = -9;
        b = 4;
        System.out.println(a + " % " + b + " = "
                           + floorMod(a, b));
 
        // Modulo of a positive number
        // by a negative number
        a = 9;
        b = -4;
        System.out.println(a + " % " + b + " = "
                           + floorMod(a, b));
 
        // Modulo of two negative numbers
        a = -9;
        b = -4;
        System.out.println(a + " % " + b + " = "
                           + floorMod(a, b));
    }
}


C++
// C++ program for the above idea
#include 
using namespace std;
 
// Driver Code
int main()
{
    int a, b, r;
 
    // Modulo of two positive numbers
    a = 9;
    b = 4;
    r = a % b > 0 ? a % b : abs(b) + a % b;
    cout << a << " % " << b << " = " << r << "\n";
 
    // Modulo of a negative number
    // by a positive number
    a = -9;
    b = 4;
    r = a % b > 0 ? a % b : abs(b) + a % b;
    cout << a << " % " << b << " = " << r << "\n";
 
    // Modulo of a positive number
    // by a negative number
    a = 9;
    b = -4;
    r = a % b > 0 ? a % b : abs(b) + a % b;
    cout << a << " % " << b << " = " << r << "\n";
 
    // Modulo of two negative numbers
    a = -9;
    b = -4;
    r = a % b > 0 ? a % b : abs(b) + a % b;
    cout << a << " % " << b << " = " << r << "\n";
 
    return 0;
}
 
// This code is contributed by Kingash


Java
// Java program for the above idea
public class PositiveModulus {
    // Driver Code
    public static void main(String args[])
    {
        int a, b, r;
 
        // Modulo of two positive numbers
        a = 9;
        b = 4;
        r = a % b > 0 ? a % b : Math.abs(b) + a % b;
        System.out.println(a + " % " + b + " = " + r);
 
        // Modulo of a negative number
        // by a positive number
        a = -9;
        b = 4;
        r = a % b > 0 ? a % b : Math.abs(b) + a % b;
        System.out.println(a + " % "
                           + b + " = " + r);
 
        // Modulo of a positive number
        // by a negative number
        a = 9;
        b = -4;
        r = a % b > 0 ? a % b : Math.abs(b) + a % b;
        System.out.println(a + " % "
                           + b + " = " + r);
 
        // Modulo of two negative numbers
        a = -9;
        b = -4;
        r = a % b > 0 ? a % b : Math.abs(b) + a % b;
        System.out.println(a + " % "
                           + b + " = " + r);
    }
}


C#
// C# program for the above idea
using System;
using System.Collections.Generic;
 
class GFG{
 
// Driver Code
public static void Main(string[] args)
{
    int a, b, r;
 
    // Modulo of two positive numbers
    a = 9;
    b = 4;
    r = a % b > 0 ? a % b : Math.Abs(b) + a % b;
    Console.WriteLine(a + " % " + b + " = " + r);
 
    // Modulo of a negative number
    // by a positive number
    a = -9;
    b = 4;
    r = a % b > 0 ? a % b : Math.Abs(b) + a % b;
    Console.WriteLine(a + " % " + b + " = " + r);
 
    // Modulo of a positive number
    // by a negative number
    a = 9;
    b = -4;
    r = a % b > 0 ? a % b : Math.Abs(b) + a % b;
    Console.WriteLine(a + " % " + b + " = " + r);
 
    // Modulo of two negative numbers
    a = -9;
    b = -4;
    r = a % b > 0 ? a % b : Math.Abs(b) + a % b;
    Console.WriteLine(a + " % " + b + " = " + r);
}
}
 
// This code is contributed by avijitmondal1998


输出:
9 % 4 = 1
-9 % 4 = -1
9 % -4 = 1
-9 % -4 = -1

注意:具有上述实现方式的其他编程语言也会产生相似的结果。注意一些有趣的事情,当红利为负数时,得出的答案也将为负数,并且将是该同余类中最大的负数成员。当红利为正数时,产生的答案也将为正数,并且是同余类中最不积极的成员

许多编程语言(例如PythonRubyPerl)都使用类似于以下给出的实现。其余部分根据等式返回

下面是上述说明的实现:

C++

// C++ program to illustrate modulo
// operations using the above equation
#include 
using namespace std;
 
// Function to calculate and
// return the remainder of a % n
int floorMod(int a, int n)
{
     
    // Type casting is necessary
    // as (int) / (int) will give
    // int result, i.e. -3 / 2
    // will give -1 and not -1.5
    int q = (int)floor((double)a / n);
 
    // Return the resultant remainder
    return a - n * q;
}
 
// Driver Code
int main()
{
    int a, b;
 
    // Modulo of two positive numbers
    a = 9;
    b = 4;
    cout << a << " % " << b
         << " = " << floorMod(a, b) << "\n";
 
    // Modulo of a negative number
    // by a positive number
    a = -9;
    b = 4;
    cout << a << " % " << b
         << " = " << floorMod(a, b) << "\n";
 
    // Modulo of a positive number
    // by a negative number
    a = 9;
    b = -4;
    cout << a << " % " << b
         << " = " << floorMod(a, b) << "\n";
 
    // Modulo of two negative numbers
    a = -9;
    b = -4;
    cout << a << " % " << b
         << " = " << floorMod(a, b) << "\n";
 
    return 0;
}
 
// This code is contributed by Kingash

Java

// Java program to illustrate modulo
// operations using the above equation
public class GFG {
 
    // Function to calculate and
    // return the remainder of a % n
    static int floorMod(int a, int n)
    {
        // Type casting is necessary
        // as (int) / (int) will give
        // int result, i.e. -3 / 2
        // will give -1 and not -1.5
        int q = (int)Math.floor((double)a / n);
 
        // Return the resultant remainder
        return a - n * q;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int a, b;
 
        // Modulo of two positive numbers
        a = 9;
        b = 4;
        System.out.println(a + " % " + b + " = "
                           + floorMod(a, b));
 
        // Modulo of a negative number
        // by a positive number
        a = -9;
        b = 4;
        System.out.println(a + " % " + b + " = "
                           + floorMod(a, b));
 
        // Modulo of a positive number
        // by a negative number
        a = 9;
        b = -4;
        System.out.println(a + " % " + b + " = "
                           + floorMod(a, b));
 
        // Modulo of two negative numbers
        a = -9;
        b = -4;
        System.out.println(a + " % " + b + " = "
                           + floorMod(a, b));
    }
}
输出:
9 % 4 = 1
-9 % 4 = 3
9 % -4 = -3
-9 % -4 = -1

注意:具有上述实现的其他编程语言也会产生相似的结果。现在,当除数为负数时,所产生的答案也将为负数,以及该同余类中最大的负数成员。当除数正时,产生的答案也将为正,并且它将是该同余类中最不肯定的成员

所有语言都产生正确的结果。他们只是选择该解决方案全班的不同代表。为了仅产生全等类别的最小正残数作为答案,而与所使用的实现方式无关。

下面是上述方法的实现:

C++

// C++ program for the above idea
#include 
using namespace std;
 
// Driver Code
int main()
{
    int a, b, r;
 
    // Modulo of two positive numbers
    a = 9;
    b = 4;
    r = a % b > 0 ? a % b : abs(b) + a % b;
    cout << a << " % " << b << " = " << r << "\n";
 
    // Modulo of a negative number
    // by a positive number
    a = -9;
    b = 4;
    r = a % b > 0 ? a % b : abs(b) + a % b;
    cout << a << " % " << b << " = " << r << "\n";
 
    // Modulo of a positive number
    // by a negative number
    a = 9;
    b = -4;
    r = a % b > 0 ? a % b : abs(b) + a % b;
    cout << a << " % " << b << " = " << r << "\n";
 
    // Modulo of two negative numbers
    a = -9;
    b = -4;
    r = a % b > 0 ? a % b : abs(b) + a % b;
    cout << a << " % " << b << " = " << r << "\n";
 
    return 0;
}
 
// This code is contributed by Kingash

Java

// Java program for the above idea
public class PositiveModulus {
    // Driver Code
    public static void main(String args[])
    {
        int a, b, r;
 
        // Modulo of two positive numbers
        a = 9;
        b = 4;
        r = a % b > 0 ? a % b : Math.abs(b) + a % b;
        System.out.println(a + " % " + b + " = " + r);
 
        // Modulo of a negative number
        // by a positive number
        a = -9;
        b = 4;
        r = a % b > 0 ? a % b : Math.abs(b) + a % b;
        System.out.println(a + " % "
                           + b + " = " + r);
 
        // Modulo of a positive number
        // by a negative number
        a = 9;
        b = -4;
        r = a % b > 0 ? a % b : Math.abs(b) + a % b;
        System.out.println(a + " % "
                           + b + " = " + r);
 
        // Modulo of two negative numbers
        a = -9;
        b = -4;
        r = a % b > 0 ? a % b : Math.abs(b) + a % b;
        System.out.println(a + " % "
                           + b + " = " + r);
    }
}

C#

// C# program for the above idea
using System;
using System.Collections.Generic;
 
class GFG{
 
// Driver Code
public static void Main(string[] args)
{
    int a, b, r;
 
    // Modulo of two positive numbers
    a = 9;
    b = 4;
    r = a % b > 0 ? a % b : Math.Abs(b) + a % b;
    Console.WriteLine(a + " % " + b + " = " + r);
 
    // Modulo of a negative number
    // by a positive number
    a = -9;
    b = 4;
    r = a % b > 0 ? a % b : Math.Abs(b) + a % b;
    Console.WriteLine(a + " % " + b + " = " + r);
 
    // Modulo of a positive number
    // by a negative number
    a = 9;
    b = -4;
    r = a % b > 0 ? a % b : Math.Abs(b) + a % b;
    Console.WriteLine(a + " % " + b + " = " + r);
 
    // Modulo of two negative numbers
    a = -9;
    b = -4;
    r = a % b > 0 ? a % b : Math.Abs(b) + a % b;
    Console.WriteLine(a + " % " + b + " = " + r);
}
}
 
// This code is contributed by avijitmondal1998
输出:
9 % 4 = 1
-9 % 4 = 3
9 % -4 = 1
-9 % -4 = 3