JavaScriptに残りの整数除算?


回答:


1239

ある数yとある除数についてx、商(quotient)と剰余(remainder)を次のように計算します。

var quotient = Math.floor(y/x);
var remainder = y % x;

84
%はJavaScriptの浮動小数点数で機能します(これは他の多くの言語とは異なります)。これはおそらく望ましくない:3.5 % 21.5と評価されます。必要に応じて(parseInt、floorなど)を処理するようにしてください

16
数学では-4.5の整数部分は-5です。これは、-5が「-4.5よりも低い可能な最大の整数」であるためです。
Toughy

9
ただし、負の数について何をすることに決めたとしても、それは商と剰余全体で一貫している必要があります。floorandを%一緒に使用することは、そのように一貫していません。のtrunc代わりにfloor(それにより負の剰余を許可する)を使用するか、減算を使用して剰余を取得します(rem = y - div * x)。
マークリード

7
1. remとにかく剰余を計算する場合は、divフローリングなしで商をより速く取得できます(y - rem) / x。2.ちなみに、ドナルドクヌースの推奨定義によるモジュロ演算(符号の一致除数、残りのユークリッド係数ではなくJavaScriptの符号の一致除算)は、JavaScriptでとしてコーディングできるものfunction mod (a, n) { return a % n + (Math.sign(a) !== Math.sign(n) ? n : 0); }です。
アーロンマンスハイム2017

1
-9 / 2 = -4.5。次に、床が-4.5、つまり-5になります。-5は-4.5未満であり、floor操作は指定された値よりも小さい最大の整数として定義されることに注意してください。
マークリード

371

私はビット演算子の専門家ではありませんが、整数を取得する別の方法があります。

var num = ~~(a / b);

これは負の数でも正しく機能しますMath.floor()が、間違った方向に丸められます。

これも正しいようです:

var num = (a / b) >> 0;

84
その目的は、私はちょうど把握しようと、最後の20分を費やしたもう一つは、明らかであるa/b | 0
BlueRaja -ダニーPflughoeft

18
@ user113716 @BlueRajaビット単位の演算は整数型でのみ意味があり、JSはもちろんそれを知っています。~~intint | 0およびint >> 0初期引数は変更しませんが、インタプリタが整数部分を演算子に渡すようにします。
アレクセイザブロドスキー

15
floorその名前を考えると、間違った方向に丸めることはほとんどありません。
Mark K Cowan

19
それはブウブウです。a = 12447132275286670000; b = 128 Math.floor(a/b)-> 97243220900677100および~~(a/b)-> -1231452688
Mirek Rusin 2014年

7
優先順位に注意してください。~~(5/2) --> 2同様に(5/2)>>0 --> 2、しかし~~(5/2) + 1 --> 3、同時に~~(5/2)>>0 + 1 --> 1~~優先順位がより適切であるため、これは良い選択です。
timkay、2014年

217

Firefoxで速度テストを行いました。

-100/3             // -33.33..., 0.3663 millisec
Math.floor(-100/3) // -34,       0.5016 millisec
~~(-100/3)         // -33,       0.3619 millisec
(-100/3>>0)        // -33,       0.3632 millisec
(-100/3|0)         // -33,       0.3856 millisec
(-100-(-100%3))/3  // -33,       0.3591 millisec

/* a=-100, b=3 */
a/b                // -33.33..., 0.4863 millisec
Math.floor(a/b)    // -34,       0.6019 millisec
~~(a/b)            // -33,       0.5148 millisec
(a/b>>0)           // -33,       0.5048 millisec
(a/b|0)            // -33,       0.5078 millisec
(a-(a%b))/b        // -33,       0.6649 millisec

上記はそれぞれ1,000万回の試行に基づいています。

結論:((a/b>>0)または(~~(a/b))または(a/b|0))を使用して、効率を約20%向上させます。また、彼らが持つすべての矛盾していることに注意してくださいMath.floora/b<0 && a%b!=0


54
整数除算の速度を最適化することは、多くの場合にのみ意味があることに注意してください。それ以外の場合は、最も単純なものを選択することをお勧めします(あなたとあなたの同僚にとって最も単純なようです)。
mik01aj 2014年

