2.

JavaScript Number 型完全ガイド(整数 / 浮動小数点 / IEEE 754 誤差 / BigInt)

編集
この記事の要点
  • JavaScript の Number整数も浮動小数点も同じ型(IEEE 754 倍精度 64bit)
  • 安全な整数の最大値は Number.MAX_SAFE_INTEGER = 2^53 - 1 = 9007199254740991。これを超える整数は BigInt を使う
  • 0.1 + 0.2 === 0.30000000000000004金額計算は整数(最小単位の銭)で扱うtoFixed() + 比較関数を使う
  • 型変換: parseInt("42px") = 42 / parseFloat("3.14abc") = 3.14 / Number("42") = 42 / Number("42px") = NaN
  • 判定: Number.isInteger(x) / Number.isNaN(x) / Number.isFinite(x)。グローバル isNaN() は型変換するので非推奨

JavaScript の Number 型の基本

JavaScript の Number1 つの型で整数も浮動小数点も扱います。内部表現は IEEE 754 倍精度 64bit 浮動小数点(符号 1bit + 指数 11bit + 仮数 52bit)。

typeof 42;          // 'number'
typeof 3.14;        // 'number'  ← 同じ型
typeof NaN;         // 'number'
typeof Infinity;    // 'number'

// 整数リテラル / 小数リテラル
const a = 42;
const b = 3.14;
const c = 0xFF;     // 16 進数 = 255
const d = 0b1010;   // 2 進数  = 10
const e = 0o777;    // 8 進数  = 511
const f = 2.5e3;    // 指数表記 = 2500

整数の限界: MAX_SAFE_INTEGER

JS は整数も 64bit 浮動小数点で表すため、仮数 53bit を超える整数は誤差が出ます:

Number.MAX_SAFE_INTEGER;        // 9007199254740991 = 2^53 - 1
Number.MIN_SAFE_INTEGER;        // -9007199254740991

9007199254740992 === 9007199254740993;  // true ! 区別できない
9007199254740992 + 1 === 9007199254740992;  // true

// 安全に扱えるか判定
Number.isSafeInteger(9007199254740991);  // true
Number.isSafeInteger(9007199254740992);  // false

// 巨大整数は BigInt で
const big = 9007199254740993n;  // n サフィックス
typeof big;                     // 'bigint'
big + 1n;                       // 9007199254740994n
// big + 1;                     // TypeError: Cannot mix BigInt and other types

浮動小数点の罠: 0.1 + 0.2

有名な現象ですが、2 進数では 0.1 が無限循環小数になるため誤差が出ます:

0.1 + 0.2;              // 0.30000000000000004
0.1 + 0.2 === 0.3;      // false !
0.3 - 0.2 === 0.1;      // false (0.09999999999999998)

// 対策1: 整数で扱う(金額は「銭」「円」の最小単位で保持)
function addYen(a, b) {
  return Math.round((a + b) * 100) / 100;  // 銭単位で四捨五入
}

// 対策2: 許容誤差で比較
function nearlyEqual(a, b, eps = 1e-9) {
  return Math.abs(a - b) < eps;
}
nearlyEqual(0.1 + 0.2, 0.3);  // true

// 対策3: toFixed で文字列化(表示のみ)
(0.1 + 0.2).toFixed(2);  // '0.30'

// 対策4: 高精度ライブラリ
// big.js / decimal.js / bignumber.js

文字列 → 数値 変換

関数動作
parseInt(s, 10)先頭から数字を読む / 末尾の文字は捨てるparseInt('42px') = 42
parseFloat(s)小数を読むparseFloat('3.14abc') = 3.14
Number(s)全体が数値でないと NaNNumber('42px') = NaN
+sNumber() と同じ(短縮)+'42' = 42
s | 0整数化(32bit に丸め)'3.7' | 0 = 3
// 第 2 引数の基数を必ず指定(特に古いブラウザ)
parseInt('010', 10);   // 10  (10進数として解釈)
parseInt('010', 8);    // 8   (8進数として)
parseInt('0xFF', 16);  // 255

// 空文字 / 空白の挙動
Number('');            // 0 !
Number(' ');           // 0 !
Number(null);          // 0 !
Number(undefined);     // NaN
Number(true);          // 1
Number(false);         // 0
Number([1]);           // 1   (要素1つの配列)
Number([1, 2]);        // NaN
Number({});            // NaN

