JavaScript%(モジュロ)は負の数に対して負の結果を返します


252

グーグル電卓に よると(-13) % 64です51

Javascript(このJSBinを参照)によれば、そうです-13

どうすれば修正できますか?


これは単に優先順位の問題かもしれません。あなたが意味するか(-13) % 64または-(13 % 64)?個人的には、わかりやすくするために、どちらの方法でもかっこを付けました。
MatrixFrog 2010


85
Javascriptが時には非常に残酷な冗談のように感じている
dukeofgaming

6
グーグルが間違っていることはできません
caub 2016年

10
JSの根本的な問題は%、モジュロ演算子ではありません。それは剰余演算子です。JavaScriptにはモジュロ演算子はありません。だから、受け入れられた答えは行く方法です。
Redu

回答:


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

この記事からの抜粋JavaScript Moduloバグ


23
それを「バグ」と呼ぶかどうかはわかりません。モジュロ演算は負の数に対してあまり明確に定義されておらず、コンピューティング環境によって処理方法が異なります。ウィキペディアのmodulo演算に関する記事は、かなりうまくカバーしています。
ダニエル・プライデン

22
しばしば「モジュロ」と呼ばれるので、馬鹿げているように見えるかもしれません。これは、数学の定義(have /nℤ代数を参照)と同じように動作し、そうではないことを示唆しています。
etienne 2013

7
nを追加する前にモジュロを取るのはなぜですか?なぜnを追加してからモジュロを取るのですか?
22:34

12
あなたは、この%を使用しなかった場合@starwed nはそれがために失敗するx < -n-例えば(-7 + 5) % 5 === -2けど((-7 % 5) + 5) % 5 == 3
fadedbee 14

7
この関数にアクセスするには、-13%10ではなく(-13).mod(10)の形式を使用する必要があることを回答に追加することをお勧めします。
Jp_

161

Number.prototypeプロトタイプメソッドを使用するたびに数値がにラップされるため、使用はSLOWです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%高速です。もちろんあなたにとってパフォーマンスが重要なのなら...


1
素晴らしいヒント。私はあなたのjsperfを取り、この質問の残りのソリューションと比較しました(とにかくこれが一番良いようです):jsperf.com/negative-modulo/3
Mariano Desanze

11
マイクロ最適化。あなたはこれのために莫大な量のmod計算をしなければならないでしょう。最も明確で最も保守しやすいものをコーディングし、パフォーマンス分析に従って最適化します。
ChrisV 2014年

私はあなたが持っていると思うnのをしてm、あなたの第二の例@StuRで間違った方法を中心にね。それはあるはずですreturn ((n % m) + m) % m;
ビミスト2015年

これは、受け入れられた回答に対するコメントであり、それ自体に対する回答ではありません。
xehpuk 2018

5
この回答で述べられている動機は、ミクロの最適化です。しかし、プロトタイプを変更することは問題があります。副作用が最も少ないアプローチ、つまりこれを優先します。
キーン

30

%JavaScript の演算子は剰余演算子であり、剰余演算子ではありません(主な違いは負の数値の処理方法にあります)。

-1 % 8 // -1, not 7


8
それはすべき剰余演算子と呼ばれるそれはされて弾性オペレーターと呼ばれる:developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/...
ビッグMcLargeHuge

15
@DaveKennedy:MDNは公式の言語リファレンスではありません。コミュニティで編集されたサイトであり、誤解されることがあります。仕様では、これをモジュロ演算子とは呼んでおらず、私が知る限り、それは決してありません(私はES3に戻りました)。これは、演算子が暗黙の除算の残りを生成することを明示的に示し、それを単に「%演算子」と呼びます。
TJクラウダー2017

2
と呼ばれる場合remainder、定義上、0より大きくなければなりません。高校の分割定理を思い出せませんか?だから多分あなたはここを見ることができます:en.wikipedia.org/wiki/Euclidean_division
Ahmad

19

肯定的な結果を返す「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

