JavaScript | 数値を固定小数点数形式で文字列に変換(toFixed() メソッド)

javascrpit JavaScript
スポンサーリンク

金融や会計などでは「0.01 の誤差すら絶対に許されない」世界です。
JavaScript の標準的な数値(Number 型)は IEEE754 の倍精度浮動小数点数 を使っているため、
例えばこんな危険な例があります。

JavaScript の罠(浮動小数点誤差)

0.1 + 0.2      // → 0.30000000000000004
1.0 - 0.9      // → 0.09999999999999998
0.29 * 100     // → 28.999999999999996
JavaScript

こうしたわずかな誤差が、金額計算で積み重なると大問題になります。
たとえば「合計金額が1円ズレる」「決算帳票が合わない」など…。

解決策1:整数(最小単位)で管理する

もっともシンプルで信頼性の高い方法です。
円やセントなどの最小単位(整数)で内部計算を行い、
表示するときだけ小数形式に変換します。

例:円単位で扱う(内部では整数)

// 3,500円の商品を2個購入、8%消費税
const priceYen = 3500;   // ← 「円」単位で整数
const qty = 2;
const taxRate = 8;       // %

const subtotal = priceYen * qty; // 7000
const tax = Math.round(subtotal * taxRate / 100); // 560
const total = subtotal + tax; // 7560

console.log(total.toLocaleString() + "円"); // → "7,560円"
JavaScript

浮動小数点を使わないので誤差はゼロ。
円単位やセント単位が明確な金融アプリではこの方法が最も確実です。

解決策2:BigInt で大きな整数を扱う

JavaScript ES2020 以降では、BigInt 型が使えます。
大きな金額(兆単位など)も誤差なしで扱えます。

const price = 3500n; // BigInt リテラル(末尾に n)
const qty = 2n;
const taxRate = 8n;

const subtotal = price * qty; // 7000n
const tax = subtotal * taxRate / 100n; // 560n
const total = subtotal + tax; // 7560n
console.log(total.toString()); // "7560"
JavaScript

ただし BigInt 同士でしか演算できず、Number と混ぜるとエラーになるので注意。

解決策3:小数ライブラリ(decimal.js, big.js 等)を使う

「ドル」「ビットコイン」など小数点以下の計算が必要な場合、
小数点を正確に扱えるライブラリを使うのが安全です。

代表的なもの:

ライブラリ特徴
decimal.js高精度の10進演算、丸めモードや指数も指定可能
big.js軽量で高速、金額計算に最適
bignumber.js金融・暗号通貨系でよく使われる
// npm install decimal.js
const Decimal = require('decimal.js');

const a = new Decimal(0.1);
const b = new Decimal(0.2);
console.log(a.plus(b).toString()); // → "0.3"(誤差なし!)

// 金額計算例
const price = new Decimal(3500);
const qty = new Decimal(2);
const taxRate = new Decimal(0.08);

const subtotal = price.times(qty);       // 7000
const tax = subtotal.times(taxRate);     // 560
const total = subtotal.plus(tax);        // 7560
console.log(total.toFixed(0));           // "7560"
JavaScript

decimal.js は内部的に文字列として10進数を扱うため、
2進数浮動小数点の誤差が一切発生しません

解決策4:数値フォーマットだけ toFixed に任せる

上のような方法で正しい数値を得たあと、
**表示整形(見た目のフォーマット)**だけを toFixed() で行うのはOKです。

const total = 7560;
console.log((total / 1000).toFixed(2)); // "7.56" → 7.56千円 表示用
JavaScript

まとめ:金融向け「誤差ゼロ」実践パターン

用途方法精度備考
円・セント単位(整数計算で済む)整数で管理✅完全正確最小単位を整数化して保持
大きな金額・桁数(兆単位など)BigInt✅完全正確四則演算限定、浮動小数は扱えない
小数点以下の金額(利息、為替など)decimal.js / big.js✅完全正確金融・暗号通貨向け標準
表示整形のみtoFixed⚠️誤差あり計算済み数値の見た目用に限定

まとめコード例:decimal.js 版「安全な金額計算」

// npm install decimal.js
const Decimal = require('decimal.js');

function calcTotal(price, qty, taxRate) {
  const p = new Decimal(price);
  const q = new Decimal(qty);
  const t = new Decimal(taxRate);

  const subtotal = p.times(q);
  const tax = subtotal.times(t);
  const total = subtotal.plus(tax);
  
  return total.toFixed(2); // "7560.00" のように整形して返す
}

console.log(calcTotal(3500, 2, 0.08)); // → "7560.00"
JavaScript
タイトルとURLをコピーしました