こんにちは!マクロの記録から一歩抜け出して、「本物のVBA」をマスターしようとしているあなたへ。
今日は、多くの開発者が一度はハマる「金融計算の闇」と、それを鮮やかに解決するプロの知見についてお話しします。
ここをクリアすれば、あなたの書くコードの信頼性はグッとプロフェッショナルに近づきます。さあ、一緒に扉を開けていきましょう!
—
1. なぜ「0.1 + 0.2」が「0.3」にならないのか?
まずは、次のコードをVBAのイミディエイトウィンドウで実行したと想像してください。
Debug.Print 0.1 + 0.2
数学的には「0.3」ですよね。しかし、VBAで標準の数値型(`Double`型など)を使ってこれを計算すると、結果はこうなります。
`0.30000000000000004`
「……ん? なんだこれ?」と思いましたか?
これが、コンピュータの宿命である「浮動小数点誤差(ふどうしょうすうてんごさ)」です。
コンピュータは「2進数」の世界に生きている
私たち人間は「10進数(0〜9で数を数える世界)」で生きていますが、コンピュータの内部はすべて「2進数(0と1の電気信号の世界)」で動いています。
ここで問題が起きます。
10進数の「0.1」や「0.2」という数字は、2進数に直すと「割り切れない無限小数」になってしまうのです。
ちょうど、10進数で「1÷3」をすると「0.333333…」と無限に続くのと同じ現象が、コンピュータの内部で起きています。
コンピュータは無限のメモリを持てないため、キリのいいところで「四捨五入(丸め)」してデータを保存します。その結果、細かい計算を重ねるうちに誤差が積み重なり、「合計金額が1円合わない」「税抜きの検算でズレる」という、経理や金融の現場では致命的なバグを引き起こすのです。
—
2. 【基本ルール】VBAで使える正確な計算のための2つの武器
この恐ろしい誤差を防ぐために、VBAには「Double型」とは異なる、正確な計算が得意なデータ型が用意されています。それが `Currency型` と `Decimal型` です。
先輩エンジニアとして、現場でどう使い分けるべきか、結論のルールを伝授します。
| データ型 | 扱える範囲・特徴 | 主な用途 |
| :— | :— | :— |
| Currency型 (通貨型) | 小数点以下 4桁 まで固定。整数部は約92京まで。動作が非常に高速。 | 金額計算、給与計算、消費税計算など(迷ったらコレ!) |
| Decimal型 (10進型) | 小数点以下 28桁 まで。ただし、`Dim`で直接宣言できず、`CDec関数`を経由する必要がある。 | 高精度な科学計算、厳密なレート計算など |
基本的には、日常の業務システムや経理ツールであれば `Currency型` を使っておけば間違いありません。
—
3. 実践!Currency型を使った安全な計算コード
それでは、実際に「浮動小数点誤差」が発生するパターンと、それを `Currency型` でピシャリと解決するコードを見てみましょう。
以下のコードをVBAのエディタ(標準モジュール)に貼り付けて実行してみてください。
Option Explicit
Sub CompareCalculation()
‘ ==========================================
‘ 1. 【危険な例】Double型を使った場合
‘ ==========================================
Dim dblTotal As Double
Dim i As Long
‘ 0.1円を10回足すループ
For i = 1 To 10
dblTotal = dblTotal + 0.1
Next i
Debug.Print “— Double型の結果 —”
Debug.Print “計算結果: ” & dblTotal
‘ 厳密な判定をするトグルを作ると…
If dblTotal = 1# Then
Debug.Print “判定: 1.0と一致しました!”
Else
Debug.Print “判定: 【エラー】1.0と一致しません!(誤差が発生)”
End If
‘ ==========================================
‘ 2. 【安全な例】Currency型を使った場合
‘ ==========================================
Dim curTotal As Currency
‘ 初期化(Currency型として0.1を足す)
For i = 1 To 10
curTotal = curTotal + CCur(0.1)
Next i
Debug.Print vbCrLf & “— Currency型の結果 —”
Debug.Print “計算結果: ” & curTotal
If curTotal = 1# Then
Debug.Print “判定: 1.0と完全に一致しました!”
Else
Debug.Print “判定: 一致しません。”
End If
End Sub
コードの解説
1. `Option Explicit`: 変数の宣言を強制する、プロの必須お約束です。
2. `Double型`のループ: 0.1を10回足しているだけなのに、内部の誤差によって `1` という数値との厳密な比較(`=`)に失敗します。
3. `Currency型`のループ: `CCur()` 関数を使って明示的に通貨型に変換して計算しています。結果は寸分狂わず「1」となり、条件分岐も正常にクリアします。
—N
4. さらに高精度な計算が必要なら「Decimal型」
「小数点以下が5桁以上ある為替レートの計算をしたい!」
そんな、よりシビアな要件が出てきたときは、`Variant` 型と `CDec関数` を組み合わせた Decimal型 の出番です。
VBAでは、`Dim x As Decimal` という直接宣言ができません。必ず一度 `Variant` 型として受けてから、`CDec` で型をキャスト(変換)します。
Sub DecimalSample()
Dim vResult As Variant
‘ CDec関数を使ってDecimal型として計算させる
‘ 小数点以下28桁までの精度を保持します
vResult = CDec(123.456789) CDec(1.05)
Debug.Print “高精度な計算結果: ” & vResult
Debug.Print “データの型: ” & VarType(vResult) ‘ 14 (vbDecimal) が返る
End Sub
実務の9割は `Currency型` でカバーできますが、「小数点以下の桁数が多い特殊な単価計算がある」という場合は、この `Decimal型` の存在を思い出してください。
—
まとめ:ここをクリアすれば、あなたのVBAはプロレベル!
- 浮動小数点誤差の恐怖: コンピュータは2進数で小数を扱うため、`0.1 + 0.2` すら厳密にはズレる。
- 金額・集計の救世主: 金融・経理系の計算では、迷わず `Currency型` を選択する。
- 超高精度が必要なら: `CDec関数` を使った `Decimal型` を活用する。
「動けばいいや」と適当な型でコードを書いているうちは、いつか大事なデータの集計ミスという地雷を踏んでしまいます。しかし、データの型のもつ性質を理解し、適切に選び抜くことができるあなたなら、もう大丈夫。
ここをクリアしたあなたは、単なる「マクロが動かせる人」から、信頼される「業務システムエンジニア」への階段を確実に登っていますよ。
次の開発も、自信を持ってコードを書いていきましょう!