parseInt('');          // NaN  (こちらは NaN)

NaN / Infinity の判定

// NaN は自分自身と等しくない (唯一)
NaN === NaN;        // false !
NaN !== NaN;        // true

// 正しい判定
Number.isNaN(NaN);      // true
Number.isNaN('abc');    // false  (文字列であって NaN ではない)
isNaN('abc');           // true   (グローバル isNaN は型変換するため非推奨)

// 有限値判定
Number.isFinite(42);        // true
Number.isFinite(Infinity);  // false
Number.isFinite(NaN);       // false
Number.isFinite('42');      // false  (グローバル isFinite('42') は true)

// Infinity
1 / 0;            // Infinity
-1 / 0;           // -Infinity
Number.MAX_VALUE; // 1.7976931348623157e+308
Number.MIN_VALUE; // 5e-324 (最小の正の値)

丸め: floor / round / ceil / trunc

Math.floor(3.7);    // 3   (切り捨て: -∞方向)
Math.floor(-3.2);   // -4  ← 負だと注意

Math.ceil(3.2);     // 4   (切り上げ: +∞方向)
Math.ceil(-3.7);    // -3

Math.round(3.5);    // 4   (四捨五入)
Math.round(3.4);    // 3
Math.round(-3.5);   // -3  ← 偶数丸めではない(銀行家丸めではない)

Math.trunc(3.7);    // 3   (0方向への切り捨て)
Math.trunc(-3.7);   // -3

// 小数 N 桁で丸める
function round(num, digits) {
  const k = Math.pow(10, digits);
  return Math.round(num * k) / k;
}
round(3.14159, 2);  // 3.14

Number ⇄ 文字列 変換(表示用)

(1234.567).toFixed(2);        // '1234.57'  小数2桁固定
(1234.567).toPrecision(4);    // '1235'     有効数字4桁

(0.0001234).toExponential(2); // '1.23e-4'
(255).toString(16);           // 'ff'   16進数文字列
(10).toString(2);             // '1010' 2進数文字列

// カンマ区切り
(1234567).toLocaleString();         // '1,234,567' (環境依存)
(1234567).toLocaleString('ja-JP');  // '1,234,567'

// 通貨
(1234.56).toLocaleString('ja-JP', {
  style: 'currency', currency: 'JPY'
});  // '¥1,235'  (JPY は整数化される)

整数判定 / 偶奇

Number.isInteger(42);     // true
Number.isInteger(42.0);   // true  (内部は同じ)
Number.isInteger(42.5);   // false
Number.isInteger('42');   // false (文字列)
Number.isInteger(NaN);    // false

// 偶奇
const isEven = n => n % 2 === 0;
const isOdd  = n => n % 2 !== 0;

// 範囲制限
const clamp = (n, min, max) => Math.min(Math.max(n, min), max);
clamp(15, 0, 10);  // 10

BigInt(任意精度整数)

const a = 12345678901234567890n;
const b = BigInt('98765432109876543210');

a + b;            // 111111111011111111100n
2n ** 100n;       // 1267650600228229401496703205376n

// Number と BigInt は混在不可
// 1n + 1;        // TypeError
1n + BigInt(1);   // 2n
Number(1n) + 1;   // 2  (BigInt → Number、ただし精度損失あり)

// JSON.stringify は BigInt 非対応
// JSON.stringify({ id: 1n });  // TypeError
// → 自前で toJSON: BigInt.prototype.toJSON = function() { return this.toString(); };

FAQ

Q: 金額計算で誤差が出る
A: 銭 / セント等の最小単位を整数で持つのが王道。複雑なら decimal.js を使ってください。

Q: 0 === -0 の挙動
A: 0 === -0 は true ですが、Object.is(0, -0) は false。1 / 0 === Infinity / 1 / -0 === -Infinity で区別できます。

Q: parseInt('0.0000001') が 1 になる
A: '0.0000001''1e-7' に内部変換 → parseInt が 1 を取得します。Number()parseFloat() を使うのが正解。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. String(文字列)
  2. Number (数値: 整数/浮動小数点数)
  3. Boolean (真偽値: true/false)
  4. Any (全ての型を許容)
  5. Array(配列)
  6. Tuple (値のペア)