はじめに
ビット否定演算子~
を使用した加算・減算ができるようです。
ビット否定演算子
MDNでは以下のように定義されています。
(日本語版ではBigint
についての記載が不足しているため、英語版を引用)
The bitwise NOT (~) operator returns a number or BigInt whose binary representation has a 1 in each bit position for which the corresponding bit of the operand is 0, and a 0 otherwise.
簡単な訳
- ビット否定演算子
~
は、number
orBigint
を返します - 各bit部分が0のときは1、それ以外では0を返します
実例
理解には、実例を見るのが速いでしょう。
「ビット否定」という名称ですが、「ビット反転」と呼ぶべき挙動です。
9 (base 10) = 00000000000000000000000000001001 (base 2) -------------------------------- ~9 (base 10) = 11111111111111111111111111110110 (base 2) = -10 (base 10)
-
base 10
は10進数のこと -
base 2
は2進数のこと
- 10進数の
9
= 2進数の00000000000000000000000000001001
-
~9
=00000000000000000000000000001001
を反転させたもの - =
11111111111111111111111111110110
=-10
※ここでの負数の扱いは、以下のページで「2の補数表現」と紹介されているものです。
以上の例では、~9
が-10
になりました。この例以外でも、~n
は-(n+1)
を返します。
console.log(~-4) //3
console.log(~0) //-1
console.log(~1) //-2
console.log(~-1) //0
ビット否定を使用した加算・減算
本題です。「~n
は-(n+1)
を返す」仕様を応用して、加算・減算ができます。
function add(n) {
return -~n
}
function subtract(n) {
return ~-n
}
console.log(add(4)) // 5
console.log(subtract(0)) // -1
この手法は、単に技術的なおもしろさだけでなく、以下の利点があります。
- オペランドが一つであり、コードが短い
-
undefined
を0
として扱うことができる
undefined
を0
として扱う
これは、-~
と同じく「コードが短い」というメリットを持つ++
と比較した時のメリットです。
以下の例では、arr[1]
が存在しませんが、それを呼び出して処理をしています。
++
を使用する場合、add3
のようにn++ | 1
という書き方をすれば解決できますが、-~
は、この場合分け記述を必要としません。
function add(n) {
return -~n
}
function add2(n) {
return n++
}
function add3(n) {
return n++ | 1
}
let arr = []
console.log(add(arr[1])) // 1
console.log(add2(arr[1])) // NaN
console.log(add3(arr[1])) // 1
おわりに
面白いだけでなく、実用的な面もある興味深い手法でした。
ただ、一般的には可読性が低いと言って良いでしょう。その点は注意が必要です。
この記事は以下のコメントをもとに作成しました。コメントありがとうございました。