javascript 的 % 是求余而非取模,结果符号与被除数一致;需用 ((i % n) + n) % n 实现安全循环索引,避免负数越界。

JavaScript 中的 % 运算符不是数学意义上的“取模”,而是“求余”——它在负数场景下会给出与被除数同号的结果,这点必须明确。
JavaScript 的 % 是求余,不是取模
标准规定:JavaScript 的 % 按照“向零截断除法”(truncating division)定义。也就是说,先计算浮点除法 a / b,再把商的小数部分直接截掉(朝零取整),最后代入公式:
r = a − b × trunc(a / b)
例如:-7 % 3 → trunc(-7 / 3) = trunc(-2.333...) = -2 → -7 − 3 × (-2) = -1
结果是 -1,符号与被除数 -7 一致。
取模要求结果非负且落在 [0, b) 区间
数学中标准的模运算(如 Python 的 % 或 Java 的 Math.floorMod())使用向下取整(floor),确保余数始终 ≥ 0(当除数为正时):
r = a − b × floor(a / b)
对同一例子:-7 mod 3 → floor(-7 / 3) = floor(-2.333...) = -3 → -7 − 3 × (-3) = 2
结果是 2,落在区间 [0, 3) 内,且符号与除数 3 一致。
不同符号组合下的行为对比
记住这个规律:JavaScript 的 % 结果符号永远和**第一个操作数(被除数)**相同:
-
7 % 3→ 1(正 ÷ 正 = 正) -
-7 % 3→ -1(负 ÷ 正 = 负) -
7 % -3→ 1(正 ÷ 负 = 正) -
-7 % -3→ -1(负 ÷ 负 = 负)
而真正取模(比如用 ((a % b) + b) % b 手动修正)会统一让结果 ≥ 0(当 b > 0 时)。
需要取模语义时怎么办
如果业务逻辑依赖非负余数(比如数组索引、循环偏移、哈希桶分配),不能直接用 %,应封装安全函数:
- 对正除数
b:用((a % b) + b) % b - 更健壮写法(兼容负除数):用
((a % b) + Math.abs(b)) % Math.abs(b) - 或直接用第三方库的
mod(a, b),避免重复造轮子
不加处理直接用 % 在负数输入时可能造成索引越界、条件判断失效等隐蔽问题。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











