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

时间:2010-12-17 03:55:34

标签: javascript math modulo

根据Google Calculator (-13) % 64 51

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

我该如何解决这个问题?

12 个答案:

答案 0 :(得分:225)

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

取自本文:The JavaScript Modulo Bug

答案 1 :(得分:129)

使用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%。如果表现当然对你很重要..

答案 2 :(得分:25)

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

-1 % 8 // -1, not 7

答案 3 :(得分:14)

“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

答案 4 :(得分:9)

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

答案 5 :(得分:8)

JavaScript模运算

成功实施科学计算或算法不仅可以通过了解特定语言或框架提供的功能,还可以了解其局限性。

计算机是精确的科学仪器,但它们通过操纵离散空间中的实体来工作(屏幕上的像素数量有限,每个数字后面的位数有限,等等。)

尝试忽略限制或框架规范,很快您就会发现数学公式与您尝试编写的代码之间存在阻抗不匹配。

模运算符

有时,错误地宣传或理解框架功能或操作员会使情况变得复杂。本文重点介绍模运算符。

询问任何C#或JavaScript程序员他们的语言中的模运算符是什么,他们很可能会回答:%(例如百分号)。大量文档将%符号称为模运算符。

哇!这是一个微妙但非常危险的错误。在C#和JavaScript中,%运算符实际用于计算当一个操作数除以第二个操作数时剩余的余数(带符号)。因此,操作数应正确地称为有符号余数运算符。

乍一看,带符号的余数运算符的功能与模运算符类似。让我们通过将JavaScript返回的结果与Google返回的结果进行比较来进行一些测试。

在Chrome中,打开控制台(按F12并选择控制台选项卡)。从左列开始逐个输入。接下来在Google搜索栏中输入相同的表达式。注意结果。它们应该是一样的。

                JavaScript  Google
    5 % 3       2           2
    26 % 26     0           0
    15 % 12     3           3

现在让我们尝试使用负值作为第一个操作数:

enter image description here

惊喜!

-5%3 = 1(根据Google) -5%3 = -2(根据JavaScript)

嗯......如果我们看一下JavaScript中的%运算符(或者甚至是C#或许多其他语言)的定义,这实际上不应该是一个惊喜。 Google会计算真正的模数,而这些计算机语言会计算签名提醒。

但是,并非所有编程语言/框架都具有相同的%实现。例如,在Python中,%运算符以与Google相同的方式计算真模数。

enter image description here

语言之间的这种行为差异可能会在计算中引入细微的错误,尤其是当您尝试将算法从一种语言移植到另一种语言时!

理解的问题是问题解决了一半

假设我们需要使用模运算在JavaScript中实现(科学)计算。

由于我们现在明白JavaScript没有真正的模运算符,我们可以很容易地将模运算作为函数来实现。

有多种方法可以在JavaScript中实现modulo。我将向您展示3种方法。

// Implement modulo by replacing the negative operand 
// with an equivalent positive operand that has the same wrap-around effect
function mod(n, p)
{
    if ( n < 0 )
        n = p - Math.abs(n) % p;

    return n % p;
}

// Implement modulo by relying on the fact that the negative remainder
// is always p numbers away from a positive reminder
// Ex: -5 % 3 | -5 = -2 * 3 + 1 and -5 = -1 * 3 + (-2) | -2 + 3 = 1  
function mod(n, p)
{
    var r = n % p;

    return r < 0 ? r + p : r;
}

// Implement modulo by solving n = v * p + r equation  
function mod(n, p) 
{
    return n - p * Math.floor( n / p );
}

我们可以使用更精确的工具,现在我们已准备好解决(科学)计算,并期望每次都能获得正确的结果。

注意:有很多计算使用模运算...如果你想看看如何在Caesar Cipher / ROT13代码的实现中使用这些新的模数函数,你可以检查这个article。 / p>

答案 6 :(得分:3)

虽然它的行为不符合您的预期,但并不意味着JavaScript不会“表现”。它是用于模数计算的JavaScript选择。因为,根据定义,答案都是有道理的。

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

答案 7 :(得分:3)

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

> -13 & (64 - 1)
51 

答案 8 :(得分:2)

所以看起来如果你试图修正度数(如果你有-50度 - 200度),你会想要使用类似的东西:

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

答案 9 :(得分:1)

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

截断小数部分功能

console.log(  41 %  7 ); //  6
console.log( -41 %  7 ); // -6
console.log( -41 % -7 ); // -6
console.log(  41 % -7 ); //  6

整数部分功能

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

console.log( parseInt( 41).mod( 7) ); //  6
console.log( parseInt(-41).mod( 7) ); //  1
console.log( parseInt(-41).mod(-7) ); // -6
console.log( parseInt( 41).mod(-7) ); // -1

欧几里德函数

Number.prototype.mod = function(n) {
    var m = ((this%n)+n)%n;
    return 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

答案 10 :(得分:1)

我处理négativea和负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); 
    }

答案 11 :(得分:0)

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

npm install just-modulo --save

从README中复制的用法

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存储库:

https://github.com/angus-c/just/tree/master/packages/number-modulo

相关问题