7
@ m01は完全に同意します
JonnyRaa

2
@ m01しかし、どちらが難しいですMath.floorか。他のAPI関数について、誰がどのように知っているか、または~(ビットごとではない)演算子について学び、JSでビットごとの演算がどのように機能するかを学習してから、二重チルドの影響を理解しますか?
Stijn de Witt

11
まあ、あなたの同僚がアセンブラーでチップをプログラミングしていない場合、彼らはおそらくMath.floorよりよく理解するでしょう。そして、そうでなくても、これはグーグルです。
mik01aj 2015年

2
@MarkGreenはい、しかしそれをしたいだけでは、それがたまたま最速であるという理由で奇妙な形式でそれを書くべきだという意味ではありません。理由はほとんどありません。通常、コードの明快さが最初の関心事です。また、これらのテストは、言語の変更後、および異なるブラウザー間では完全に無意味になる可能性があります。アプリケーションに関係なく、何が遅いのかをプロファイルで調べる必要があります。すでに他の1つを最適化していない限り、整数除算法になる可能性は低いです。
JonnyRaa 2017

150

ES6では新しいMath.trunc方法が導入されています。これにより、@ MarkElliotの回答を修正して、負の数でも機能するようにすることができます。

var div = Math.trunc(y/x);
var rem = y % x;

注ことMathの方法は、彼らが2の上に数字で動作することをビット演算子を上回る利点持っている31


var y = 18014398509481984; var x = 5; div =?-バグ?
4esn0k 2015

4
@ 4esn0kバグではありません。数値の桁数が多すぎるため、64ビットのバイナリ形式のIEEE 754数値ではそれほど多くの精度を持つことができません。たとえば、18014398509481984 == 18014398509481985
Oriol

18014398509481984 == 2 ** 54。この数値は、binary64形式で正確に表されるため、特別に使用しました。答えも正確に表されています
4esn0k

1
選択は簡単だと思います。32ビットまでの符号付きのサポートが必要ですか?を使用し~~(x/y)ます。署名された最大54ビットまでのより大きな数をサポートする必要がありますか?使用Math.truncあなたがそれを持っている場合、またはMath.floorそれ以外の場合は(正しい負の数の場合)。さらに大きな数をサポートする必要がありますか?大きなライブラリを使用してください。
Stijn de Witt

4
検索でGoogleからのここrubyistsためにdivmod、次のようなそれを実装することができますfunction divmod(x, y) { var div = Math.trunc(x/y); var rem = x % y; return [div, rem]; }
アレックス・ムーア・ニエミ

29
var remainder = x % y;
return (x - remainder) / y;

1
このバージョンは、x = -100の場合、-33ではなく-34を返すため、残念ながらテストに失敗します。
Samuel

1
「var x = 0.3; var y = 0.01;」はどうですか??(github.com/JuliaLang/julia/issues/4156#issuecomment-23324163に感謝)
4esn0k

実際、@ Samuelは負の値で、このメソッドは正しい結果を返します。または、少なくともMath.trunc:) を使用するメソッドと同じ値を返します。100,3で確認しました。-100,3; 100、-3および-100、-3。もちろん、あなたのコメントや物事が変わってからかなりの時間が経過しました。
Marjan Venema

19

私は通常使用します:

const quotient =  (a - a % b) / b;
const remainder = a % b;

それはおそらく最もエレガントではありませんが、動作します。


1
フロートの解析や切り捨ての醜さを回避するため、素晴らしい解決策です。
Dem Pilafian

6
商と剰余の両方が必要な場合は、まず剰余を計算してから、商の式でその値を再利用します。つまり、商=(a-剰余)/ b;
gb96

2
残り= a%b; 商=(a-剰余)/ b;
Zv_oDD '30 / 10/30

16

関数parseIntを使用して、切り捨てられた結果を取得できます。

parseInt(a/b)

剰余を取得するには、mod演算子を使用します。

a%b

parseIntには、基数10で基数パラメータを使用しないようにするために、文字列に関するいくつかの落とし穴があります

