IBM i のウンチクを語ろう:その106
- わかっているようでわかっていない文字コードの話 ~ EBCDICとは -
皆さん、こんにちは。私事で恐縮ですが、「文字コード」という言葉を聞くと、今を遡ること約四半世紀、家族を引き連れてIBM i 開発部門のあるアメリカはミネソタ州ロチェスターに長期駐在の機会を得たことを思い出します。日本語を始めとする、いわゆるダブルバイト文字コード事情に関するサポート役として、1年3か月ほど滞在しておりました。技術者ではない人間が場違いな組織に放り込まれたために、毎日がプレッシャーと冷や汗の連続でしたが、業務・個人生活の両面において良い経験だったことを思い出します。
さて、システムを利用する以上は常に何らかの形で文字コードに触れることになるのですが、日常的に使っている割には何となくしかわからない、というのが多くの方の印象なのではないでしょうか。「縁の下の力持ち」的なテクノロジーとして普段は意識されることはありませんが、英小文字が使えない、文字化けが発生した、といった事象・課題に直面すると、「IBM i だから、EBCDICだから」といった具合に製品の方に矛先が向けられがちです。IBM i が採用するEBCDICはユニークな文字コードであることは事実ではありますが、そこにはそれなりの必然性があったはずです。そのあたりを探ってみるのが今回の狙いです。
当コラムでは理解のし易さを優先しますので、ある程度の正確性を犠牲にする可能性があることを、念のためあらかじめお断りさせていただきます。文字コードの資料を見ると、CCSIDとはCSとCPとESの組み合わせになっていて、それぞれは何であって、あーだ・こーだ・・・といった具合に始まることが多いのですが、慣れていない方にとっては睡眠導入以外の効果はまずありません。ここでは面倒なことは極力回避しながら話を進めてまいります。
エビスディック、時にエビクディックとも発音されるEBCDIC(Extended Binary Coded Decimal Interchange Code)とはどのような経緯で誕生した文字コードなのか、といった点から話を始めたいと思います。拡張された(Extended)・2進化10進数(Binary Coded Decimal: 以下BCD)・データ交換用コード(Interchange Code)といった単語の羅列になっているので、2進化10進数(BCD)を拡張してデータ交換用に仕立てたコード、といった意味を持つことがわかります。
ではBCDとは何なのか。これそのものは文字コードではなく、今でも特に商用計算において利用されることがある数値表現です。システムが内部で取り扱うのは2進数というのは常識ではありますが、見かけ上は2進数でありながら実際には10進数表現になっているのが特徴です。2進数においては「0」と「1」の組み合わせだけで数値を表現するので、まともに使うと桁数ばかり増えてしまいます。そこで慣習的に4桁ずつをまとめて最小「0000」から最大「1111」までを、10進数の0から15まで、16進数の0からFまで(ただしA=10、B=11・・・)、に割り当てます。表現効率は良くなるのですが、2進数4桁対10進数1桁という関係が崩れるため煩雑になってしまいます。そこで少々もったいないことではありますが、一部を切り捨てて「0000」から「1001」までを、16進数の0から9まで、これをそのまま10進数の0から9までであると見なしてしまえばすっきりします。これがBCDです。蛇足ながら2進数と16進数は、算数・数学においては別物ですが、ITの世界では同義と思っていて良いようです。
冗長的表現であるにも関わらず、商用計算においてBCDが利用されるのは、計算時に誤差が生じないというメリットがあることによります。計算式を説明するのは当コラムの趣旨ではないので詳細は省きますが、10進小数値を2進数に変換すると、多くの場合は無限小数になるので、どこかで切り捨て誤差が生じます。これが積み重なると、例えば企業の経理情報を歪めないとも限りません。例えば0.1を10回足し算したらいくつになるかと問えば、小学生でも1と即答しますが、試しにPythonで単純な繰り返し加算のプログラムを組んで実行すると、その答えは「0.9999999999999999」と返ってきます。コンピュータも間違える(!?)のですねぇ。念のために実際に使用したPythonプログラムを文末に掲載しておきます。
IBMのコンピュータの歴史を紐解くと、1964年にIBMがSystem360を登場させる前までは、このBCDが内部の数値表現としての主流だったようです。かつてのコンピュータは今でいうところのプロセッサ部、制御装置、ストレージ、テープ、プリンタなどが別筐体という大掛かりなものであり、これら全てがBCD互換というわけです。当時の文字表現についての状況はわからないのですが、System360発表に際して取り扱うべきあらゆる数値と文字の表現方法を標準化しようという試みがなさました。このような場合の技術的選択肢は二つ考えられます。すなわち全く新規に文字と数字を包含する体系を定義するのか、既存の体系に対して上位互換を維持しながら文字も扱える体系に拡張するのか、です。
旧来システムをSystem360に置き換える際に、システムを構成する機器類全てを刷新しなければならないとしたら、お客様のコスト負担は大きなものになってしまいます。BCDに対応する周辺機器類はそのままでプロセッサ部のみをSystem360に置き換えられるようにできれば、お客様にとって有利であると同時に、IBMにとってもビジネスに役立ちます。そこでお客様の既存IT資産を保護するために、BCDを拡張して上位互換を維持する体系にしたから、EBCDICという名になっているのです。そして1988年に登場したAS/400も、当時のIBM製品間の互換性が維持されているというわけです。
EBCDICのどの文字コード表でも良いのですが、10進数が基本にあったという名残を部分的ながら見ることができます。例えばIBMのドキュメント「ホスト・コード・ページ解説書」のページ23にある、日本語環境で利用される「ホスト・コード・ページ 1027/1172 日本 (英数小文字) 拡張」の表を見てみましょう。表中のアルファベット大文字に着目してみると、「A」に16進数のC1(慣習として「0xC1」と表記します)を割り当てることから始まって「I」の0xC9まで進み、折り返して「J」の0xD1から「R」の0xD9まで、と規則的に並んでいます。下位桁のみですが、最大値は9であることというBCDの特徴を垣間見ることができます。一方でカタカナの方は、「ツ」の0x78、「テ」の0x8A、といった具合に、BCDが拡張された後の空きスペースに「何とか押し込まれている」らしいことがわかります。
さて、先に参照したホスト・コード・ページ解説書には、漢字とか平仮名がありませんでした。EBCDICは当初1バイトのみ、すなわち256種類の文字しか表現できない表であり、2バイトを用いて漢字や平仮名などの65,536文字をサポートするための表は、後から追加されたものです。当初のコンピュータは「非力」だったので、1文字を表現するのに2バイトを費やせるようになるには、時代を少しばかり下る必要があったようです。すなわち我々がダブルバイト文字コードと呼んでいるものは、1バイト表を基本にしながら、2バイト表を追加で組み合わせたセットになっているというわけです。そしてどちらの表を参照しているのかを明確にするために、デフォルトでは1バイト表を参照し、2バイト表を利用する際には切り替え宣言を行い、再度1バイト表に戻る場合は切り戻し宣言を行います。これがかの有名(?)なシフト・アウトとシフト・インです。
先に日本語と言いましたが、EBCDICにおける日本語は実は一つではなく、定義はされていても実際には利用されていないものを除くと実質的に3種類が存在します。別な言葉で表現すると、1バイト表と2バイト表の組み合わせが3セット存在するということです。さらに他の国語言語だけでなくShift-JISやユニコードなどといった文字コード体系を含めて、IBMはあらゆる文字のセットをCCSID(Coded Character Set IDentifier)と呼ばれる識別情報で管理しています。よく目にするCCSIDは、日本語EBCDICの5026・5035・1399、ユニコードだとUTF-8の1208とUTF-16の1200、そして何の定義にも該当しない、トランプのジョーカーのような位置付けにある65535といったところでしょうか。
3種類の日本語EBCDICの構成要素は、2種類の1バイト表と、2種類の2バイト表です。計算上は計4種類になるはずですが、うち1種類はサポートされていません。これらの内訳を少し覗いてみましょう。
1バイト表は先に参照したホスト・コード・ページ解説書で言うと、ページ15の「290日本 (英数カナ) 拡張」とページ23の「1027/1172 日本 (英数小文字) 拡張」の2種です。両者を比べると、英大文字に割り当てられている16進数値は共通ですが、「290」においてはカタカナに比較的規則正しく16進数値が割り当てられているのに対して、英小文字では割り当ての規則性が崩れています。かつての2バイト文字を処理できないコンピュータで、1バイトだけでも何とか日本語を表現しようという思惑から、カタカナを優先する代わりに英小文字を「犠牲」にした様子が見てとれます。「1027/1172」では逆に、英小文字に規則性が見られる一方で、カタカナでは規則性が崩れています。この英小文字に割り当てられた16進数値は、英語圏のコードページと共通です。サポートされる文字種類としては同じでも、カタカナ重視の「290」と、英小文字重視の「1027/1172」というわけです。このことは英語圏の製品を日本語環境に実装する際の、相性の良し悪しに現れます。きちんと実装できていればどちらでも良いはずなのですが、日本語化されたはずの製品を動作させてみた時に、「1027/1172」の方が安定性に優れるのが現実です。
2バイトの表についても見てみましょう。先のホスト・コード・ページ解説書には掲載されていませんが、日本語文字にはコードページ300という識別情報が割り当てられています。このコードページ300には二種類あって、JIS X0208(旧JIS)に準拠し、第一・第二水準漢字を含むものと、より新しいJIS X0213(新JIS)に準拠し、第一から第四水準漢字までとより多くの漢字を含むものとがあります。本来は別の概念を使うことで両者を識別するのですが、煩雑さを避けるために少々強引ながら、ここでは仮にコードページ「旧300」と「新300」と呼ぶことにしましょう。
これでようやくCCSIDを語る材料が出揃いました。代表的な日本語EBCDICのCCSIDは以下コードページの組み合わせになっています。
CCSID | 1バイトコード ページ | 2バイトコード ページ |
5026 | 290 | 旧300 |
5035 | 1027 | 旧300 |
1399 | 1027 | 新300 |
1バイトのコードページは英語圏の製品との相性の良さにおいて「1027」が優れると先に述べました。これに該当するCCSIDは5035か1399です。当コラムをお読みいただいている方の中には、何かの機能・製品を起動する際に、これらCCSIDを前提にするようガイドされたことのある方がいらっしゃるかもしれません。また、「新300」の方が扱える文字数は「旧300」よりも多く、例えばローマ数字のⅠ・Ⅴ・Ⅹや、マル付き数字の①・②・③、頻繁に使用されるために記号化された ㈱・℡・㍼・㍻ などを包含しています。旧来ならば外字またはユーザー定義文字として登録しなければならなかったものが、CCSID 1399では標準文字の中に組み入れられています。
老婆心ながら、CCSID 1399が優れるようだからと言って、現行システムの設定値をいきなり変更することはお勧めできません。データベース内の情報の持ち方や、他のユーザーとの整合性などを事前に確認しなければなりませんので。
文字コード関連のよく目にする用語に関わるお話だけで、想定以上の字数を費やしてしまいました。いずれエミュレータでは英小文字が取り扱えない事情を探ってみたいと思います。
ではまた
【 Python プログラム 】
Jupyter Notebook を利用して以下を入力・実行
sum = 0.0
for i in range(0, 10):
sum += 0.1
print(sum)