54

What does modulo in the following piece of code do?

from math import *
3.14 % 2 * pi

How do we calculate modulo on a floating point number?

Michel
  • 769
  • 4
  • 19
KodeWarrior
  • 3,538
  • 3
  • 26
  • 40

5 Answers5

66

When you have the expression:

a % b = c

It really means there exists an integer n that makes c as small as possible, but non-negative.

a - n*b = c

By hand, you can just subtract 2 (or add 2 if your number is negative) over and over until the end result is the smallest positive number possible:

  3.14 % 2
= 3.14 - 1 * 2
= 1.14

Also, 3.14 % 2 * pi is interpreted as (3.14 % 2) * pi. I'm not sure if you meant to write 3.14 % (2 * pi) (in either case, the algorithm is the same. Just subtract/add until the number is as small as possible).

Blender
  • 289,723
  • 53
  • 439
  • 496
  • 3
    I prefer the explanation x%y is x - (math.floor(x/y)*y) which is the same as what you said but looks more understandable to me – sabbahillel Jan 28 '16 at 18:29
  • @sabbahillel And that is why `(-123) % 10 == 7` in python3, while the result is -3 in other languages like C++. Because `(-123) - (math.floor(-123/10)*10) == 7` – very hit Mar 02 '18 at 13:51
  • @veryhit Do you know any reference to the Python sourceCode where % is defined as x - (math.floor(x/y)*y) ? Is % defined differently in cPython ? I know documentation for the math.fmod method, but I want to know how the native % operator is defined. – MNCODE May 23 '18 at 11:13
  • 1
    @MNCODE: Here's how it's defined in CPython: https://github.com/python/cpython/blob/0301c9bdd1ebd788d1334cf3fe06c48f35bab0dc/Objects/floatobject.c#L587-L615 – Blender May 23 '18 at 18:29
26

In addition to the other answers, the fmod documentation has some interesting things to say on the subject:

math.fmod(x, y)

Return fmod(x, y), as defined by the platform C library. Note that the Python expression x % y may not return the same result. The intent of the C standard is that fmod(x, y) be exactly (mathematically; to infinite precision) equal to x - n*y for some integer n such that the result has the same sign as x and magnitude less than abs(y). Python’s x % y returns a result with the sign of y instead, and may not be exactly computable for float arguments. For example, fmod(-1e-100, 1e100) is -1e-100, but the result of Python’s -1e-100 % 1e100 is 1e100-1e-100, which cannot be represented exactly as a float, and rounds to the surprising 1e100. For this reason, function fmod() is generally preferred when working with floats, while Python’s x % y is preferred when working with integers.

Thomas
  • 174,939
  • 50
  • 355
  • 478
3

Same thing you'd expect from normal modulo .. e.g. 7 % 4 = 3, 7.3 % 4.0 = 3.3

Beware of floating point accuracy issues.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Xorlev
  • 8,561
  • 3
  • 34
  • 36
2

same as a normal modulo 3.14 % 6.28 = 3.14, just like 3.14%4 =3.14 3.14%2 = 1.14 (the remainder...)

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
  • @MadPhysicist what? the order of operations of modulo is the same as pow ... certainly less than equals ... so whats the issue? – Joran Beasley Feb 06 '15 at 17:58
  • 1
    `%` has the same precedence as `/`, which is definitely less than pow (same as times though). `3.14 % 2 * pi` is the same as `(3.14 % 2) * pi == 1.14 * pi` rather than `3.14 % (2 * pi)`. – Mad Physicist Feb 06 '15 at 22:39
  • I dont have any times or divides in my answer... if I did I would probably group things with parens ... Im not entirely sure what you are saying Oh I c now ... in the original question its not quite clear where the OP would like the parens `3.14 % ( 2*pi)` however is still `3.14` which my example was trying to demonstrate with a number less than 3.14 ... afaik the question was not about the order of operations but meh – Joran Beasley Feb 06 '15 at 22:41
  • Fair enough. I can't remove the downvote now, although the answer makes sense now that you explained it. – Mad Physicist Feb 07 '15 at 07:36
1

you should use fmod(a,b)

While abs(x%y) < abs(y) is true mathematically, for floats it may not be true numerically due to roundoff.

For example, and assuming a platform on which a Python float is an IEEE 754 double-precision number, in order that -1e-100 % 1e100 have the same sign as 1e100, the computed result is -1e-100 + 1e100, which is numerically exactly equal to 1e100.

Function fmod() in the math module returns a result whose sign matches the sign of the first argument instead, and so returns -1e-100 in this case. Which approach is more appropriate depends on the application.

where x = a%b is used for integer modulo

Sakhri Houssem
  • 975
  • 2
  • 16
  • 32