JavaScript % (modulo) geeft een negatief resultaat voor negatieve getallen

Volgens Google Calculator(-13) % 64is 51.

Volgens Javascript (zie deze JSBin) is het -13.

Hoe los ik dit op?


Antwoord 1, autoriteit 100%

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

Uit dit artikel: De JavaScript Modulo-bug


Antwoord 2, autoriteit 65%

Het gebruik van Number.prototypeis LANGZAAM, omdat elke keer dat u de prototypemethode gebruikt, uw nummer wordt verpakt in een Object. In plaats van dit:

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

Gebruik:

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

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

~97% sneller dan het gebruik van een prototype. Als prestaties voor jou belangrijk zijn natuurlijk..


Antwoord 3, autoriteit 11%

De %-operator in JavaScript is de rest-operator, niet de modulo-operator (het belangrijkste verschil is hoe negatieve getallen worden behandeld):

-1 % 8 // -1, not 7


Antwoord 4, autoriteit 6%

Een “mod”-functie om een ​​positief resultaat te retourneren.

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

En natuurlijk

mod(-13,64) // 51

Antwoord 5, autoriteit 3%

Het geaccepteerde antwoord maakt me een beetje nerveus omdat het de %-operator opnieuw gebruikt. Wat als Javascript het gedrag in de toekomst verandert?

Hier is een tijdelijke oplossing waarbij % niet opnieuw wordt gebruikt:

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

Antwoord 6, autoriteit 2%

Als xeen geheel getal is en neen macht van 2 is, kun je x & (n - 1)in plaats van x % n.

> -13 & (64 - 1)
51 

Antwoord 7

Hoewel het zich niet gedraagt ​​zoals u had verwacht, betekent dit niet dat JavaScript zich niet ‘gedraagt’. Het is een keuze die JavaScript heeft gemaakt voor zijn modulo-berekening. Omdat beide antwoorden per definitie logisch zijn.

Zie ditvan Wikipedia. Je kunt rechts zien hoe verschillende talen het teken van het resultaat hebben gekozen.


Antwoord 8

Dit is geen bug, er zijn 3 functies om modulo te berekenen, je kunt degene gebruiken die aan je behoeften voldoet (ik raad aan om de Euclidische functie te gebruiken)

De decimale deelfunctie afkappen

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

Gehele deelfunctie

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

Euclidische functie

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

Antwoord 9

Dus het lijkt erop dat als je probeert om graden te modificeren (zodat als je -50 graden – 200 graden hebt), je zoiets wilt gebruiken als:

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

Antwoord 10

Ik heb ook te maken met negatieve a en negatieve 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); 
    }

Antwoord 11

Er is een NPM-pakket dat het werk voor u doet. Je kunt het installeren met het volgende commando.

npm install just-modulo --save

Gebruik gekopieerd van de 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-repository is te vinden via de volgende link:

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


Antwoord 12

Voor de lol, hier is een “wrap”-functie die een beetje als een modulo werkt, behalve dat je ook de minimumwaarde van het bereik kunt specificeren (in plaats van dat het 0 is):

const wrap = (value = 0, min = 0, max = 10) =>
  ((((value - min) % (max - min)) + (max - min)) % (max - min)) + min;

Eigenlijk gewoon de echte modulo-formule, compenseert het zodanig dat mineindigt op 0, en voegt daarna minweer toe.

Handig als je een waarde hebt die je tussen twee waarden wilt houden.

Other episodes