parseInt("09", 10)

場合によっては、数値の文字列表現が科学表記になることがあります。この場合、parseIntは誤った結果を生成します。

parseInt(100000000000000000000000000000000, 10) // 1e+32

この呼び出しは結果として1を生成します。


7
parseInt可能な場合は避けてください。ダグラスクロックフォードの警告は次のとおりです。「文字列の最初の文字が0の場合、文字列は10進数ではなく8進数で評価されます。8、8、9は数字ではないため、parseInt( "08")とparseInt ( "09")は結果として0を生成します。このエラーは、日付と時刻を解析するプログラムで問題を引き起こします。幸い、parseIntは基数パラメーターを取ることができるため、parseInt( "08"、10)は8を生成します。基数パラメータを指定してください。」 archive.oreilly.com/pub/a/javascript/excerpts/...
パワーズ

3
部門では、文字列ではなく数値を受け取ることを期待していますが、これは良い点です。
ÉdipoコスタRebouças

2
@Powers基数を追加します。彼はparseInt避けるべきだとは言っていません。注意すべきいくつかの落とし穴があります。これらのことを認識し、対処する準備をしておく必要があります。
なし

2
parseInt数値引数を指定して呼び出さないでください。parseInt数値を切り捨てるのではなく、部分的に数値の文字列を解析することになっています。
Oriol

1
もともと特定の方法で使用することを意図していないからといって、使用してはならないという意味ではありません。この答えは機能します。
fregante

6

JavaScriptは、それらの数学的定義に従って、負の数の下限と残りの非整数の数を正しく計算します。

FLOORは「パラメーターよりも小さい最大の整数」として定義されるため、次のようになります。

  • 正の数:FLOOR(X)= Xの整数部分。
  • 負の数:FLOOR(X)= Xの整数部分から1を引いた数(パラメーターよりも小さい必要があるため、より負の数になるため!)

REMAINDERは、除算の "残り"(ユークリッド算術)として定義されます。被除数が整数でない場合、商も通常整数ではありません。つまり、余りはありませんが、商が整数になるように強制される場合(そして、誰かが剰余または剰余を取得しようとすると、それが起こります)浮動小数点数)、非整数の「残り」があることは明らかです。

JavaScriptはすべてを期待どおりに計算するので、プログラマーは適切な質問をするように注意する必要があります(そして、人々は質問に答えるように注意する必要があります!)Yarinの最初の質問は「XのYによる整数除算とは何か」ではありませんでしたが、代わりに、「与えられた整数の完全な回数が別の整数になります」。整数の除算(除数による除数)は、数値(除数)が別の(被除数)に「入る」時間よりも-1小さいため、正の数の場合、答えは両方とも同じですが、負の数の場合は異なります。つまり、FLOORは負の数の整数除算に対して正しい答えを返しますが、Yarinはそれを要求しませんでした。

gammaxは正しく答えました。そのコードはYarinからの質問どおりに機能します。一方、サミュエルは間違っている、彼は数学をしなかったと思う、または彼はそれがうまくいくのを見たであろう(また、彼は彼の例の除数が何であるかを言っていなかったが、私はそれが3):

残り= X%Y = -100%3 = -1

GoesInto =(X-残り)/ Y =(-100--1)/ 3 = -99 / 3 = -33

ちなみに、Firefox 27.0.1でコードをテストしましたが、正数と負数、および非整数値を使用して、被除数と除数の両方で期待どおりに機能しました。例:

-100.34 / 3.57:GoesInto = -28、Remainder = -0.3800000000000079

はい、気づきました。精度の問題がありますが、確認する時間がありませんでした(Firefox、Windows 7、または私のCPUのFPUの問題かどうかはわかりません)。ただし、整数のみが関係するYarinの質問の場合、gammaxのコードは完全に機能します。


5

Math.floor(operation) 操作の切り捨てられた値を返します。

最初の質問の例:

var x = 5;
var y = 10.4;
var z = Math.floor(x + y);

console.log(z);

コンソール:

15

2 番目の質問の例:

var x = 14;
var y = 5;
var z = Math.floor(x%y);

console.log(x);

