JavaScript

JavaScriptのMath.log2():2倍と半分を対称な数値で比較する

この記事でわかること

Math.log2()で倍率を比較し、2倍と半分を対称な値に変換する方法を解説。引数・戻り値、ブラウザーとNode.jsでの実行手順、入力検証や計算精度の注意点を学べます。

目的:倍率の変化を同じ尺度で比較する

処理時間が100ミリ秒から200ミリ秒になった場合は2倍、100ミリ秒から50ミリ秒になった場合は半分です。倍率をそのまま並べると、それぞれ2と0.5になり、変化なしを表す1からの距離がそろいません。

Math.log2()を使うと、2倍を1、変化なしを0、半分を-1に変換できます。4倍なら2、4分の1なら-2です。掛け算による変化を、足し算で比較できる尺度へ置き換えられます。

この記事では、処理時間の比較を題材に、倍率を底が2の対数へ変換します。正の値どうしの相対的な変化を比較したい場合に向く方法です。元の処理時間も残せば、変化の大きさと実際の待ち時間を両方確認できます。

動作環境と対応バージョン

Math.log2()はJavaScriptの標準組み込みメソッドです。ブラウザーとNode.jsの両方で利用でき、外部パッケージやDOMは必要ありません。

2026年10月21日時点で参照したMDNのMath.log2()リファレンスでは、2015年7月以降、主要ブラウザーで広く利用可能な機能とされています。本記事のブラウザー向け手順は、現在のChrome、Edge、Firefox、Safariを対象にします。

Node.jsでは、本記事の実行対象を22系以降とします。これは記事で使う環境の範囲であり、APIの初対応バージョンを意味しません。実験的な機能を有効にするフラグは不要です。Node.jsの標準機能と実行フラグの関係は公式のECMAScript解説も参照してください。

古いブラウザーや組み込みの実行環境を対象にする場合は、typeof Math.log2 === "function"で利用可能か確認できます。後述のコードにも、この確認を含めます。

引数と戻り値を理解する

基本構文

JavaScript
Math.log2(x)

引数のxは、対数を求める数値です。戻り値はnumberで、「2を何乗するとxになるか」を表します。たとえば2の3乗は8なので、Math.log2(8)は3です。

Mathはコンストラクターではありません。インスタンスを作らず、Math.log2()の形で呼び出します。

値の範囲と特別な結果

  • xが1なら、戻り値は0です。
  • xが1より大きければ、戻り値は正になります。
  • xが0より大きく1未満なら、戻り値は負になります。
  • xが0または-0なら、戻り値は-Infinityです。
  • xが負の数なら、戻り値はNaNです。
  • xがInfinityなら、戻り値はInfinityです。

これらの特殊値は、MDNの使用例でも確認できます。負数を渡しても、そのことだけで例外になるわけではありません。業務上受け付けない値は、呼び出す側で検証する必要があります。

コピーして試す:処理時間の倍率を変換する

次のコードは、以前と現在の処理時間から倍率を求め、その倍率をMath.log2()へ渡します。入力は有限の正の数値に限定します。

自己完結したコード

Node.jsで試す場合は、次の内容をlog-two-demo.cjsという名前で保存してください。ブラウザーでは、コード全体を開発者ツールのコンソールで実行できます。

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

  if (typeof Math.log2 !== "function") {
    console.error("この環境ではMath.log2()を利用できません");
    return;
  }

  function compareDuration(previous, current) {
    for (const value of [previous, current]) {
      if (typeof value !== "number" || !Number.isFinite(value)) {
        throw new TypeError("処理時間は有限の数値にしてください");
      }
      if (value <= 0) {
        throw new RangeError("処理時間は0より大きくしてください");
      }
    }

    const ratio = current / previous;
    if (!Number.isFinite(ratio) || ratio <= 0) {
      throw new RangeError("倍率が計算可能な範囲を外れています");
    }

    return { ratio, logRatio: Math.log2(ratio) };
  }

  const samples = [
    { label: "変化なし", previous: 100, current: 100 },
    { label: "2倍", previous: 100, current: 200 },
    { label: "半分", previous: 100, current: 50 },
    { label: "4倍", previous: 100, current: 400 },
    { label: "4分の1", previous: 100, current: 25 },
    { label: "不正な入力", previous: 0, current: 100 },
  ];

  for (const sample of samples) {
    try {
      const result = compareDuration(sample.previous, sample.current);
      console.log(
        `${sample.label}: 倍率=${result.ratio}, 対数=${result.logRatio}`
      );
    } catch (error) {
      if (!(error instanceof Error)) {
        throw error;
      }
      console.log(`${sample.label}: ${error.name}: ${error.message}`);
    }
  }
})();

