不同编程语言中的整数求余【Modulo (Mathematical Definition)/Remainder (Truncated Division)】

TL;DR

There are 2 definitions:

  • Modulo (Mathematical Definition). In this class, the result of a % b always has the same sign as the divisor (b).
  • Remainder (Truncated Division). In this class, the result of a % b always has the same sign as the dividend (a).


Programming languages can be classified into different categories based on how they handle modulo/remainder operations, particularly when negative numbers are involved. The behavior of the modulo operator in various languages mainly falls into two classes:


1. Modulo (Mathematical Definition)

In this class, the result of a % b always has the same sign as the divisor (b). This behavior corresponds to the true mathematical definition of modulo.

Examples:

  • 5 % 3 = 2
  • -5 % 3 = 1 (result has the same sign as 3)
  • 5 % -3 = -1 (result has the same sign as -3)
  • -5 % -3 = -2 (result has the same sign as -3)

Languages in this Class:

  • Python
  • Ruby
  • R
  • Haskell
  • Erlang
  • Ada

2. Remainder (Truncated Division)

In this class, the result of a % b always has the same sign as the dividend (a). This behavior corresponds to the remainder after truncated division (division rounded toward zero).

Examples:

  • 5 % 3 = 2
  • -5 % 3 = -2 (result has the same sign as -5)
  • 5 % -3 = 2 (result has the same sign as 5)
  • -5 % -3 = -2 (result has the same sign as -5)

Languages in this Class:

  • JavaScript
  • C
  • C++
  • Java
  • Go
  • Swift
  • Kotlin
  • Scala (%)

3. Other/Hybrid Behaviors

Some languages use non-standard or configurable behavior for modulo, allowing you to choose between different definitions.

Examples:

  • SQL (e.g., PostgreSQL):

    • PostgreSQL uses the remainder definition (a % b takes the sign of a).
    • However, it also offers a MOD(a, b) function, which behaves like the mathematical modulo (result takes the sign of b).
  • Fortran:

    • Fortran has two operators: MOD(a, b) (result takes the sign of b) and MODULO(a, b) (result takes the sign of a).
  • Scala:

    • Scala's % operator behaves like remainder (same sign as a).
    • However, the math.floorMod(a, b) method behaves like mathematical modulo (same sign as b).
  • Perl:

    • Perl's % operator behaves like remainder (same sign as a), but you can implement mathematical modulo manually if needed.

Comparison Table

Language % Behavior (Modulo or Remainder) Notes
Python Modulo Result sign matches divisor (b).
Ruby Modulo Result sign matches divisor (b).
Haskell Modulo Result sign matches divisor (b).
R Modulo Result sign matches divisor (b).
C Remainder Result sign matches dividend (a).
C++ Remainder Result sign matches dividend (a).
Java Remainder Result sign matches dividend (a).
JavaScript Remainder Result sign matches dividend (a).
Go Remainder Result sign matches dividend (a).
Swift Remainder Result sign matches dividend (a).
Scala Remainder Use math.floorMod for true modulo.
SQL Configurable % is remainder; MOD() is modulo.
Fortran Configurable MOD(a, b) (modulo), MODULO(a, b).

How Do We Use This Classification?

  1. When Porting Code Between Languages:

    • Be aware of the differences in % behavior when translating code between languages like Python and JavaScript (or others in different classes). They can lead to subtle bugs, particularly with negative numbers.
  2. When Writing Cross-Language Algorithms:

    • If you're working with mixed-language environments or need consistent behavior across multiple languages, you can manually implement a specific modulo definition (e.g., using formulas) to unify the behavior.

    • Mathematical Modulo Formula (in languages that use remainder):

      result = ((a % b) + b) % b
      
    • Remainder Formula (in languages that use modulo):

      result = a % b if a * b > 0 else a % b - b
      
  3. Choosing a Language for Specific Applications:

    • For applications involving modular arithmetic (e.g., cryptography, cyclic computations), languages with mathematical modulo (Python, Ruby) may be more intuitive.

    • For low-level programming or compatibility with hardware (e.g., embedded systems), languages with remainder behavior (C, C++) might be preferred.


My question

Adapter of different modulo? More Examples are appreciated.

// javascript
function pythonMod(a, b) {
  return ((a % b) + b) % b;
}
// scala

/*
Python's % operator returns a result with the same sign as the divisor, and // rounds towards negative infinity.

In Scala, % and / don't behave the same way. The % operator returns a result with the same sign as the dividend, and / performs truncating division, rounding towards zero.
*/


def pythonMod(a: Int, b: Int): Int = ((a % b) + b) % b

def pythonDiv(a: Int, b: Int): Int = {
  if ((a > 0 && b > 0) || (a < 0 && b < 0)) a / b
  else if (a % b == 0) a / b
  else a / b - 1
}
def scala_div(x, y):
    if y == 0:
        raise ZeroDivisionError('division by zero')
    elif (x < 0 and y < 0) or (x > 0 and y > 0):
        return abs(x) // abs(y)
    else:
        return -(abs(x) // abs(y))
        
def scala_mod(x, y):
    if y == 0:
        raise ZeroDivisionError('modulo by zero')
    elif x < 0:
        return -(abs(x) % abs(y))
    else:
        return x % abs(y)

posted @ 2023-05-17 13:52  yhm138  阅读(96)  评论(0)    收藏  举报