JavaScript

JavaScriptのMath.clz32():整数の表現に必要なビット数を求める

この記事でわかること

Math.clz32()で先頭のゼロビットを数え、整数の表現に必要なビット数を求める方法を解説。引数・戻り値、入力検証、ブラウザーとNode.jsの実行手順、32ビット変換の制約を学べます。

整数をバイナリー形式で保存するとき、「この値を表すには何ビット必要か」を知りたい場面があります。例えば、値が255までなら8ビットで収まりますが、256を含むなら9ビット必要です。

Math.clz32()は、32ビットの整数表現で先頭に連続するゼロを数えるメソッドです。その結果を32から引けば、正の整数の表現に必要なビット数を求められます。この記事では、この性質を使った入力検証付きの関数を作ります。

Math.clz32()の目的と基本動作

clz32はCount Leading Zeros 32の略です。数値を32ビットの符号なし整数へ変換し、最上位側から最初の1に出会うまでのゼロを数えます。

例えば、5の2進表現は101です。32桁にそろえると、その前に29個のゼロが並びます。そのため、Math.clz32(5)の戻り値は29です。

JavaScript
console.log(Math.clz32(0));
console.log(Math.clz32(1));
console.log(Math.clz32(5));
console.log(Math.clz32(255));
console.log(Math.clz32(256));

期待出力は次のとおりです。

CODE
32
31
29
24
23

ゼロは32ビットすべてがゼロなので、戻り値は32です。途中や末尾にあるゼロは数えません。例えば、5の101の中央にあるゼロは結果に影響しません。MDNのMath.clz32()で、この動作を確認できます。

動作環境とバージョン

2026年10月15日時点で、MDNはMath.clz32()を広く利用可能な機能とし、2015年7月以降はブラウザー横断で利用できると説明しています。現在のChrome、Edge、Firefox、Safariで使用できます。

ブラウザー専用のAPIではないため、Node.jsでも利用できます。この記事のサンプルはNode.js 22以降を対象とします。これは記事の実行対象であり、Math.clz32()が初めて導入されたバージョンを意味しません。追加パッケージや実験的フラグは不要です。

古いブラウザーや組み込みのJavaScript実行環境では、実行前に機能の有無を確認してください。

JavaScript
console.log(typeof Math.clz32 === "function");

対応環境の期待出力はtrueです。後述する完成コードにも同じ確認を入れ、非対応環境では処理を続行しない構成にします。

引数・戻り値と32ビットへの変換

呼び出し方

構文はMath.clz32(x)です。xには調べたい数値を渡します。Mathの静的メソッドなので、インスタンスを作る必要はありません。

戻り値は0から32までの整数です。32ビット表現の最上位が1なら0、すべてゼロなら32を返します。入力値そのものを書き換える処理はありません。

自動変換は入力検証にならない

引数は数値に変換され、その後32ビットの符号なし整数として扱われます。小数や文字列を渡しても、常にエラーになるわけではありません。

JavaScript
console.log(Math.clz32("5"));
console.log(Math.clz32(5.9));
console.log(Math.clz32(-1));
console.log(Math.clz32(4294967296));
console.log(Math.clz32(NaN));

期待出力は次のとおりです。

CODE
29
29
0
32
32

文字列の"5"は数値の5へ変換され、5.9の小数部分は取り除かれます。負の1は32ビット変換によって全ビットが1の値になります。2の32乗である4294967296は変換後にゼロとなります。

このため、任意の大きな整数のビット数を調べる用途へ、そのまま適用できません。数値変換ができないSymbolやBigIntを直接渡すとTypeErrorになる点にも注意が必要です。

入力検証付きの完成コード

次の例は、0から4294967295までの整数だけを受け付けるbitLength32()を定義します。正の整数では32 - Math.clz32(value)を返し、ゼロのビット長はアプリケーション側の約束として0とします。

JavaScript
(() => {
  "use strict";

  if (typeof Math.clz32 !== "function") {
    console.log("この環境はMath.clz32()に対応していません");
    return;
  }

  function bitLength32(value) {
    if (typeof value !== "number") {
      throw new TypeError("数値を指定してください");
    }

    if (
      !Number.isInteger(value) ||
      value < 0 ||
      value > 4294967295
    ) {
      throw new RangeError("0〜4294967295の整数を指定してください");
    }

    return 32 - Math.clz32(value);
  }

  const samples = [0, 1, 5, 255, 256, 4294967295];

  for (const value of samples) {
    console.log(`${value}: ${bitLength32(value)}ビット`);
  }

  const maximumCode = 1000;
  const width = bitLength32(maximumCode);
  console.log(`最大コード${maximumCode}の保存幅: ${width}ビット`);

  const invalidValues = ["5", -1, 1.5, 4294967296];

  for (const value of invalidValues) {
    try {
      bitLength32(value);
    } catch (error) {
      console.log(`${JSON.stringify(value)}: ${error.name}`);
    }
  }
})();

