「ダブルチルダ」(~~)演算子とは? JavaScriptにおけるビット演算の基礎

2024-05-02

JavaScriptにおける「ダブルチルダ」(~~)演算子

JavaScriptの「ダブルチルダ」(~~)演算子は、ビット反転演算子と呼ばれ、オペランドのビットを反転させ、符号を反転させた値を1引いた値を返します。主に、整数のビット演算で使用されます。

ビット反転とは、各ビットの値を反対にする操作です。例えば、8ビットのバイナリ数 00110101 に対してビット反転を行うと、11001010 になります。

符号反転とは、負数の場合は符号をプラスに、正数の場合は符号をマイナスに変換する操作です。

1引くとは、ビット反転と符号反転を行った結果から1を引く操作です。

つまり、~~演算子は、オペランドのビットを反転させ、符号を反転させ、さらに1を引いた値を返す演算子と言えるでしょう。

~~演算子の使い方

~~演算子は、数値リテラルや変数に適用できます。

例えば、以下のコードは、変数 num の値をビット反転させ、符号を反転させ、さらに1を引いた値をコンソールに出力します。

let num = 10;
console.log(~num); // -11

また、~~演算子は、ビットマスクと組み合わせて使用することもできます。

let num = 15;
let mask = 15; // 00001111
console.log(num & mask); // 1111
console.log(~(num & mask)); // -12

~~演算子の注意点

  • ~~演算子は、整数値にのみ適用できます。浮動小数点値には適用できません。
  • ~~演算子は、ビット演算なので、オペランドが32ビット整数をオーバーフローする可能性があります。オーバーフローすると、誤った結果が返されます。
  • ~~演算子は、符号付き整数と符号なし整数の両方で使用できますが、符号反転の効果は符号付き整数でのみ発生します。符号なし整数の場合、ビット反転のみが行われます。

~~演算子の例

以下に、~~演算子の具体的な例をいくつか示します。

  • 符号反転
let num = -5;
console.log(~num); // 4
  • ビットマスクと組み合わせての使用
let num = 17;
let mask = 8; // 00001000
console.log(num & mask); // 8
console.log(~(num & mask)); // -7
  • 32ビット整数オーバーフロー
let num = 2147483647; // 最大32ビット整数
console.log(~num); // -2147483648

このように、~~演算子は、整数のビット演算を行う際に便利な演算子です。しかし、注意点も理解した上で使用することが重要です。

~~演算子は、JavaScriptにおけるビット演算の重要な演算子の一つです。整数のビットを反転させ、符号を反転させ、さらに1を引いた値を返す演算子として理解しておきましょう。




JavaScriptにおける「ダブルチルダ」(~~)演算子のサンプルコード

符号反転

let num1 = 10; // 正の整数
let num2 = -5; // 負の整数

console.log(~num1); // -11 (ビット反転、符号反転、1引く)
console.log(~num2); // 4  (ビット反転、符号反転、1引く)

ビットマスクと組み合わせての使用

let num = 17; // 10001
let mask = 8;   // 1000

console.log(num & mask); // 8 (ビットマスク)
console.log(~(num & mask)); // -7 (ビットマスク、ビット反転、符号反転、1引く)

32ビット整数オーバーフロー

let num = 2147483647; // 最大32ビット整数

console.log(~num); // -2147483648 (ビット反転、符号反転、1引く)

論理否定との違い

let num = 10;

console.log(~num); // -11 (ビット反転、符号反転、1引く)
console.log(!num); // false (論理否定)

解説

  • 上記のコード例では、~~演算子のさまざまな使い方を демонстриしています。
  • 符号反転、ビットマスクとの組み合わせ、32ビット整数オーバーフローなど、~~演算子のさまざまな動作を確認できます。
  • 論理否定演算子 ! との比較も行っています。~~演算子はビット演算を行い、論理否定演算子は論理演算を行う点が異なります。
  • サンプルコードはあくまでも例であり、状況に応じて自由に改変できます。
  • ~~演算子は、ビット演算を理解している場合にのみ使用することをお勧めします。
  • ビット演算の詳細については、JavaScriptのマニュアルやリファレンスを参照してください。



JavaScriptにおける「ダブルチルダ」(~~)演算子の代替方法

~~演算子は、整数のビット演算を行う際に便利な演算子ですが、状況によっては他の方法で置き換えることも可能です。

