JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptで減算演算子を使わずに引き算を実現する方法

はじめに

JavaScriptには、2つの数値を受け取ってその差(引き算の結果)を返す関数を実装するという課題があります。ただし、ここでの条件は減算演算子(-)を一切使用しないことです。

この問題は、コンピュータが数値を2進数で扱っていることを利用すれば解決できます。具体的には、XOR・AND・NOT・左シフトといったビット演算を組み合わせ、再帰的に処理を繰り返すことで、減算とまったく同じ結果を得ることができます。

解法のポイント

アルゴリズムの中核をなすのは、次の2つの式です。

  • num1 ^ num2(XOR) … 各桁の「借りを考慮しない差」を求めます。
  • (~num1 & num2) << 1 … 借りが必要な桁を検出し、1ビット左へシフトして上位の桁へ借りを伝えます。

借りがすべて処理され、第2引数が 0 になるまでこの操作を再帰的に繰り返せば、num1 に最終的な差が格納されます。

コード例

const num1 = 56;
const num = 78;

const subtractWithoutMinus = (num1, num2) => {
  // 借りがなくなれば、その時点の num1 が答え
  if (num2 === 0) {
    return num1;
  }
  // XORで差を求め、借りをシフトして再帰的に継続
  return subtractWithoutMinus(num1 ^ num2, (~num1 & num2) << 1);
};

console.log(subtractWithoutMinus(num, num1));

出力結果

22

78 − 56 の計算結果である 22 がコンソールに出力されます。

処理の流れを詳しく解説

subtractWithoutMinus(78, 56) を呼び出したとき、内部では次のようなステップが順番に実行されます。

  1. ステップ1: 78 ^ 56 を計算し、借りを無視した各桁の差を求めます。
  2. ステップ2: ~78 & 56 によって「num1 が 0・num2 が 1」となっているビット(=借りが必要な桁)を抽出し、<< 1 で左シフトして借りの位置を調整します。
  3. ステップ3: 新しい2つの値で関数を再度呼び出します。これを借りが尽きる(num2 === 0 となる)まで繰り返します。

なお、JavaScriptのビット演算はオペランドを32ビット符号付き整数に変換して実行されるため、この手法は負の数に対しても正しく機能します。

まとめ

減算演算子が使えない状況でも、ビット演算+再帰を組み合わせれば減算を正確に実装できます。同じ考え方で加算も a ^ b(a & b) << 1 を使って実装できることからも分かるように、ビットレベルの演算への理解は、低レイヤー処理やアルゴリズムの学習において非常に役立つ知識です。

  1. new演算子を使ってJavaScriptコンストラクタを作成する方法

    JavaScriptでは、通常の関数を「new」演算子と組み合わせて呼び出すことで、コンストラクタとして機能させることができます。これにより、同じ構造を持つ複数のオブジェクトを効率的に生成できます。以下に、new演算子を使用してJavaScriptのコンストラクタを作成するコード例を紹介します。 サンプルコード <!DOCTYPE html> <html lang=ja> <head> <meta charset=UTF-8 /> <meta name=viewport content=width=device-width, initial

  2. JavaScriptのnew演算子とは?オブジェクト生成の基本をサンプルコードで解説

    new演算子の基本的な役割 JavaScriptにおけるnew演算子は、ユーザーが定義したオブジェクト型や、コンストラクタ関数を持つ組み込みオブジェクト型のインスタンスを新しく生成するために使用されます。 new演算子を使うことで、同じ構造を持つ複数のオブジェクトを効率よく作成でき、コードの再利用性や保守性が大きく向上します。 new演算子の使用例 以下は、JavaScriptでnew演算子を使用した実際のコード例です。 <!DOCTYPE html> <html lang=ja> <head> <meta charset=UTF-8 /> &l