JavaScript% (modulo) dá um resultado negativo para números negativos

De acordo com o Google Calculator (-13) % 64 é 51 .

De acordo com o Javascript (veja este JSBin ), é -13 .

Como faço para corrigir isso?

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

    Retirado deste artigo: O Bug Modulo JavaScript

    O uso do Number.prototype é SLOW, porque cada vez que você usa o método prototype, seu número é empacotado em um Object . Em vez disso:

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

    Usar:

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

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

    ~ 97% mais rápido que usar o protótipo. Se o desempenho é importante para você, claro ..

    O operador % em JavaScript é o operador de resto, não o operador de módulo (a principal diferença é como os números negativos são tratados):

    -1 % 8 // -1, not 7

    De qualquer forma aqui é um tutorial com uma function “mod” para retornar um resultado positivo.

     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 

    E claro

     mod(-13,64) // 51 

    A resposta aceita me deixa um pouco nervoso porque reutiliza o operador%. E se o JavaScript mudar o comportamento no futuro?

    Aqui está uma solução alternativa que não reutiliza%:

     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 

    Embora não esteja se comportando como você esperava, isso não significa que o JavaScript não esteja “se comportando”. É uma escolha JavaScript feita para o seu cálculo de módulo. Porque, por definição, qualquer uma das respostas faz sentido.

    Veja isso da Wikipedia. Você pode ver à direita como diferentes idiomas escolhem o sinal do resultado.

    Se x é um inteiro e n é uma potência de 2, você pode usar x & (n - 1) vez de x % n .

     > -13 & (64 - 1) 51 

    Então, parece que se você está tentando modificar em torno de graus (de modo que se você tem -50 graus – 200 graus), você gostaria de usar algo como:

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

    Operação de módulo do JavaScript

    A implementação bem-sucedida de um cálculo ou algoritmo científico é possível não apenas pela compreensão dos resources que uma determinada linguagem ou estrutura oferece, mas também pela compreensão das limitações.

    Computadores são instrumentos científicos precisos, mas funcionam manipulando entidades em espaços discretos (você tem um número limitado de pixels na canvas, há um número limitado de bits que estão por trás de cada número, etc.)

    Tente ignorar as limitações ou especificações do framework e logo você descobrirá que tem uma incompatibilidade de impedância entre sua fórmula matemática e o código que você tenta escrever.

    Operador Modulo

    Às vezes, as situações são complicadas por funções ou operadores de estrutura falsamente anunciados ou compreendidos. Este artigo enfoca o operador de módulo.

    Pergunte a qualquer programador C # ou JavaScript qual é o operador de módulo em seu idioma e há uma grande chance de que ele tenha atendido:% (por exemplo, o sinal de porcentagem). Muita documentação se refere ao sinal% como operador de módulo.

    Uau! Este é um erro sutil, mas muito perigoso. Em C # e JavaScript% operator é utilizado para calcular o restante (com sinal) restante quando um operando é dividido pelo segundo operando. Portanto, o operando deve ser corretamente chamado de operador de resto assinado.

    À primeira vista, o operador de resto assinado funciona de forma semelhante ao operador de módulo. Vamos fazer alguns testes comparando os resultados retornados pelo JavaScript com os retornados pelo Google.

    No Chrome, abra o console (pressione F12 e selecione a guia Console). Digite lá, um por um, os cálculos da coluna da esquerda. Em seguida, digite as mesmas expressões na barra de pesquisa do Google. Observe os resultados. Eles deveriam ser os mesmos.

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

    Vamos agora tentar usar um valor negativo como o primeiro operando:

    insira a descrição da imagem aqui

    Surpresa!

    -5% 3 = 1 (de acordo com o Google) -5% 3 = -2 (de acordo com o JavaScript)

    Bem… isso não deveria ser uma surpresa se olharmos para a definição de% operator em JavaScript (… ou mesmo em C # ou em muitos outros idiomas). O Google calcula o módulo verdadeiro, enquanto esses idiomas calculam um lembrete assinado.

    No entanto, nem todas as linguagens de programação / frameworks têm a mesma implementação para%. Em Python, por exemplo, o operador% calcula o módulo verdadeiro da mesma maneira que o Google.

    insira a descrição da imagem aqui

    Essa diferença de comportamento entre idiomas pode introduzir erros sutis em seu cálculo, especialmente se você estiver tentando portar um algoritmo de um idioma para outro!

    Um problema entendido é um problema meio resolvido

    Vamos supor que precisamos implementar um cálculo (científico) em JavaScript usando a aritmética do módulo.

    Como agora entendemos que o JavaScript não possui um operador de módulo verdadeiro, podemos implementar facilmente nossa operação de módulo como uma function.

    Existem várias maneiras de implementar o módulo em JavaScript. Eu vou te mostrar 3 maneiras de fazer isso.

     // 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 ); } 

    Com ferramentas mais precisas à nossa disposição, agora estamos prontos para lidar com esse cálculo (científico) e esperar obter resultados corretos a cada vez.

    Nota: Existem muitos cálculos que fazem uso da aritmética do módulo… Se você quiser ver como usar essas novas funções do módulo na implementação de um código Cesar Cipher / ROT13, você pode verificar este artigo .

    Eu lido com négative a e negative n também

      //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); } 

    Este não é um bug, existem 3 funções para calcular o módulo, você pode usar o que se adequa às suas necessidades (eu recomendaria usar a function Euclideana)

    Truncar a function da parte decimal

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

    Função de parte inteira

     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 

    Função euclidiana

     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 

    Existe um pacote NPM que fará o trabalho para você. Você pode instalá-lo com o seguinte comando.

    npm install just-modulo --save

    Uso copiado do 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 

    O repository do GitHub pode ser encontrado através do seguinte link:

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