ビット反転と符号反転を別々に実行

let num = 10;

// ビット反転
let reversedBits = ~num;

// 符号反転
let invertedSign = -num;

// 1引く
let result = reversedBits + invertedSign - 1;

console.log(result); // -11
  • 上記のコードでは、~~演算子の機能を個別に再現しています。
  • ビット反転、符号反転、1引くという3つの操作を別々に実行することで、~~演算子と同じ結果を得ています。
  • この方法は、~~演算子の内部動作を理解したい場合に役立ちます。

ビットマスクと論理演算を使用してビットを反転

let num = 17; // 10001

// ビットマスク
let mask = 0; // 00000
let count = 0;

while (num > 0) {
  // 最下位ビットを抽出
  let bit = num & 1;

  // ビットを反転
  bit = !bit;

  // ビットマスクに設定
  mask |= bit << count;

  // カウントアップ
  count++;

  // 右シフト
  num >>>= 1;
}

// 1引く
let result = mask - 1;

console.log(result); // -7
  • 上記のコードでは、ビットマスクと論理演算を使用して、ビットを反転しています。
  • ビットマスクを操作することで、各ビットを個別に反転することができます。
  • この方法は、~~演算子よりも複雑ですが、より柔軟なビット演算が可能になります。

ビット演算ライブラリを使用

// ビット演算ライブラリのインポート
const bitwise = require('bitwise');

let num = 17; // 10001

// ビット反転
let reversedBits = bitwise.not(num);

// 1引く
let result = reversedBits - 1;

console.log(result); // -7
  • 上記のコードでは、ビット演算ライブラリを使用して、~~演算子の機能を実現しています。
  • ビット演算ライブラリを使用すると、~~演算子よりも簡潔にコードを書ける場合があります。
  • ただし、ライブラリのインストールやインポートが必要となります。

それぞれの方法の比較

方法メリットデメリット状況
~~演算子を使用するシンプルで分かりやすいビット演算の詳細が分からない場合、誤解が生じる可能性がある初心者向け、簡単なビット演算
ビット反転と符号反転を別々に実行する~~演算子の内部動作を理解しやすいコードが冗長になる~~演算子の動作を理解したい場合
ビットマスクと論理演算を使用してビットを反転より柔軟なビット演算が可能コードが複雑になる高度なビット演算が必要な場合
ビット演算ライブラリを使用するコードが簡潔になるライブラリのインストールやインポートが必要ライブラリを使用することに抵抗がない場合

それぞれの方法のメリットとデメリットを理解した上で、適切な方法を選択することが重要です。


javascript


Moment.jsを使わずにJavaScriptで日付を比較する方法

最も簡単な方法は、Dateオブジェクトの比較演算子を使う方法です。以下の演算子が使用できます。==: 2つの日付が同じかどうかを比較します。<: 1番目の日付が2番目の日付よりも前かどうかを比較します。この方法はシンプルですが、時間の情報は考慮されません。例えば、2023年12月31日午後11時59分と2024年1月1日午前0時01分は、この方法では同じ日付とみなされます。...


えっ、そんなに簡単だったの?JavaScriptで2つの日付間の差日数を計算する方法

DateオブジェクトのgetTimeメソッドは、日付をミリ秒単位のタイムスタンプに変換します。このタイムスタンプを利用して、2つの日付間の差日数を計算することができます。この方法のメリット:シンプルで分かりやすい多くのブラウザでサポートされている...


初心者でも安心!JavaScriptで数値を文字列に変換する3つの方法

String() 関数を使う最も簡単で一般的な方法は、String() 関数を使うことです。これは、任意の値を文字列に変換するグローバル関数です。Number. toString() メソッドを使うもう1つの方法は、Number オブジェクトの toString() メソッドを使うことです。これは、Number インスタンスを文字列に変換するメソッドです。...


【徹底比較】JavaScriptの配列から重複を削除する3つの方法のメリットとデメリット

JavaScriptの配列から重複する値を削除するには、いくつかの方法があります。方法 1: Set オブジェクトを使用する最も簡単な方法は、Set オブジェクトを使用することです。Set オブジェクトは、重複を許容しない要素の集合を表します。...


React.jsでonChangeイベントを使ってcontenteditable要素の変更を検知する方法

