JavaScriptで整数のビットが交互になっているかを判定する方法
問題
整数 num を唯一の引数として受け取るJavaScript関数を作成することを考えます。
この関数の役割は、num の2進数表現におけるビットが「交互(オルタネーティング)」になっているかどうかを判定することです。つまり、隣り合うビットが常に異なる値を持つかどうかを確認します。
例として、関数に次の入力を与えた場合を見てみましょう。
入力
const num = 5;
出力
const output = true;
出力の説明
5 の2進数表現は 101 であり、0と1が交互に並んでいるため、結果は true となります。
解決アプローチ①:2進数の文字列を走査する
最も直感的な方法は、数値を2進数の文字列に変換し、隣り合う文字同士を順番に比較していくことです。同じビットが連続した時点で false を返せばよいわけです。
以下がそのコードです。
const num = 5;
const isAlternating = (num = 1) => {
const binary = num.toString(2);
let curr = binary[0];
for(let i = 1; i < binary.length; i++){
const el = binary[i];
if(curr !== el){
curr = el;
continue;
};
return false;
};
return true;
};
console.log(isAlternating(num));出力
true
コードの仕組み
toString(2)を使って、数値を2進数形式の文字列に変換します。- 先頭のビットを基準値
currとして保持します。 - 残りのビットを先頭から順に走査し、直前のビットと異なれば基準値を更新して処理を続けます。
- もし同じビットが連続していれば、そこで即座に
falseを返します。 - ループを最後まで抜けられれば、すべてのビットが交互になっているため
trueを返します。
解決アプローチ②:ビット演算を使った効率的な方法
文字列変換を行わず、ビット演算だけで判定するより効率的な方法もあります。
const isAlternating = (num = 1) => {
const x = num ^ (num >> 1);
return (x & (x + 1)) === 0;
};
console.log(isAlternating(5)); // true
console.log(isAlternating(7)); // false(111 は交互になっていない)この方法のポイント
num ^ (num >> 1): 数値自身と1ビット右シフトした値との排他的論理和(XOR)を計算します。ビットが交互になっていれば、この結果はすべて1(例:101→111)になります。x & (x + 1): すべて1のビット列に1を加えると2の累乗になります。そのため、XORの結果とその+1とのAND演算が0になれば、元の数値は交互ビットであると判定できます。
どちらのアプローチでも正しく判定できますが、大きな数値を扱う場合やパフォーマンスが重視される場面では、ビット演算を使った方法②が有利です。
-
JavaScriptのPromiseとは?非同期処理の基本をわかりやすく解説
JavaScriptのPromiseとは?Promise(プロミス)は、JavaScriptで非同期処理を扱うためのオブジェクトです。Promiseが生成された時点では、最終的な結果の値はまだ確定していません。処理が完了した将来のタイミングで、成功または失敗の結果を受け取ることができます。これにより、APIからのデータ取得やファイル読み込みなど、時間のかかる処理を効率的に記述できます。Promiseの3つの状態Promiseは、必ず以下の3つの状態のいずれかを持ちます。pending(待機):初期状態。処理がまだ完了していない状態です。fulfilled(履行):処理が正常に完了し、結果の値が
-
JavaScriptのimportで波括弧「{}」を使う理由とは?名前付きエクスポートの基本をわかりやすく解説
JavaScript(ESモジュール)でモジュールを読み込む際、import 文に波括弧 { } を付けるかどうか迷ったことはありませんか?実はこの波括弧は、名前付きエクスポート(named export)を読み込むために必要な記法です。本記事では、実際のコード例を使いながら、{ } の役割と使い方を詳しく解説します。 importで { } を使う場面とは JavaScriptのESモジュールでは、エクスポート方法によって読み込み側の書き方が変わります。 名前付きエクスポート:export { 関数名 } のようにエクスポートされたものを読み込む場合は、import { 名前 } fro