The math.remainder(x, y) function computes the IEEE 754-2008 standard remainder of x with respect to y, defined as r = x − (n × y), where n is the integer nearest to x / y. Unlike Python's modulo operator (%) or math.fmod(), the result is strictly bounded within the symmetric range [−|y|/2, |y|/2].
Ties to Even: If x / y lies exactly halfway between two consecutive integers (e.g. 1.5 or 2.5), n is chosen to be the nearest even integer (banker's rounding).
The math.remainder() function was introduced in Python 3.7 as part of the standard math module:
import math
r = math.remainder(x, y)
| Parameter | Type | Description |
|---|---|---|
x |
float or int |
Required. The numerator (dividend). |
y |
float or int |
Required. The denominator (divisor). Must not be zero. |
| Return Value | float |
The IEEE 754 remainder within [−|y|/2, |y|/2]. |
ValueError |
Exception | Raised when y == 0 or when x is infinite. |
TypeError |
Exception | Raised when passing non-numeric arguments (strings, lists, None). |
To understand why math.remainder(12, 7) produces -2.0 while 12 % 7 produces 5, look at the quotient:
x / y = 12 / 7 ≈ 1.714.1.714 is 2 (not 1).r = x - (n * y) = 12 - (2 * 7) = 12 - 14 = -2.0.import math
print("remainder(12, 7):", math.remainder(12, 7)) # 12 / 7 = 1.71 -> n=2 -> 12 - 14 = -2.0
print("remainder(12, 5):", math.remainder(12, 5)) # 12 / 5 = 2.40 -> n=2 -> 12 - 10 = 2.0
print("remainder(13, 7):", math.remainder(13, 7)) # 13 / 7 = 1.86 -> n=2 -> 13 - 14 = -1.0
print("remainder(10, 3):", math.remainder(10, 3)) # 10 / 3 = 3.33 -> n=3 -> 10 - 9 = 1.0
Output:
remainder(12, 7): -2.0
remainder(12, 5): 2.0
remainder(13, 7): -1.0
remainder(10, 3): 1.0
Python offers three distinct remainder functions, each following a different integer rounding rule for the quotient n:
| Operation | Quotient Rule n |
Sign of Remainder | Output Range | Zero Divisor Error |
|---|---|---|---|---|
math.remainder(x, y) |
Nearest integer (round to even) | Can be positive or negative | [−|y|/2, |y|/2] |
ValueError |
math.fmod(x, y) |
Truncated towards zero | Same sign as x |
(-|y|, |y|) |
ValueError |
x % y (Modulo) |
Floor towards -∞ | Same sign as y |
[0, y) if y > 0 |
ZeroDivisionError |
Comparing outcomes across mixed-sign numbers:
import math
test_pairs = [(12, 7), (7, 4), (-12, 7), (12, -7), (-12, -7)]
print(f"{'Pair (x, y)':>14} | {'math.remainder':>15} | {'math.fmod':>10} | {'x % y':>6}")
print("-" * 52)
for x, y in test_pairs:
rem = math.remainder(x, y)
fmod_val = math.fmod(x, y)
mod_op = x % y
print(f"{str((x, y)):>14} | {rem:15.1f} | {fmod_val:10.1f} | {mod_op:6.1f}")
Output:
Pair (x, y) | math.remainder | math.fmod | x % y
----------------------------------------------------
(12, 7) | -2.0 | 5.0 | 5.0
(7, 4) | -1.0 | 3.0 | 3.0
(-12, 7) | 2.0 | -5.0 | 2.0
(12, -7) | -2.0 | 5.0 | -2.0
(-12, -7) | 2.0 | -5.0 | -5.0
When x / y lands exactly on a .5 boundary halfway between two integers, math.remainder() breaks the tie by choosing the nearest even integer:
import math
# 1.5 / 1.0 = 1.5 -> nearest integers are 1 and 2 -> choose even 2 -> 1.5 - 2*1 = -0.5
print("remainder(1.5, 1.0):", math.remainder(1.5, 1.0)) # -0.5
# 2.5 / 1.0 = 2.5 -> nearest integers are 2 and 3 -> choose even 2 -> 2.5 - 2*1 = 0.5
print("remainder(2.5, 1.0):", math.remainder(2.5, 1.0)) # 0.5
# 3.5 / 1.0 = 3.5 -> nearest integers are 3 and 4 -> choose even 4 -> 3.5 - 4*1 = -0.5
print("remainder(3.5, 1.0):", math.remainder(3.5, 1.0)) # -0.5
Output:
remainder(1.5, 1.0): -0.5
remainder(2.5, 1.0): 0.5
remainder(3.5, 1.0): -0.5
The most important real-world application of math.remainder() is angle wrapping. In robotics, flight avionics, and 3D game engines, angular bearings must be normalized so that deviations are represented within a symmetric range about zero:
math.remainder(angle, 360) normalizes any heading into [−180°, 180°].math.remainder(angle, 2 * math.pi) normalizes any angle into [−π, π].import math
angles_deg = [370, 350, 190, -200, 725]
print(f"{'Original':>10} | {'Normalized [-180, 180]':>24}")
print("-" * 38)
for a in angles_deg:
norm = math.remainder(a, 360)
print(f"{a:9d}° | {norm:22.1f}°")
Output:
Original | Normalized [-180, 180]
--------------------------------------
370° | 10.0°
350° | -10.0°
190° | -170.0°
-200° | 160.0°
725° | 5.0°
Examine how math.remainder() handles division by zero and IEEE 754 non-finite values:
import math
# 1. Zero divisor raises ValueError (unlike modulo which raises ZeroDivisionError)
try:
math.remainder(10.0, 0.0)
except ValueError as err:
print("remainder(10, 0) ValueError:", err)
# 2. Infinite dividend raises ValueError
try:
math.remainder(float('inf'), 5.0)
except ValueError as err:
print("remainder(inf, 5) ValueError:", err)
# 3. Finite dividend with infinite divisor returns dividend
print("remainder(7.0, inf): ", math.remainder(7.0, float('inf'))) # 7.0
Output:
remainder(10, 0) ValueError: math domain error
remainder(inf, 5) ValueError: math domain error
remainder(7.0, inf): 7.0
In autonomous mobile robotics and self-driving vehicles, an onboard navigator must compute the shortest rotational steering delta (Δθ) to align the robot's current heading with a waypoint bearing. Using math.remainder() ensures the robot always turns via the shortest arc without glitching across the 0°/360° boundary:
import math
def calculate_steering_turn(current_heading, target_heading):
"""
Computes the shortest angular turn in degrees from current_heading to target_heading.
Returns:
- Positive float: turn right (clockwise)
- Negative float: turn left (counter-clockwise)
- Float strictly in range [-180.0, 180.0]
"""
if not (isinstance(current_heading, (int, float)) and isinstance(target_heading, (int, float))):
raise TypeError("Headings must be numeric values.")
raw_delta = target_heading - current_heading
turn_angle = math.remainder(raw_delta, 360.0)
return round(turn_angle, 2)
# Unit Assertions
# 1. Simple clockwise turn: 45° -> 90° requires +45°
assert calculate_steering_turn(45, 90) == 45.0
# 2. Simple counter-clockwise turn: 90° -> 45° requires -45°
assert calculate_steering_turn(90, 45) == -45.0
# 3. Crossing the North meridian (350° to 10°): shortest turn is +20° right (not -340°)
assert calculate_steering_turn(350, 10) == 20.0
# 4. Crossing the North meridian counter-clockwise (10° to 350°): shortest turn is -20°
assert calculate_steering_turn(10, 350) == -20.0
# 5. Exactly opposite direction (180°): bank tie-breaking to even yields 180.0
assert calculate_steering_turn(0, 180) == 180.0
print("Steering turn from 355° to 15°:", calculate_steering_turn(355, 15), "°")
print("All robotics steering navigator assertions passed successfully!")
Open in Google Colab View on GitHub
Run all math.remainder() examples interactively, contrast precision with math.fmod() and %, test half-to-even tie breaking, and execute robotics heading calculations in Google Colab.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.