期待出力は次のとおりです。実機実行の記録ではなく、仕様と各入力から導いた結果です。

CODE
0: 0ビット
1: 1ビット
5: 3ビット
255: 8ビット
256: 9ビット
4294967295: 32ビット
最大コード1000の保存幅: 10ビット
"5": TypeError
-1: RangeError
1.5: RangeError
4294967296: RangeError

Number.isInteger()によって、小数だけでなくNaNや無限大も拒否します。さらに上限を確認することで、32ビット変換による値の折り返しを防ぎます。

例外を捕捉しているのは失敗を試す部分です。入力ごとにtry...catchを置いているため、1件が失敗しても次の入力を確認できます。すべて同期処理なので、awaitやPromiseの拒否処理は不要です。

ブラウザーとNode.jsでの実行方法

ブラウザーで実行する

対応ブラウザーで空のタブを開き、開発者ツールのConsoleを表示します。「入力検証付きの完成コード」のJavaScript全体をコピーして実行してください。コードフェンスの記号はコピーしません。

出力はページ本体ではなくConsoleに表示されます。即時実行関数の中に変数や関数を置いているため、同じコードを再実行しても、トップレベルの定数の再宣言による衝突を避けられます。

Consoleが式の評価結果として最後にundefinedを表示する場合があります。これはサンプルが返す値であり、期待出力に含めたログの失敗を意味しません。

Node.jsで実行する

Node.js 22以降を用意し、完成コードをUTF-8のbit-length.cjsとして保存します。ターミナルで保存先のフォルダーを開き、次を実行します。

Shell
node bit-length.cjs

ブラウザーと同じログがターミナルに表示されます。documentやwindowを使わないため、コードの変更は不要です。ファイル名をnodeへ渡す実行方法は、Node.js公式のスクリプト実行ガイドで確認できます。

失敗例と設計上の制約

ゼロの表現方法を決める

完成コードはゼロのビット長を0としています。一方、文字としてゼロを表すなら0の1桁が必要です。常に1ビット以上の保存幅が必要な形式では、戻り値が0なら1に置き換えるなど、利用側の仕様を決めてください。

ビット長は1の個数ではない

5の2進表現101には1が2個ありますが、表現に必要な長さは3ビットです。Math.clz32()から求められるのは最上位の1までを含む長さであり、立っているビットの個数ではありません。

また、符号付き整数の保存幅も別の問題です。完成コードは負数を拒否しており、符号ビットを含めた必要幅を計算するものではありません。

シフト演算での再計算に注意する

求めたビット数から値の範囲を計算するとき、安易に1 << widthを使うと、符号付き32ビット演算やシフト量の扱いによって意図しない結果になります。

例えば、幅32に対する1 << 32は4294967296になりません。この用途では2 ** widthのように通常の数値演算を使い、ビット演算の変換規則を持ち込まない設計が分かりやすくなります。

活用事例と導入時の改善案

主な活用先は、非負整数を詰めて保存する形式の幅の見積もりや、フラグ値がどのビット位置まで使われているかの確認です。最大コードが1000なら10ビット、最大値が65535なら16ビット必要だと判断できます。

ただし、この計算だけでJavaScriptの数値のメモリー使用量が減るわけではありません。ビット単位に詰める処理やバイト境界の調整は、保存形式側で別途実装します。

導入時の改善案として、入力の最大値とゼロの扱いを関数の仕様に明記してください。扱う範囲が32ビットを超えるなら、この関数の上限を外すのではなく、大きな整数を扱える別の計算方法を検討する必要があります。

公式参考資料

PREFERRED SOURCES

Googleの優先するニュース提供元にSEの部屋を追加

Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。

Googleの設定画面で確認する 新しいタブで開きます

候補にSEの部屋が表示されない場合は、まだ追加できません。

y.
WRITTEN BY

y_ymo10

SEの部屋で、HTML・CSSからJavaScript・React・Next.jsまで、Web制作の開発ノートを公開しています。

ほかの開発ノートを読む →