23

I am learning Go and I come from a Python background.

Recently, I stumbled onto a behaviour of the %(modulo) operator which is different from the corresponding operator in Python. Quite contrary to the definition of modular operation and remainder, the modulus of negative integers by a positive integer returns a negative value.

Example:

Python

a, b, n = -5, 5, 3
for i in range(a, b):
    print(i%n)    

Output:

1
2
0
1
2
0
1
2
0
1

Go

a, b, n := -5, 5, 3
for i:=a; i<b; i++ {
    fmt.Println(i%n)
}

Output:

-2
-1
0
-2
-1
0
1
2
0
1

After reading about the Modulo operator and few similar questions asked about the reason behind these differences, I understand that these were due to design goals of the concerned languages.

Is there a built-in functionality in Go which replicates the modulus operation of Python?

Alternate: Is there an internal method for computing the "modulus" instead of the "remainder"?

blackgreen
  • 34,072
  • 23
  • 111
  • 129
Kshitij Saraogi
  • 6,821
  • 8
  • 41
  • 71

5 Answers5

19

See this comment by one of the language designers:

There are a several reasons for the current definition:

  • the current semantics for % is directly available as a result from x86 architectures
  • it would be confusing to change the meaning of the elementary operator % and not change its name
  • it's fairly easy to compute another modulus from the % result

Note that % computes the "remainder" as opposed to the "modulus".

There is not an operator or function in the standard library which replicates the modulus operation of Python.

It is possible to write a function which replicates the modulus operation of Python:

func modLikePython(d, m int) int {
   var res int = d % m
   if ((res < 0 && m > 0) || (res > 0 && m < 0)) {
      return res + m
   }
   return res
}

Note that in Python 5 % -3 is -1 and this code replicates that behavior as well. If you don't want that, remove the second part after || in the if statement.

Community
  • 1
  • 1
Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242
  • Thank you for the reference. This issue slipped from me since it is closed. I will update my question to reflect this. – Kshitij Saraogi Mar 25 '17 at 15:45
  • 4
    You can simplify your Go to Python Modulus code to just: `(i % n) + n) % n`. Verified [here](https://play.golang.org/p/QT5PA9fltU) – Liam Kelly Mar 29 '17 at 02:02
16

Is there an internal method for computing the "modulus" instead of the "remainder"?

Note that % computes the "remainder" as opposed to the "modulus".

These quotes are a bit misleading.

Look up any definition of "modulo", by and large it will say that it is the remainder after division. The problem is that when we say "the remainder", it implies that there is only one. When negative numbers are involved, there can be more than one distinct remainder. On the Wikipedia page for Remainder, it differentiates between the least positive remainder and the least absolute remainder. You could also add a least negative remainder (least negative meaning negative, but closest to 0).

Generally for modulus operators, if it returned a positive value, it was the least positive remainder and if it returned a negative value, it was the least negative remainder. The sign of the returned value can be determined in multiple ways. For example given c = a mod b, you could define the sign of c to be

  • The sign of a (what % does in Go)
  • The sign of b (what % does in Python)
  • Non-negative always

Here's a list of programming languages and their modulo implementations defined in this way https://en.wikipedia.org/wiki/Modulo_operation#In_programming_languages

Here's a branchless way to replicate Python's % operator with a Go function

func mod(a, b int) int {
    return (a % b + b) % b
}

To reiterate, this follows the rule:

given c = a mod b, the sign of c will be the sign of b. Or in other words, the modulus result has the same sign as the divisor

Hymns For Disco
  • 7,530
  • 2
  • 17
  • 33
0

math/big does Euclidean modulus:

package main
import "math/big"

func mod(x, y int64) int64 {
   bx, by := big.NewInt(x), big.NewInt(y)
   return new(big.Int).Mod(bx, by).Int64()
}

func main() {
   z := mod(-5, 3)
   println(z == 1)
}

https://golang.org/pkg/math/big#Int.Mod

Zombo
  • 1
  • 62
  • 391
  • 407
0

On Q2, you could use:

func modNeg(v, m int) int {
    return (v%m + m) % m
}

Would output:

modNeg(-1, 5) => 4
modNeg(-2, 3) => 0
Ruan
  • 163
  • 1
  • 8
0

In most cases, just add the second number to the result:

Python:

-8%6 => 4

Golang:

-8%6 + 6 => 4

So the function will be like this:

func PyMod(d int, m int) int {
  d %= m
  if d < 0 { 
    d += m
  }
  return d
}

It works for some other situations such as a%-b in addition to -a%b.

But if you want it to work even for -a%-b, do like this:

func PyMod(d int, m int) int {
  // Add this condition at the top
  if d < 0 && m < 0 {
    return d % m
  } 
  d %= m
  if d < 0 { 
    d += m
  }
  return d
}
Arsham Arya
  • 1,461
  • 3
  • 17
  • 25