JavaScriptでの整数の余りによる除算?
-
26-09-2019 - |
質問
JavaScript では、次の情報を取得するにはどうすればよいですか:
- 特定の整数が別の整数に入る回数の整数?
- 残り?
解決
ある数字については y
そしていくつかの約数 x
商を計算します (quotient
) と余り (remainder
) として:
var quotient = Math.floor(y/x);
var remainder = y % x;
他のヒント
私はビット演算子の専門家ではありませんが、整数を取得する別の方法は次のとおりです。
var num = ~~(a / b);
これは負の数に対しても適切に機能しますが、 Math.floor()
間違った方向に丸まってしまいます。
これも正しいようです:
var num = (a / b) >> 0;
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.floor
, 、 いつ a/b<0 && a%b!=0
.
ES6 では新しい機能が導入されています Math.trunc
方法。これにより修正が可能になります @MarkElliotの答え 負の数にも機能させるには:
var div = Math.trunc(y/x);
var rem = y % x;
ご了承ください Math
メソッドには、2 を超える数値を処理できるというビット演算子よりも利点があります。31.
var remainder = x % y;
return (x - remainder) / y;
機能を使用できます parseInt
切り捨てられた結果を取得します。
parseInt(a/b)
剰余を取得するには、mod 演算子を使用します。
a%b
parseInt には、基数 10 の radix パラメータの使用を避けるため、文字列に関していくつかの落とし穴があります。
parseInt("09", 10)
場合によっては、数値の文字列表現が科学的表記法になることがあります。この場合、parseInt は間違った結果を生成します。
parseInt(100000000000000000000000000000000, 10) // 1e+32
この呼び出しでは、結果として 1 が生成されます。
私は通常、以下を使用します:
const quotient = (a - a % b) / b;
const remainder = a % b;
おそらく最もエレガントではありませんが、機能します。
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、残り = -0.3800000000000079
はい、精度に問題があることに気づきましたが、それを確認する時間がありませんでした (Firefox、Windows 7、または私の CPU の FPU の問題なのかはわかりません)。ただし、Yarin の質問では、整数のみが関係しており、ガンマックスのコードは完全に機能します。
Math.floor(operation)
演算の切り捨てられた値を返します。
例1セント 質問:
var x = 5;
var y = 10.4;
var z = Math.floor(x + y);
console.log(z);
コンソール:
15
例2nd 質問:
var x = 14;
var y = 5;
var z = Math.floor(x%y);
console.log(x);
コンソール:
4
アレックス・ムーア=ニエミのコメントの答え:
Rubyist の場合は、Google からここを検索してください divmod
, 、次のように実装できます。
function divmod(x, y) {
var div = Math.trunc(x/y);
var rem = x % y;
return [div, rem];
}
結果:
// [2, 33]
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 番目は余り)
ページ数の計算は 1 つのステップで実行できます。Math.ceil(x/y)
3 進数を使用して、正および負の整数値を処理する方法を決定することもできます。
var myInt = (y > 0) ? Math.floor(y/x) : Math.floor(y/x) + 1
数値が正の場合は、すべて問題ありません。Math.floor の負数の処理方法により、数値が負の場合は 1 が加算されます。
これは常にゼロに向かって切り捨てられます。手遅れかどうかはわかりませんが、次のとおりです。
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
};
}
JS ランタイムではそのように表現できない非常に大きな整数の剰余を計算する必要がある場合 (2^32 より大きい整数は浮動小数点数として表現されるため、精度が失われます)、何らかのトリックを行う必要があります。
これは、日常生活のさまざまな場面 (銀行口座番号、クレジット カードなど) に存在する多くのチェック ディジットをチェックする場合に特に重要です。
まず第一に、数値を文字列として必要とします (そうでないと、すでに精度が失われており、剰余は意味を持ちません)。
str = '123456789123456789123456789'
ここで、文字列を小さな部分に分割する必要があります。これは、残りと文字列の一部を連結したものが 9 桁に収まる程度に小さくする必要があります。
digits = 9 - String(divisor).length
文字列を分割する正規表現を用意する
splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g')
たとえば、次の場合 digits
が 7 の場合、正規表現は
/.{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
これにより、最後の剰余に影響を与えることなく、数値の 10 進表現の「最初の部分」をその剰余で置き換えることができます。
最終的なコードは次のようになります。
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);
}