コンソール:

4



1

アレックスムーアニエミ回答としてののコメント:

ここでGoogleからRubyを検索divmodする場合、次のように実装できます。

function divmod(x, y) {
  var div = Math.trunc(x/y);
  var rem = x % y;
  return [div, rem];
}

結果:

// [2, 33]

2
通常、負の数が含まれる場合、切り捨てられた除算()とは異なる、divmod床除算(Math.floor)を使用しますMath.trunc。これは、NPM divmodパッケージRubydivmodSWI-Prologdivmod、およびおそらく他の多くの実装にも当てはまります。
Palec 2017

切り捨てられた除算は、フロアされた除算よりも自然に見える結果をもたらしますが、互換性はそれよりも優れています、IMO。おそらく、床除算を使用することの数学的またはパフォーマンス上の理由もあるでしょう。divmod2つの操作を別々に計算するよりも2倍速く実行されるため、通常は存在することに注意してください。このパフォーマンス上の利点なしにそのような関数を提供することは混乱するかもしれません。
Palec 2017

1

2のべき乗で除算する場合は、ビットごとの演算子を使用できます。

export function divideBy2(num) {
  return [num >> 1, num & 1];
}

export function divideBy4(num) {
  return [num >> 2, num & 3];
}

export function divideBy8(num) {
  return [num >> 3, num & 7];
}

(1つ目は商、2つ目は余りです)


一般的に、function divideByPowerOf2(num, exponent) { return [num >> exponent, num & ((1 << exponent) - 1)]; }
Palec 2017

0

3値を使用して、正および負の整数値の処理方法を決定することもできます。

var myInt = (y > 0) ? Math.floor(y/x) : Math.floor(y/x) + 1

数値が正の場合、すべて問題ありません。数値が負の場合、Math.floorが負を処理する方法のため、1が追加されます。


0

これは常にゼロに向かって切り捨てられます。手遅れかどうかはわかりませんが、次のようになります。

function intdiv(dividend, divisor) { 
    divisor = divisor - divisor % 1;
    if (divisor == 0) throw new Error("division by zero");
    dividend = dividend - dividend % 1;
    var rem = dividend % divisor;
    return { 
        remainder: rem, 
        quotient: (dividend - rem) / divisor
    };
}

0

JSランタイムがそのように表すことができない非常に大きな整数の余りを計算する必要がある場合(2 ^ 32より大きい整数は浮動小数点として表されるため、精度が失われます)、いくつかのトリックを実行する必要があります。

これは、日常生活の多くの場合に存在するチェックデジットの多くのケース(銀行口座番号、クレジットカードなど)をチェックする場合に特に重要です。

まず第一にあなたはあなたの数を文字列として必要とします(そうでなければあなたはすでに精度を失っており、残りは意味がありません)。

str = '123456789123456789123456789'

ここで、文字列を小さな部分に分割する必要があります。残りの部分と文字列の一部を連結して9桁に収まるように、十分に小さくします。

digits = 9 - String(divisor).length

文字列を分割する正規表現を準備する

splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g')

たとえば、digits7の場合、正規表現は

/.{1,7}(?=(.{7})+$)/g

これは、最大長7の空でない部分文字列に一致し、その後に続きます((?=...)に7の倍数の文字数正の先読み)。 'g'は、最初の一致で停止するのではなく、式をすべての文字列で実行します。

次に、各部分を整数に変換し、reduce(前の剰余を加算して-または0-正しい10の累乗を掛けて)剰余を計算します。

reducer = (rem, piece) => (rem * Math.pow(10, digits) + piece) % divisor

これは、「減算」剰余アルゴリズムのために機能します。

n mod d = (n - kd) mod d

これにより、最終的な剰余に影響を与えることなく、数値の小数表現の「最初の部分」をその剰余で置き換えることができます。

最終的なコードは次のようになります。

function remainder(num, div) {
  const digits = 9 - String(div).length;
  const splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g');
  const mult = Math.pow(10, digits);
  const reducer = (rem, piece) => (rem * mult + piece) % div;

  return str.match(splitter).map(Number).reduce(reducer, 0);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.