生成AI研修
金融システム開発規約

金額計算のルール

決済システムにおける金額の扱い方、浮動小数点の罠、丸め処理

金額計算のルール

決済システムで最も致命的なバグは「金額の計算誤り」です。1円のずれが数百万件の取引で累積すると巨額の差異になります。


1. 浮動小数点を使わない

なぜ浮動小数点がダメなのか

// 絶対にやってはいけない
0.1 + 0.2  // → 0.30000000000000004
1.03 * 100 // → 102.99999999999999

IEEE 754 浮動小数点数は、10進数を正確に表現できません。金額計算に使うと、丸め誤差が累積します。

正しい方法: 最小通貨単位の整数で扱う

// 正しい: 円の場合は整数(銭は使わない)
const price = 1000;  // 1000円
const tax = 100;     // 100円
const total = price + tax;  // 1100円

// 正しい: USDの場合はセント単位の整数
const priceUsd = 1099;  // $10.99 = 1099 cents
通貨最小単位表現方法
JPY(円)1円整数そのまま(100 = 100円)
USD(ドル)1セントセント単位の整数(1099 = $10.99)
BHD(ディナール)1フィルスミリ単位(1000 = 1 BHD)

ルール: 金額は必ず最小通貨単位の整数値bigint or long)で保持する。表示時に小数点を付与する。


2. 言語別の推奨実装

TypeScript / JavaScript

// BigIntを使用
const amount = BigInt(10000);  // 10000円

// ライブラリの活用
// dinero.js, currency.js 等の通貨ライブラリを使用する

Java

// BigDecimalを使用(doubleは禁止)
BigDecimal amount = new BigDecimal("1000");
BigDecimal rate = new BigDecimal("0.08");
BigDecimal tax = amount.multiply(rate)
    .setScale(0, RoundingMode.HALF_UP);

Python

from decimal import Decimal, ROUND_HALF_UP

# Decimalを使用(floatは禁止)
amount = Decimal('1000')
rate = Decimal('0.08')
tax = (amount * rate).quantize(Decimal('1'), rounding=ROUND_HALF_UP)

3. 丸め処理

丸めモードの種類

モード動作用途
HALF_UP四捨五入一般的な金額計算
HALF_EVEN銀行丸め(偶数丸め)統計的に偏りが少ない
DOWN切り捨て消費者有利の計算
UP切り上げ事業者有利の計算

ルール: 丸めモードはビジネス仕様として明示的に定義し、コード内でデフォルトの丸めに依存しない。

消費税計算の注意点

// 悪い例: 合計に税率を掛ける
const total = items.reduce((sum, item) => sum + item.price, 0);
const tax = Math.round(total * 0.10);

// 良い例: 明細ごとに税額を計算し、丸めてから合計
const taxTotal = items.reduce((sum, item) => {
  return sum + Math.floor(item.price * 0.10);
}, 0);

消費税の端数処理は、事業者が「切り捨て」「切り上げ」「四捨五入」を選択できます。どの方式を採用しているかを仕様として明記してください。


4. 通貨の扱い

通貨コード(ISO 4217)

通貨は必ず ISO 4217 の通貨コードで管理します。

interface Money {
  amount: bigint;       // 最小単位の整数
  currency: string;     // ISO 4217 通貨コード("JPY", "USD" 等)
}

// 異なる通貨の演算は禁止
function add(a: Money, b: Money): Money {
  if (a.currency !== b.currency) {
    throw new Error(`Currency mismatch: ${a.currency} vs ${b.currency}`);
  }
  return { amount: a.amount + b.amount, currency: a.currency };
}

為替計算

  • 為替レートは 小数点以下の桁数を十分に確保(通常6桁以上)
  • レート適用のタイミング(取引時 or 精算時)を仕様で明確にする
  • 為替差損益の処理方法を定義する

5. チェックリスト

  • 金額に float / double を使用していないか
  • 金額を最小通貨単位の整数で保持しているか
  • 丸めモードが明示的に指定されているか
  • 異なる通貨間の演算を防止しているか
  • 消費税の端数処理方式がドキュメント化されているか
  • オーバーフローのチェックを行っているか

On this page