JavaScript % (modulo) 给出负数的负结果

IT技术 javascript math modulo
2021-01-14 05:28:18

根据谷歌计算器 (-13) % 6451.

根据 Javascript(请参阅此JSBin),它是-13.

我该如何解决?

6个回答
Number.prototype.mod = function (n) {
  return ((this % n) + n) % n;
};

摘自这篇文章:JavaScript Modulo Bug

我建议在答案中添加访问此功能的人应使用格式 (-13).mod(10) 而不是 -13 % 10。这样会更清楚。
2021-03-12 05:28:18
为什么在添加 n 之前取模?为什么不加 n 然后取模?
2021-03-20 05:28:18
@starwed 如果你不使用这个%n 它会失败x < -n- 例如(-7 + 5) % 5 === -2但是((-7 % 5) + 5) % 5 == 3
2021-03-27 05:28:18
我不知道我会称它为“错误”。模运算对负数的定义不是很好,不同的计算环境处理它的方式也不同。维基百科关于模运算的文章很好地涵盖了它。
2021-03-31 05:28:18
它可能看起来很愚蠢,因为它通常被称为“模”,这表明它的行为与其数学定义相同(参见 ℤ/nℤ 代数),但事实并非如此。
2021-04-02 05:28:18

使用Number.prototype很慢,因为每次使用原型方法时,您的数字都会被包裹在Object. 取而代之的是:

Number.prototype.mod = function(n) {
  return ((this % n) + n) % n;
}

利用:

function mod(n, m) {
  return ((n % m) + m) % m;
}

见:http : //jsperf.com/negative-modulo/2

比使用原型快 97%。如果性能对你来说当然很重要..

很棒的提示。我拿了你的 jsperf 并与这个问题中的其他解决方案进行了比较(但似乎这是最好的):jsperf.com/negative-modulo/3
2021-03-13 05:28:18
微优化。您必须为此进行大量的 mod 计算才能产生任何差异。编写最清晰、最易于维护的代码,然后优化以下性能分析。
2021-03-21 05:28:18
我认为您在第二个示例 @StuR 中的ns 和ms 方法错误。应该是return ((n % m) + m) % m;
2021-03-24 05:28:18
@JeneralJames 更改原型的主要问题是命名空间冲突。归根结底,这只是全球数据的突变。除了小的一次性代码之外,改变全局变量是不好的做法。将函数导出为可跟踪的依赖项。作为规则的例外,Polyfill 在这里无关紧要。这不是 polyfill。真正的 polyfill 遵循使碰撞安全的标准。如果你想在原则上争论这个,有一个单独的问题。stackoverflow.com/questions/6223449/...
2021-03-25 05:28:18
这个答案中陈述的动机是微优化,是的,但是修改原型是有问题的。更喜欢副作用最少的方法,就是这个。
2021-04-10 05:28:18

%JavaScript中运算符是求余运算符,而不是模运算符(如何负数的处理方式主要区别):

-1 % 8 // -1, not 7

“mod”应该从一开始就被实施到每种语言中。经过 30 年的编程,当 a 为负时,我——从不——需要 % b:每一次,我需要的是 mod(a,b)。
2021-03-17 05:28:18
应该被称为余数运算符,但它称为模运算符:developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/...
2021-03-25 05:28:18
@Ahmad——它现在被称为乘法运算符
2021-03-29 05:28:18
如果调用remainder,则根据定义它必须大于 0。你还记得高中除法定理吗?!所以也许你可以看看这里:en.wikipedia.org/wiki/Euclidean_division
2021-04-05 05:28:18
@DaveKennedy:MDN 不是官方语言参考,它是一个社区编辑的网站,有时会出错。规范没有称它为模运算符,据我所知它从来没有(我回到 ES3)。它明确表示运算符产生隐含除法的余数,并称其为“% 运算符”。
2021-04-07 05:28:18

返回正结果的“mod”函数。

var mod = function (n, m) {
    var remain = n % m;
    return Math.floor(remain >= 0 ? remain : remain + m);
};
mod(5,22)   // 5
mod(25,22)  // 3
mod(-1,22)  // 21
mod(-2,22)  // 20
mod(0,22)   // 0
mod(-1,22)  // 21
mod(-21,22) // 1

而且当然

mod(-13,64) // 51
糟糕,您指定的链接实际上是#sec-applying-the-mod-operator在 url 中引用的 :) 无论如何,感谢您的注意,我从答案中删除了绒毛,无论如何这并不重要。
2021-03-14 05:28:18
MDN 不是官方语言参考,它是一个社区编辑的站点,有时会出错。规范没有称它为模运算符,据我所知它从来没有(我回到 ES3)。它明确表示运算符产生隐含除法的余数,并称其为“% 运算符”。
2021-03-26 05:28:18
//@山尼玛:大声笑!确实如此。HTML 编辑器出错。规范文本没有。
2021-04-03 05:28:18

接受的答案让我有点紧张,因为它重新使用了 % 运算符。如果 Javascript 将来改变行为怎么办?

这是一个不重复使用 % 的解决方法:

function mod(a, n) {
    return a - (n * Math.floor(a/n));
}

mod(1,64); // 1
mod(63,64); // 63
mod(64,64); // 0
mod(65,64); // 1
mod(0,64); // 0
mod(-1,64); // 63
mod(-13,64); // 51
mod(-63,64); // 1
mod(-64,64); // 0
mod(-65,64); // 63
+1 分享这种关注和替代特色答案#answer-4467559 以及4 个原因:(1) 为什么它声明,&是的“不太可能改变这样一个基本操作的行为”,但仍需谨慎考虑甚至发现它是不需要的。(2) 根据损坏的操作定义工作操作,虽然令人印象深刻,但至少在第一次看时令人担忧,应该直到显示为止 (3) 虽然我没有很好地验证这个替代方案,但我发现更容易遵循快速浏览。(4)tiny:它使用 1 div+1 mul 而不是 2 (mod) div & 我听说过很多早期的硬件 w/oa 好的 FPU,乘法速度更快。
2021-03-21 05:28:18
如果 javascript 更改模运算符以匹配数学定义,则接受的答案仍然有效。
2021-03-24 05:28:18
@DestinyArchitect 这不谨慎,毫无意义。如果他们要改变余数运算符的行为,就会破坏使用它的大量程序。那永远不会发生。
2021-03-24 05:28:18
“如果 Javascript 将来改变行为怎么办?” - 为什么会这样?改变这样一个基本运算符的行为是不可能的。
2021-03-26 05:28:18
如果-, *, /, ;, ., (, ), ,, Math.floor,function或 的行为return发生了什么变化?那么你的代码被严重破坏了。
2021-04-10 05:28:18