Describe the bug
This bug is found from property based testing.
For floating-point inputs, mx.divmod(a, b) returns a quotient that truncates
toward zero, while mx.floor_divide(a, b) correctly floors toward −∞
(matching NumPy). So for any a/b < 0 the two operations return different
quotients, and divmod's (q, r) no longer reconstruct the dividend:
q * b + r == a # the universal divmod invariant — BROKEN for floats
To Reproduce
import mlx.core as mx
import numpy as np
a, b = np.float32(-7.0), np.float32(2.0)
np.array(mx.floor_divide(mx.array(a), mx.array(b))) # -4.0 (correct, floors)
q, r = mx.divmod(mx.array(a), mx.array(b))
np.array(q), np.array(r) # (-3.0, 1.0) WRONG
# reconstruction:
(-3.0) * 2.0 + 1.0 # -5.0 != -7.0
Expected behavior
>>> a, b = np.float32(-7.0), np.float32(2.0)
>>> q, r = mx.divmod(mx.array(a), mx.array(b))
>>> np.array(q).item(), np.array(r).item()
(-3.0, 1.0) # actual — wrong
>>> # expected (NumPy parity, and consistency with mx.floor_divide):
>>> np.floor_divide(a, b), np.remainder(a, b)
(-4.0, 1.0) # q=-4, r=1; check: -4*2 + 1 = -7 ✓
>>> np.array(mx.floor_divide(mx.array(a), mx.array(b))).item()
-4.0 # mx.floor_divide is already correct for floats
FYI
a/b floor_div divmod_q divmod_r q*b+r want np_floor
-7.0/ 2.0 -4.00 -3.00 1.00 -5.00 -7.0 -4.00 <- BUG
7.0/-2.0 -4.00 -3.00 -1.00 5.00 7.0 -4.00 <- BUG
-5.5/ 2.0 -3.00 -2.00 0.50 -3.50 -5.5 -3.00 <- BUG
5.5/-2.0 -3.00 -2.00 -0.50 3.50 5.5 -3.00 <- BUG
-9.0/ 4.0 -3.00 -2.00 3.00 -5.00 -9.0 -3.00 <- BUG
floor_divide(-7.0,2.0) = -4.0 divmod(-7.0,2.0).q = -3.0 agree? False
Describe the bug
This bug is found from property based testing.
For floating-point inputs,
mx.divmod(a, b)returns a quotient that truncatestoward zero, while
mx.floor_divide(a, b)correctly floors toward −∞(matching NumPy). So for any
a/b < 0the two operations return differentquotients, and
divmod's(q, r)no longer reconstruct the dividend:To Reproduce
Expected behavior
FYI