ブラウザーでの実行方法

Chromeなどで空のタブを開き、開発者ツールからコンソールを選択します。上のJavaScript全体を入力して実行してください。HTMLファイルの作成やサーバーの起動は不要です。

コードを即時実行関数で囲んでいるため、再実行してもトップレベルのconst宣言が衝突しません。コンソールが表示する評価結果のundefinedは、後述のログとは別の表示です。

Node.jsでの実行方法

Node.js 22系以降を用意し、ターミナルでlog-two-demo.cjsを保存したフォルダーへ移動して、次を実行します。

Shell
node --version
node log-two-demo.cjs

追加のインストール作業やpackage.jsonは必要ありません。.cjsを使うことで、周囲のプロジェクトのモジュール設定による影響を避けています。ファイル名を指定して実行する手順はNode.js公式ガイドに沿っています。

期待出力と計算の読み方

対応環境では、次のログが出る想定です。これはコードと仕様から導いた期待出力であり、実機での実行確認結果ではありません。

CODE
変化なし: 倍率=1, 対数=0
2倍: 倍率=2, 対数=1
半分: 倍率=0.5, 対数=-1
4倍: 倍率=4, 対数=2
4分の1: 倍率=0.25, 対数=-2
不正な入力: RangeError: 処理時間は0より大きくしてください

current / previousなので、現在の処理時間が長くなると正、短くなると負です。この例では正方向が遅延の増加を意味します。処理件数など、大きいほうが望ましい指標では評価の向きが変わるため、画面上に指標の意味を明記してください。

logRatioが2だからといって、処理時間が2ミリ秒増えたわけではありません。基準の4倍になったという意味です。単位付きの差分と対数による倍率は、別の情報として扱います。

失敗例と制約

try/catchだけではNaNを防げない

次のコードは例外を投げず、NaNを出力します。

JavaScript
try {
  console.log(Math.log2(-8));
} catch (error) {
  console.log("計算に失敗しました");
}

catchへ入ることを前提にしていると、不正な計算結果が後続処理へ流れます。実用例で型、有限性、正数という条件を先に確認したのは、この問題を防ぐためです。文字列の"100"も実用例では拒否し、入力形式の誤りを見逃さない設計にしています。

ゼロを勝手に置き換えない

処理時間がゼロだった場合、実用例はRangeErrorにします。ゼロを小さな正数へ置き換えれば計算はできますが、選んだ数によって結果が大きく変わります。計測の分解能より短かった値なのか、欠測をゼロで表しているのかを確認し、別の表示状態として扱うほうが判断しやすくなります。

割り算と丸め誤差にも注意する

有限の正数どうしでも、極端な値を割ると倍率がInfinityになったり、非常に小さくなって0になったりします。実用例は割り算の後も検証し、その範囲を扱わない方針です。

また、一般の入力では計算結果が近似値になります。対数が整数かどうかの厳密比較や、境界ぎりぎりの値による区分には注意してください。表示用に小数桁をそろえる場合も、判定には丸める前の値を使い、許容誤差は計測精度に基づいて決めます。

この処理は同期処理です。Promiseやawaitは不要で、実用例は各データの例外をその場で処理しているため、不正な1件があっても次のデータへ進みます。

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

同じ種類の処理について、変更前後の所要時間を比較するレポートに使えます。2倍と半分、4倍と4分の1を対称に表せるため、基準からの相対的な変化を並べやすくなります。

ただし、元の値の重要性は残ります。1ミリ秒から2ミリ秒への変化と、1秒から2秒への変化は、対数上ではどちらも1です。利用者への影響まで同じとは判断できません。

実務へ導入するなら、最初は元の処理時間、倍率、対数の3つを併記する方法を提案します。対数だけでは読み取りに慣れが必要ですが、元データを併記すれば結果の意味を確かめられるためです。まず比較条件をそろえた小さなレポートで試し、判断に役立つことを確認してから表示へ組み込みましょう。

公式参考資料

PREFERRED SOURCES

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

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

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

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

y.
WRITTEN BY

y_ymo10

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

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