JavaScriptのMath.sign():数値の差分を増加・減少・変化なしに分類する
Math.sign()で数値の符号を調べ、差分を増加・減少・変化なしに分類する方法を解説。引数・戻り値、ブラウザーとNode.jsの実行手順、入力検証や小数の誤差への対処を学べます。
目的:変化の大きさから向きだけを取り出す
前回と今回の在庫数を比較するとき、「何個変わったか」と「増えたか減ったか」は別の情報です。差分が20でも3でも、増加を示す表示は共通にできます。
Math.sign()は、数値の符号を調べる静的メソッドです。正なら1、負なら-1を返すため、差分を表示用の状態へ変換するときに使えます。ゼロはゼロのまま返します。MDNのMath.sign()
この記事では、在庫の差分を「増加」「減少」「変化なし」に分類します。方向を求めた後も元の差分を残す設計にし、表示と集計の両方で利用できるようにします。
動作環境と互換性
2026年10月23日時点で、MDNはMath.sign()を広く利用可能な機能とし、2015年9月から主要ブラウザー間で利用できると説明しています。現在のChrome、Edge、Firefox、Safariが対象です。この説明は、すべての旧バージョンで動くという意味ではありません。MDNの互換性情報
Math.sign()はブラウザー専用APIではなく、Node.jsでも利用できます。本記事のサンプルはNode.js 22以降を対象とします。これはサンプルの対象バージョンであり、同APIが初めて実装されたバージョンではありません。追加パッケージや実験用フラグは不要です。Node.jsにおけるJavaScript機能の提供方針は、公式のECMAScript解説で確認できます。
古い実行環境へ配布する場合は、先にtypeof Math.sign === "function"で存在を確認してください。存在しなければ、環境の更新やポリフィルの導入を検討します。
ブラウザーで実行する
開発者ツールを開き、Consoleに後述のJavaScriptコード全体を貼り付けて実行します。HTMLや外部ライブラリーは不要です。サンプルは即時実行関数で囲んでいるため、同じConsoleで繰り返し実行できます。
Node.jsで実行する
Node.jsを導入した環境で、コードをUTF-8のinventory-sign.jsに保存します。ターミナルで保存先フォルダーへ移動し、次のコマンドを実行してください。
node --version
node inventory-sign.js最初の行でバージョンを確認し、次の行でファイルを実行します。ファイル名をnodeに渡す方法は、Node.js公式の実行手順に沿っています。
引数と戻り値
呼び出し方はMath.sign(x)です。引数xを1つ受け取り、符号を表す数値を同期的に返します。Promiseではないので、awaitは必要ありません。
- 正の数の戻り値は
1です。 - 負の数の戻り値は
-1です。 0の戻り値は0です。-0の戻り値は-0です。NaNや、数値へ変換できない文字列ではNaNになります。
Math.sign()は入力検証の関数ではありません。例えば文字列の"-3"も数値へ変換され、-1になります。引数を省略した場合はNaNです。これらはMDNの使用例にも示されています。
アプリケーションで数値だけを受け付けたい場合は、呼び出し前に型と値の範囲を確かめます。今回使うNumber.isFinite()は暗黙の数値変換をせず、有限の数値だけを受け付けます。MDNのNumber.isFinite()
自己完結したコードで在庫の変化を分類する
次のコードをブラウザーのConsole、またはinventory-sign.jsで実行してください。通信やファイル読み込みは行わず、コード内の固定データだけを使います。
(() => {
"use strict";
function classifyChange(previous, current) {
if (!Number.isFinite(previous) || !Number.isFinite(current)) {
throw new TypeError("前回値と今回値には有限の数値が必要です");
}
const delta = current - previous;
if (!Number.isFinite(delta)) {
throw new RangeError("差分が有限の数値に収まりません");
}
const direction = Math.sign(delta);
let label;
if (direction === 0) {
label = "変化なし";
} else if (direction === 1) {
label = "増加";
} else {
label = "減少";
}
return { delta, direction, label };
}
const inventories = [
{ name: "ノート", previous: 10, current: 14 },
{ name: "ペン", previous: 8, current: 5 },
{ name: "付箋", previous: 6, current: 6 }
];
for (const item of inventories) {
const result = classifyChange(item.previous, item.current);
console.log(
`${item.name}: 差分=${result.delta}, ` +
`方向=${result.direction}, ${result.label}`
);
}
try {
classifyChange(10, "14");
} catch (error) {
console.log(`${error.name}: ${error.message}`);
}
})();期待出力
ノート: 差分=4, 方向=1, 増加
ペン: 差分=-3, 方向=-1, 減少
付箋: 差分=0, 方向=0, 変化なし
TypeError: 前回値と今回値には有限の数値が必要ですこれは仕様とコードの読み取りから求めた期待出力であり、実機での実行検証結果ではありません。
classifyChange()は、前回値previousと今回値currentを受け取り、差分delta、方向direction、表示名labelを持つオブジェクトを返します。差分は必ず「今回値から前回値を引く」順序にします。引き算を逆にすると、増減の判定も逆になります。
入力が有限でも、極端に大きな正負の値を引くと差分が無限大になる場合があります。そのため、入力に加えて差分も検証しています。通常の在庫数では起きにくいものの、共通関数として使う際の境界を明確にできます。
例外は同期的に発生するので、失敗例はtry...catchで受け止めます。非同期処理や通信がないため、Promiseの拒否処理はありません。
失敗例と制約
正かどうかを真偽値だけで判断しない
if (Math.sign(delta))と書くと、1も-1も真として扱われます。その分岐だけでは増加と減少を区別できません。方向ごとに処理する場合は、サンプルのように1、-1、ゼロを比較します。
また、検証せずに「正でも負でもなければ変化なし」とすると、NaNまで変化なしに分類する危険があります。未知の入力は先に検証し、正常な数値だけを分類へ進めてください。
負のゼロを業務上の状態へ持ち込まない
JavaScriptには-0があり、Math.sign(-0)も-0です。ただし、-0 === 0は真なので、今回のdirection === 0は両方を「変化なし」にまとめます。
在庫や件数の表示では、この扱いが自然です。符号付きゼロ自体に意味がある数値計算へ転用する場合は、表示用の分類と計算用の値を分けて設計してください。
小数の誤差を解消する機能ではない
Math.sign()は、小さな正負の値もそのまま分類します。例えば0.1 + 0.2 - 0.3は浮動小数点の誤差で厳密なゼロにならず、増加と判断される場合があります。
計測値を扱うなら、「絶対値が0.01未満なら変化なし」のような業務上の許容差を先に定め、その範囲をゼロへそろえてからMath.sign()を使います。許容差は単位と必要精度に合わせます。一律の小さな定数を置くだけでは、用途に合うとは限りません。
活用事例と設計の改善案
在庫管理以外にも、アクセス件数の前回比較や、目標値に対する過不足の表示に使えます。変化量の単位が異なっても、方向を-1、ゼロ、1で扱えば表示ルールを共有できます。
ただし、「増加」と「良い変化」は別です。販売数の増加と障害件数の増加では意味が異なります。改善案として、数値の分類を行う関数と、指標ごとの評価を行う処理を分けてください。Math.sign()の結果だけで表示色や評価を決定しない設計にすると、指標を追加しても修正範囲を抑えられます。
まずはサンプルの在庫数を変更し、増加・減少・同値の3ケースを確認します。その後、実際のデータの単位、許容範囲、欠損値の扱いを決めてから組み込むと、判定の意味が明確になります。
公式参考資料
Googleの優先するニュース提供元にSEの部屋を追加
Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。
候補にSEの部屋が表示されない場合は、まだ追加できません。