it-swarm.com.de

JavaScript% (Modulo) ergibt ein negatives Ergebnis für negative Zahlen

Gemäß Google Calculator(-13) % 64 ist 51.

Laut Javascript (siehe diese JSBin ) ist es -13.

Wie kann ich das beheben?

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

Aus diesem Artikel entnommen: Der JavaScript-Modulo-Fehler

216
Enrique

Die Verwendung von Number.prototype ist SLOW, da Ihre Nummer bei jeder Verwendung der Prototypmethode in eine Object eingeschlossen wird. An Stelle von:

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

Benutzen:

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

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

~ 97% schneller als mit Prototypen. Wenn Leistung für Sie natürlich von Bedeutung ist ..

121
StuR

Der %-Operator in JavaScript ist der Restoperator und nicht der Modulo-Operator (der Hauptunterschied besteht darin, wie negative Zahlen behandelt werden):

-1 % 8 // -1, not 7

24
Rob Sobers

Eine "mod" -Funktion, um ein positives Ergebnis zu erhalten.

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

Und natürlich 

mod(-13,64) // 51
14
Shanimal

Die akzeptierte Antwort macht mich etwas nervös, da der Operator% erneut verwendet wird. Was ist, wenn Javascript das Verhalten in der Zukunft ändert?

Hier ist eine Problemumgehung, die% nicht wiederverwendet:

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
8
wisbucky

JavaScript-Modulobetrieb

Die erfolgreiche Implementierung einer wissenschaftlichen Berechnung oder eines Algorithmus ist nicht nur durch das Verständnis der Merkmale einer bestimmten Sprache oder eines bestimmten Frameworks möglich, sondern auch durch das Verständnis der Einschränkungen.

Computer sind präzise wissenschaftliche Instrumente, aber sie funktionieren, indem sie Entitäten in diskreten Räumen manipulieren (Sie haben eine begrenzte Anzahl von Pixeln auf dem Bildschirm, hinter jeder Zahl gibt es eine begrenzte Anzahl von Bits usw.)

Versuchen Sie, die Einschränkungen oder Rahmenbedingungen zu ignorieren, und Sie werden bald feststellen, dass zwischen Ihrer mathematischen Formel und dem Code, den Sie zu schreiben versuchen, ein Konflikt besteht.

Modulo-Operator

Manchmal werden die Situationen durch falsch angekündigte oder verstandene Rahmenfunktionen oder Operatoren kompliziert. Dieser Artikel konzentriert sich auf den Modulo-Operator.

Fragen Sie einen C # - oder JavaScript-Programmierer, was der Modulo-Operator in seiner Sprache ist, und es besteht eine große Chance, dass er eine Antwort erhält:% (z. B. das Prozentzeichen). Zahlreiche Dokumentationen beziehen sich auf das Prozentzeichen als Modulo-Operator.

Beeindruckend! Dies ist ein subtiler, aber sehr gefährlicher Fehler. In C # und JavaScript% wird der Operator tatsächlich verwendet, um den verbleibenden Rest (mit Vorzeichen) zu berechnen, wenn ein Operand durch den zweiten Operanden geteilt wird. Daher sollte der Operand korrekt als signierter Restoperator bezeichnet werden.

Auf den ersten Blick funktioniert der signierte Rest-Operator ähnlich wie der Modulo-Operator. Lassen Sie uns einige Tests durchführen, indem Sie die von JavaScript zurückgegebenen Ergebnisse mit denen von Google vergleichen.

Öffnen Sie in Chrome die Konsole (drücken Sie F12 und wählen Sie die Registerkarte Konsole). Geben Sie dort nacheinander die Berechnungen aus der linken Spalte ein. Geben Sie als Nächstes die gleichen Ausdrücke in die Google-Suchleiste ein. Beachten Sie die Ergebnisse. Sie sollten gleich sein.

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

Versuchen wir nun, einen negativen Wert als ersten Operanden zu verwenden:

 enter image description here

Überraschung!

-5% 3 = 1 (laut Google) - 5% 3 = -2 (gemäß JavaScript)

Nun, das sollte eigentlich keine Überraschung sein, wenn wir uns die Definition von% operator in JavaScript ansehen (… oder sogar C # oder viele andere Sprachen). Google berechnet das wahre Modulo, während diese Computersprachen eine unterzeichnete Erinnerung berechnen.

Allerdings haben nicht alle Programmiersprachen/Frameworks die gleiche Implementierung für%. In Python zum Beispiel berechnet der Operator% das wahre Modulo auf dieselbe Weise wie Google.

 enter image description here

Dieser Unterschied im Verhalten zwischen Sprachen kann zu geringfügigen Fehlern in Ihrer Berechnung führen, insbesondere wenn Sie versuchen, einen Algorithmus von einer Sprache in eine andere zu portieren!

Ein verstandenes Problem ist ein halb gelöstes Problem

Nehmen wir an, wir müssen eine (wissenschaftliche) Berechnung in JavaScript implementieren, indem wir die Modulo-Arithmetik verwenden.

Da wir nun verstehen, dass JavaScript keinen echten Modulo-Operator hat, können wir unsere Modulo-Operation problemlos als Funktion implementieren.

Es gibt mehrere Möglichkeiten, um Modulo in JavaScript zu implementieren. Ich zeige Ihnen 3 Wege, dies zu tun.

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

Mit präziseren Werkzeugen stehen wir nun bereit, diese (wissenschaftliche) Berechnung in Angriff zu nehmen und erwarten, dass jedes Mal korrekte Ergebnisse erzielt werden.

Hinweis: Es gibt zahlreiche Berechnungen, die die Modulo-Arithmetik verwenden… Wenn Sie sehen möchten, wie diese neuen Modulo-Funktionen bei der Implementierung eines Caesar Cipher/ROT13-Codes verwendet werden, können Sie diesen article überprüfen.

7
Marian Veteanu

Wenn x eine ganze Zahl und n eine Potenz von 2 ist, können Sie x & (n - 1) anstelle von x % n verwenden.

> -13 & (64 - 1)
51 
3
quasimodo

Obwohl es sich nicht wie erwartet verhält, bedeutet dies nicht, dass JavaScript sich nicht "benimmt". Es ist eine Wahl, die JavaScript für seine Modulo-Berechnung erstellt hat. Denn per Definition ist eine Antwort sinnvoll.

Siehe dies aus Wikipedia. Sie können auf der rechten Seite sehen, wie verschiedene Sprachen das Vorzeichen des Ergebnisses ausgewählt haben.

3
dheerosaur

Es scheint also so zu sein, dass Sie, wenn Sie versuchen, Grad zu modifizieren (dh, wenn Sie -50 Grad - 200 Grad haben), etwas wie Folgendes verwenden möchten:

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

Ich beschäftige mich auch mit negativem a und negativem 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); 
    }
1
bormat

Dies ist kein Fehler, es gibt 3 Funktionen zur Berechnung von Modulo, Sie können diejenige verwenden, die Ihren Anforderungen entspricht (ich würde empfehlen, die Euclidean-Funktion zu verwenden)

Die Dezimalteilfunktion wird abgeschnitten

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

Integer-Teilefunktion

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

Euklidische Funktion

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
1
zessx

Es gibt ein NPM-Paket, das die Arbeit für Sie erledigt. Sie können es mit dem folgenden Befehl installieren.

npm install just-modulo --save

Verwendung aus der README-Datei kopiert

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

Das GitHub-Repository kann über den folgenden Link gefunden werden:

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

0
maartenpaauw