contenteditable属性を持つ要素は、ユーザーが直接編集できるテキストエリアのような機能を提供します。React. jsでこの要素の変更を検知するには、onChangeイベントを使用します。以下のコードは、contenteditable属性を持つ要素の変更を検知し、その内容をコンポーネントの状態に反映する例です。...


SQL SQL SQL SQL Amazon で見る



JavaScript クロージャーの仕組みを徹底解説! 3つのスコープとメモリリークへの対策

JavaScriptでは、関数内にある変数は、その関数内でしかアクセスできません。しかし、クロージャーを使用すると、関数内にある変数を、関数外からでもアクセスすることができます。これは、関数内にある変数が、関数オブジェクトの一部として保持されるためです。つまり、関数が実行された後も、その変数はメモリに残っているのです。


ブラウザ標準機能で使える! structuredClone によるディープクローン

この方法は、オブジェクトをJSONに変換してから、再びオブジェクトに変換する方法です。すべてのブラウザでサポートされており、比較的簡単に実装できます。この方法の利点は、以下の通りです。簡単で短いコードで実装できるすべてのブラウザでサポートされている


Object.defineProperty() メソッドを使って JavaScript オブジェクトからプロパティを削除する方法

delete 演算子を使用する最も簡単な方法は、delete 演算子を使用することです。 構文は以下の通りです。例えば、以下のオブジェクトから name プロパティを削除するには、次のように記述します。Object. defineProperty() メソッドを使用して、プロパティの configurable 属性を false に設定することで、プロパティを削除不可にすることができます。


安全な比較のために:JavaScriptの === 演算子を使いこなそう

== 演算子は、値の型を変換して比較を行います。つまり、異なる型の値であっても、値が同じであれば true と判定されます。例:これらの例では、左辺と右辺の値は異なる型ですが、== 演算子によって true と判定されています。=== 演算子は、値の型と値を厳密に比較します。そのため、異なる型の値は常に false と判定されます。


JavaScriptの「let」と「var」を使いこなして、コードをもっと読みやすく!

var: 関数スコープを持ちます。つまり、関数内で宣言された変数は、その関数内でのみアクセス可能です。let: ブロックスコープを持ちます。つまり、ブロック内(if文やforループなど)で宣言された変数は、そのブロック内でのみアクセス可能です。


真偽値の扱い方マスター!JavaScriptで真偽値を反転させるテクニック

例:この例では、x は 10 という非ゼロ値なので、!!x は true となります。一方、y は 0 というゼロ値なので、!!y は false となります。!! 演算子は、以下の用途で使用できます。真偽値の確認:上記の例では、isLoggedIn 変数が true かどうかを !!isLoggedIn で確認しています。


JavaScriptでsetTimeout、setInterval、async/awaitを使ったsleep機能の比較

最も一般的な方法は、setTimeout()関数を使うことです。setTimeout()は、指定された時間後にコードを実行する関数です。このコードは、まずsleep()という関数を定義します。この関数は、引数で渡された時間(ミリ秒単位)だけ待ってから、Promiseを解決します。


JavaScriptの未来を先取り!厳格モードでモダンなコードを書く

「use strict」を使用する主な理由は次のとおりです。コードの品質向上: 潜在的なバグやエラーを早期に発見しやすくなります。より安全なコード: 意図しない動作を防ぎ、セキュリティ上の脆弱性を軽減できます。将来性: 将来のバージョンのJavaScriptでは、厳格モードがデフォルトになる可能性があります。


GoogleのJSON応答の先頭にwhile(1);が付加される理由

JSONPは、クロスドメインリクエストを可能にするJavaScript技術です。従来のAJAXリクエストとは異なり、JSONPはJSONデータをscript要素を使用して送信します。Googleは、JSONPリクエストをサポートするために、JSON応答の先頭にwhile(1);を追加しています。これは、JSONPコールバック関数が正しく呼び出されるようにするためです。


JavaScriptで特定の範囲のランダムな数値を生成する関数を作成する方法

Math. random() を使用する方法最も簡単な方法は、 Math. random() 関数を使用する方法です。Math. random() は、0から1までの擬似乱数を生成します。1から10までのランダムな数値を生成するには、Math


パフォーマンスアップ!JavaScript 配列から要素を効率的に削除する方法

splice() メソッドを使うこれは最も一般的で、柔軟な方法です。splice() メソッドは、配列の要素を追加、削除、置き換えることができます。引数 start: 削除を開始するインデックス deleteCount: 削除する要素の数