はじめに
プログラミングでよく遭遇する浮動小数点数の精度問題。
0.1 + 0.2 が 0.3 にならない、という有名な問題をご存知でしょうか?
今回は、COBOLがこの問題をどう扱うのか、JavaScript、Pythonと比較してみました。
※昔は基本情報の午後でCOBOLを選べた時代があり、筆者は高校1年生の頃に学校の方針でCOBOLで基本情報を受けさせられました。
ちなみに、最近もこういう記事がありました。
SCSKがCOBOL支援の新会社を設立。COBOLは「古い言語」と言われていますが、金融機関などではまだ多くのシステムが稼働し続けているようです。
浮動小数点の精度問題とは?
多くの言語では、小数は IEEE 754 浮動小数点数で表現されます。
しかし、0.1 や 0.2 は2進数では正確に表現できないため、誤差が発生します。
サンプルコード
JavaScript
// 基本的な計算
console.log(0.1 + 0.2); // 期待: 0.3
// 繰り返し計算での誤差の蓄積
let sum = 0;
for (let i = 0; i < 10; i++) {
sum += 0.1;
}
console.log(sum); // 期待: 1.0
// 金額計算での問題例
let price = 0.10; // 10円
let quantity = 3;
let total = price * quantity;
console.log(total); // 期待: 0.30
実行結果:
0.30000000000000004
0.9999999999999999
0.30000000000000004
Python
# 基本的な計算
print(0.1 + 0.2) # 期待: 0.3
# 繰り返し計算での誤差の蓄積
sum_val = 0
for i in range(10):
sum_val += 0.1
print(sum_val) # 期待: 1.0
# 金額計算での問題例
price = 0.10 # 10円
quantity = 3
total = price * quantity
print(total) # 期待: 0.30
# Decimalモジュールを使った正確な計算
from decimal import Decimal
print(Decimal('0.1') + Decimal('0.2')) # 正確に 0.3
実行結果:
0.30000000000000004
0.9999999999999999
0.30000000000000004
0.3
COBOL
IDENTIFICATION DIVISION.
PROGRAM-ID. DECIMAL-PRECISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NUM1 PIC 9V9 VALUE 0.1.
01 WS-NUM2 PIC 9V9 VALUE 0.2.
01 WS-RESULT PIC 9V9.
01 WS-SUM PIC 9V9 VALUE 0.
01 WS-COUNTER PIC 99.
01 WS-PRICE PIC 9V99 VALUE 0.10.
01 WS-QUANTITY PIC 9 VALUE 3.
01 WS-TOTAL PIC 9V99.
PROCEDURE DIVISION.
*> 基本的な計算
COMPUTE WS-RESULT = WS-NUM1 + WS-NUM2.
DISPLAY "0.1 + 0.2 = " WS-RESULT.
*> 繰り返し計算
PERFORM VARYING WS-COUNTER FROM 1 BY 1
UNTIL WS-COUNTER > 10
COMPUTE WS-SUM = WS-SUM + 0.1
END-PERFORM.
DISPLAY "0.1 x 10回 = " WS-SUM.
*> 金額計算
COMPUTE WS-TOTAL = WS-PRICE * WS-QUANTITY.
DISPLAY "0.10 x 3 = " WS-TOTAL.
STOP RUN.
実行結果:
0.1 + 0.2 = 0.3
0.1 x 10回 = 1.0
0.10 x 3 = 0.30
比較結果まとめ
| テスト | JavaScript | Python (float) | Python (Decimal) | COBOL |
|---|---|---|---|---|
| 0.1 + 0.2 | 0.30000000000000004 | 0.30000000000000004 | 0.3 | 0.3 |
| 0.1を10回加算 | 0.9999999999999999 | 0.9999999999999999 | 1.0 | 1.0 |
| 0.10 × 3 | 0.30000000000000004 | 0.30000000000000004 | 0.3 | 0.30 |
なぜCOBOLは正確なのか?
固定小数点演算(DECIMAL型)
COBOLは内部的に 10進数の固定小数点演算 を使用します。
01 WS-AMOUNT PIC 9(5)V99.
この PIC 9(5)V99 は:
- 整数部5桁
- 小数部2桁
- 10進数で正確に 格納
つまり、0.1や0.2を正確に表現できます。
他の言語の対処法
JavaScript:
// ライブラリを使用
const Decimal = require('decimal.js');
console.log(new Decimal(0.1).plus(0.2).toString()); // "0.3"
Python:
from decimal import Decimal
print(Decimal('0.1') + Decimal('0.2')) # 0.3
COBOLが使われている場面
金融システム
*> 銀行の利息計算
01 WS-PRINCIPAL PIC 9(10)V99. *> 元金
01 WS-RATE PIC 9V9(4). *> 金利
01 WS-INTEREST PIC 9(10)V99. *> 利息
COMPUTE WS-INTEREST = WS-PRINCIPAL * WS-RATE.
1円単位の誤差も許されない金融計算では、こうした特性からCOBOLが使われているケースがあるようです。
会計システム
- 消費税計算
- 売上集計
- 給与計算
COBOLの現状と課題
今も残るCOBOLシステム
上記した記事のように2024年6月、SCSKがプログラミング言語「COBOL」の利用企業を支援する新会社「COBOL PARK」を設立したというニュースがありました(日本経済新聞)。
こうした動きの背景には、COBOLで構築された基幹システムが、多くの金融機関で今も稼働し続けている現状があると考えられます。
なぜ置き換えが進まないのか?
- 安定性の高さ: メインフレームで動作するCOBOLシステムは、数十年間安定稼働している実績があるとされています
- 大量データ処理: 金融機関の膨大なトランザクション処理に適していると考えられています
- 置き換えコスト: システム全体を刷新するには莫大なコストとリスクが伴うと言われています
直面する課題
一方で、以下のような課題も指摘されています:
- 人材不足: COBOLを扱える技術者が減少している
- 市場縮小: クラウド化の進展に伴い、メインフレーム市場が縮小傾向
- 老朽化対応: 多くの企業が「脱COBOL」を検討している
このような背景から、COBOL支援事業が立ち上がるなど、レガシーシステムの維持と移行が大きな課題となっています。
まとめ
| 項目 | COBOL | JavaScript/Python |
|---|---|---|
| 小数点の精度 | ◎ 正確 | △ 誤差あり(対策必要) |
| 金融計算 | ◎ 適している | △ ライブラリ必要 |
| 学習コスト | △ 独特の構文 | ◎ モダンで読みやすい |
| 開発速度 | △ 冗長 | ◎ 簡潔 |
COBOLの特徴:
- デフォルトで正確な10進数演算
- 金融・会計システムでの実績
- 誤差の心配が少ない
使い分けの例:
- 金融・会計システム → COBOL(または Decimal ライブラリ)
- 科学技術計算 → 浮動小数点でOK
- Web開発 → Decimal.js などのライブラリで対応
JavaScriptやPythonでも、ライブラリを使えば厳密な小数の計算はできます。しかしCOBOLはデフォルトで正しく計算ができるため、少しの差が大きな事故につながる金融系ではヒューマンエラーを防ぐ仕組みとして機能していると言えます。
「古い言語」と思われがちなCOBOLですが、金融計算の精度という観点では、現代でも一定の価値があると言えそうです。
参考
- IEEE 754 浮動小数点数の仕組み
- 0.30000000000000004.com
- COBOL支援の新会社設立 - 日本経済新聞
- COBOLのPICTURE句仕様