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

JavaScript%(模)给出负数的负结果,javascript,math,modulo,Javascript,Math,Modulo,根据(-13)%64是51 根据Javascript(见此),它是-13 我该如何解决这个问题 Number.prototype.mod = function(n) { return ((this%n)+n)%n; }; 摘自本文:尽管它的行为不像您预期的那样,但这并不意味着JavaScript没有“行为”。它是为其模计算而做出的选择。因为,从定义上来说,这两个答案都是有意义的 参见维基百科。您可以在右侧看到不同语言如何选择结果的符号。JavaScript中的%运算符是余数运算符,而不

根据
(-13)%64
51

根据Javascript(见此),它是
-13

我该如何解决这个问题

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

摘自本文:

尽管它的行为不像您预期的那样,但这并不意味着JavaScript没有“行为”。它是为其模计算而做出的选择。因为,从定义上来说,这两个答案都是有意义的


参见维基百科。您可以在右侧看到不同语言如何选择结果的符号。

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

-1%8/-1,而不是7

一个“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

被接受的答案让我有点紧张,因为它重新使用了%运算符。如果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

使用
Number.prototype
速度很慢,因为每次使用prototype方法时,您的编号都被包装在
对象中。与此相反:

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

见:


比使用原型快约97%。当然,如果性能对您很重要。

这不是一个bug,有3个函数可以计算模,您可以使用一个适合您需要的函数(我建议使用欧几里德函数)

截断小数部分函数 整数部分函数 欧几里德函数
Number.prototype.mod=函数(n){
var m=((此%n)+n)%n;
返回m<0?m+Math.abs(n):m;
};
console.log(parseInt(41.mod(7));//6.
console.log(parseInt(-41.mod(7));//1.
console.log(parseInt(-41.mod(-7));//1.
console.log(parseInt(41.mod(-7));//6.

因此,如果您尝试在度数附近进行调整(如果您有-50度-200度),您可能会希望使用以下方法:

function modrad(m) {
    return ((((180+m) % 360) + 360) % 360)-180;
}

如果
x
是整数,
n
是2的幂,则可以使用
x&(n-1)
而不是
x%n

> -13 & (64 - 1)
51 

我也处理négative a和负n

 //best perf, hard to read
   function modul3(a,n){
        r = a/n | 0 ;
        if(a < 0){ 
            r += n < 0 ? 1 : -1
        }
        return a - n * r 
    }
    // shorter code
    function modul(a,n){
        return  a%n + (a < 0 && Math.abs(n)); 
    }

    //beetween perf and small code
    function modul(a,n){
        return a - n * Math[n > 0 ? 'floor' : 'ceil'](a/n); 
    }
//最佳性能,难以阅读
功能模块3(a,n){
r=a/n | 0;
如果(a<0){
r+=n<0?1:-1
}
返回a-n*r
}
//短码
函数模(a,n){
返回一个%n+(a<0&&Math.abs(n));
}
//beetween性能和小代码
函数模(a,n){
返回a-n*Math[n>0?'floor':'ceil'](a/n);
}

有一个NPM包可以为您完成这项工作。您可以使用以下命令安装它

npm仅按模安装--保存

从自述文件复制的用法

import modulo from 'just-modulo';

modulo(7, 5); // 2
modulo(17, 23); // 17
modulo(16.2, 3.8); // 17
modulo(5.8, 3.4); //2.4
modulo(4, 0); // 4
modulo(-7, 5); // 3
modulo(-2, 15); // 13
modulo(-5.8, 3.4); // 1
modulo(12, -1); // NaN
modulo(-3, -8); // NaN
modulo(12, 'apple'); // NaN
modulo('bee', 9); // NaN
modulo(null, undefined); // NaN
可以通过以下链接找到GitHub存储库:



这可能只是一个优先问题。你是说
(-13)%64
还是
-(13%64)
?就我个人而言,为了更清楚起见,我会把parens放在其中。本质上是的一个副本,尽管这是一个javascript问题。javascript有时感觉像是一个非常残酷的笑话,这是不会错的。根本问题在于JS
%
不是模运算符。这是余数运算符。JavaScript中没有模运算符。因此,公认的答案是正确的。我不知道我会称之为“bug”。对于负数,模运算的定义不是很好,不同的计算环境处理它的方式也不同。维基百科的文章对它进行了很好的描述。它可能看起来很愚蠢,因为它通常被称为“模”,表明它的行为与其数学定义相同(参见ℤ/Nℤ 代数),但它不是。为什么在加n之前取模?为什么不直接加n然后取模呢?@starwed如果你不使用这个%n,它将在
x<-n
-例如
(-7+5)%5===-2
但是
(-7%5)+5)%5==3
中失败。我建议你在答案中补充一点,要访问这个函数,应该使用格式(-13)。mod(10)而不是-13%10。这会更清楚。很好的提示。我拿了你的jsperf,并与这个问题中的其他解决方案进行了比较(但似乎这是最好的):微观优化。你必须要做大量的mod计算才能产生任何不同。编写最清晰、最可维护的代码,然后优化以下性能分析。我认为在第二个示例@StuR中,您的ns和ms的使用方法是错误的。它应该是
return((n%m)+m)%m。这应该是对已接受答案的评论,而不是答案本身。答案中所述的动机是微观优化,是的,但修改原型是有问题的。更喜欢副作用最少的方法,就是这个。它应该称为余数运算符,但称为模数运算符:@DaveKennedy:MDN不是官方语言参考,它是一个社区编辑的网站,有时会出错。不称它为模运算符,据我所知,它从来没有(我回到ES3)。它明确地表示运算符产生隐含除法的余数,并将其称为“%运算符”。如果称为
余数
,则根据定义它必须大于0。难道你不记得高中时的除法定理吗?!所以也许你可以看看这里:@Ahmad它现在被称为“mod”,应该从一开始就在每种语言中实现。经过30年的编程,当a为负值时,我——从未——需要a%b:每次,我需要的都是mod(a,b)。如果javascript更改模运算符以匹配数学定义,则公认的答案仍然有效。“如果javascript在将来更改行为会怎么样?”-为什么?改变这样一个基本运算符的行为是不可能的。+1用于分享这一问题&替代th
function modrad(m) {
    return ((((180+m) % 360) + 360) % 360)-180;
}
> -13 & (64 - 1)
51 
 //best perf, hard to read
   function modul3(a,n){
        r = a/n | 0 ;
        if(a < 0){ 
            r += n < 0 ? 1 : -1
        }
        return a - n * r 
    }
    // shorter code
    function modul(a,n){
        return  a%n + (a < 0 && Math.abs(n)); 
    }

    //beetween perf and small code
    function modul(a,n){
        return a - n * Math[n > 0 ? 'floor' : 'ceil'](a/n); 
    }
import modulo from 'just-modulo';

modulo(7, 5); // 2
modulo(17, 23); // 17
modulo(16.2, 3.8); // 17
modulo(5.8, 3.4); //2.4
modulo(4, 0); // 4
modulo(-7, 5); // 3
modulo(-2, 15); // 13
modulo(-5.8, 3.4); // 1
modulo(12, -1); // NaN
modulo(-3, -8); // NaN
modulo(12, 'apple'); // NaN
modulo('bee', 9); // NaN
modulo(null, undefined); // NaN