1
MDNは公式の言語リファレンスではありません。コミュニティによって編集されたサイトであり、誤解することがあります。仕様では、これをモジュロ演算子とは呼んでおらず、私が知る限り、それは決してありません(私はES3に戻りました)。これは、演算子が暗黙の除算の残りを生成することを明示的に示し、それを単に「%演算子」と呼びます。
TJクラウダー2017

1
おっと、あなたが指定したリンクは実際#sec-applying-the-mod-operatorにはURLのすぐそこを参照しています:)とにかく、メモをありがとう、私は私の答えから綿毛を取り除きました、それはとにかく本当に重要ではありません。
Shanimal

3
@シャニマル:笑!します。HTMLエディターによるエラー。仕様テキストにはありません。
TJクラウダー2017

10

受け入れられた答えは、%演算子を再利用するため、少し緊張します。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

8
JavaScriptがモジュロ演算子を数学的な定義に一致するように変更した場合、受け入れられた答えは引き続き機能します。
starwed

20
「もしJavaScriptが将来の振る舞いを変えたらどうなるの?」-なぜでしょうか?このような基本的な演算子の動作を変更することはほとんどありません。
nnnnnn 2014

1
注目の回答に対するこの懸念と代替案を共有するための+1#answer-4467559&4つの理由:(1)なぜそれが述べられているのか?はい、「そのような基本的な操作の動作を変更することはおそらくない」が、検討するのは賢明であるそれを見つけることさえ必要ではありません。(2)壊れたものに関して作業中の操作を定義することは印象的ではありますが、少なくとも一見すると心配です、これは示されていませんが表示されないはずです(3)この代替策を十分に検証していないと、従うのが簡単になりますクイックルック。(4)小さな:2(mod)divの代わりに1 div + 1 mulを使用します&良いFPUのない以前のハードウェアで聞いたことがありますが、乗算はより高速でした。
Destiny Architect

2
@DestinyArchitectそれは賢明ではありません、それは無意味です。もし剰余演算子の振る舞いを変更しようとすると、それを使っている多くのプログラムが壊れてしまいます。それは決して起こらないでしょう。
イージス

10
何の行動であれば-*/;.(),Math.floorfunctionまたはreturn変更?次に、コードがひどく壊れています。
xehpuk 2018

5

期待どおりに動作していませんが、JavaScriptが「動作」していないという意味ではありません。これは、モジュロ計算のためにJavaScriptが選択したものです。なぜなら、定義上、どちらの答えも理にかなっているからです。

ウィキペディアからこれを参照てください。右側で、さまざまな言語が結果の記号を選択した方法を確認できます。


4

場合はx整数で、n2のべき乗では、使用することができますx & (n - 1)代わりにx % n

> -13 & (64 - 1)
51 

2

したがって、(-50度-200度のように)度を変更しようとする場合は、次のようなものを使用する必要があります。

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

1

私は負の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); 
    }

1

これはバグではありません。モジュロを計算する3つの関数があり、ニーズに合った関数を使用できます(ユークリッド関数の使用をお勧めします)

小数部関数の切り捨て

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

1
ユークリッド関数チェックでは、((this%n)+ n)%nは常に正であるため、m <0は役に立たない
bormat

1
@bormatはい、そうですが、Javascriptでは%否定的な結果が返される可能性があります(これはこれらの関数の目的であり、修正するためです)
zessx

あなたはこれを書きました[コード] Number.prototype.mod = function(n){var m =((this%n)+ n)%n; m <0を返す?m + Math.abs(n):m; }; [/ code] mが負であるnの値を1つ与えます。最初の%の後にnを追加するため、mは負の値です。
ボルマット2016年

このチェックがないと、代わりにparseInt(-41).mod(-7)返され-6ます1(そしてこれがまさに私が書いたInteger part関数の目的です)
zessx

1
2番目のモジュロNumber.prototype.mod = function(n){var m = this%n;を削除することにより、関数を簡略化できます。return(m <0)?m + Math.abs(n):m; };
ボルマット2016年

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.