二進化十進数 (BCD:Binary-coded decimal )の特殊系DPD(Densely packed decimal )、BID(Binary Integer Decimal)というものも存在するらしいですが、まずはBCDを

皆さ~ん、『 BCD:Binary-coded decimal 』 ってご存知ですか~?私は、初めて知りました。というわけで、今回は、BCDにトライ、Javaでね。

なんか、モヤッとした感じなので、お時間の在る方のみご照覧ください。

 

二進化十進数 (BCD:Binary-coded decimal )とは?

そも、「二進化十進数 (BCD:Binary-coded decimal )」って何ぞや?

例のごとく、Wikipediaさんにお聞きしてみましょう。

二進化十進数 (BCDBinary-coded decimal ) とは、コンピュータにおける数値の表現方式の一つで、十進法の1桁を、0から9までを表す二進法の4桁で表したものである。「二進化十進符号」などとも呼ばれる。3増し符号など同じ目的の他の方式や、より一般的に、十進3桁を10ビットで表現するDensely packed decimalなども含めることもある。

二進化十進表現 - Wikipedia

となっており、 

一般に二進法の4桁(ニブル)は、0から15までの整数を表すことができる。二進化十進法ではこのうちの最初の10個を有効な数値として扱う。

十進法 BCD表現
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001

二進化十進表現 - Wikipedia

⇧  十進数の 0~9 を表現しうる2進数が有効であると。 「1010」「1011」「1100」「1011」「1110」「1111」 は無効らしい。(10進数でいう、「10」「11」「12」「13」「14」「15」は、0~9 の数字の組み合わせで表現できるってことですかね)

 

イメージ的には、データも圧縮される感じですかね。

■ 0019830720って文字列をBCD変換する場合

f:id:ts0818:20190113110851p:plain

⇧  元のデータが10byteだとすると、5byteになるということですかね。

ちなみに、文字列のbyte数は、

qiita.com

⇧  上記サイト様によりますと、「"バイト数を知りたい文字列".getBytes("文字コード").length」で取得できるそうな。

 

www.system-brain.com

⇧  上記サイト様によりますと、10進数表記に関して厄介この上無さそうだと。

 

そして、「アンパック10進数」「パック10進数」なる用語とかも関係してくるのだろうか...

アンパック10進数unpacked BCD)とは、数値コンピュータ上で表現する手法の一つで、BCDをベースに定義されている。ゾーン10進数とも呼ぶ。パック10進数の登場により、「パック」ではないという意味で「アンパック」と呼ばれるようになったものと推測される。

10進数の1桁を、4桁のゾーンビットと4桁の数値ビットとに分けて表現する。数値の最後の桁はゾーンビットではなく正の数か負の数かを判断するための符号ビットが割り当てられる。なお、ゾーンビットは、EBCDICでは15、JIS8コードでは3を、符号ビットは、IBM互換のメインフレームでは正の数に12、負の数に13が割り当てられている。符号部についてはCOBOLベンダ各社で相違があるため、非常に互換性が低い。

アンパック10進数 - Wikipedia

パック10進数(packed BCD)とは、数値コンピュータ上で表現する手法の一つで、BCDをベースに定義されている。COBOLのUSAGE句ではCOMP-3形式として表されることが多い。当初はゾーン10進数で表現していたが、1桁につき1バイト(= 8ビット)を要し、場所をとる。そこで、無駄になっていたゾーンビットにも数値を割り当て、1バイトで2桁表現できるようにしたものがパック10進数である。

10進数の1桁を4桁の数値ビットで表現するが、正の数か負の数かを判断するため、符号ビットと呼ばれる4ビットを、数値の末尾に追加する。符号ビットは、正の数に12、負の数に13が割り当てられている。ただし、東芝オフィスコンピュータでは、符号ビットが特殊な値を採るので互換性の問題が発生する。

パック10進数 - Wikipedia

⇧  このへん、考慮しないといけないのかが分かりませんな... 

 

んでは、何故に、こんなBCD:Binary-coded decimal なんて面倒臭そうな形式を利用する必要があるのかと。

本来、コンピュータでは二進法で演算するのがコンピュータ資源(レジスタ、メモリ、計算量)の有効利用になる。それでも二進化十進数が有効な場合があるのは、二進法と十進法との変換を回避することに「社会的な価値」があるからである。

二進化十進表現 - Wikipedia

⇧ と、コンピュータは、2進数で処理したいから、10進数であれば、2進数に変換してから処理したいんだと。それが、ありのままの姿~見せるのよ~的なコンピュータの本来の姿であると。

だが、しかし

社会的な価値」の具体例として、小数の丸め処理が挙げられる。0.1 のような値は十進法では有限桁で表記可能だが、二進法では無限桁の循環小数となる。このため、一般的な二進法浮動小数点数演算では 0.1 の表現に丸め誤差があるので、それを繰り返し足し込むと誤差の影響が無視できなくなることがある。

二進化十進表現 - Wikipedia

⇧ 2進数ならではの弊害、計算するために、本来であれば無限桁の循環小数となってしまうものを、無理やり捻じ曲げて、だいたい0.1として扱うことによって計算に狂いが出てきてしまう、つまり、サバを読むことによる悲劇!

例えば以下の Java プログラムを実行すると、double 型を使って 0.1 を 10,000 回加えた結果は 1,000.0 ではなく 1,000.0000000001588 となることがわかる。

public static void main(String[] args) {
    double sum = 0.0;
    for (int i = 0; i < 10000; i++)
        sum += 0.1;
    System.out.println("sum = " + sum);
}

二進化十進表現 - Wikipedia

⇧ となってしまうらしい。

このような問題を避けるため、処理対象の値が十進の場合は、コンピュータ内の処理も二進化十進数で実装されることが少なくない。通貨を扱う事務アプリケーションなどが、しばしばこのケースに該当する。

二進化十進表現 - Wikipedia

⇧ 業務系アプリケーションでは、一般的らしいですね、知らなかったけど...。確かに、お金が絡むシステムでは、誤差は許されない気はします。

では、二進化十進数で、あらゆることに対応できるかというと、

なお、10.0 / 3.0 を計算する時には全く何も変わらない同様の問題を十進でも抱えている。このようなケースでは、二進化十進数でも正確に表す事はできない。

二進化十進表現 - Wikipedia

⇧ だ、駄目やん...

ビットコインなんかの仮想通貨とかのシステムではどうしてるんでしょうね

ただし、ビットコインのシステムの都合で、通常は546Satoshi以下の送金は承認されません。546Satoshi以下の数量を「ダスト(dust)」と言います。日本語で「ゴミ」です。

ビットコイン(1BTC)いくらから買える?最低取引単位「Satoshi」とは?

www.crypto-currencies.jp

⇧  上記サイト様によりますと、弱者切り捨て的な対処となる感じですかね。送金にかかるコスト的な問題なんでしょうかね...

脱線しましたが、演算(お金に関わってくる計算)が絡む場合は、何かしらの妥協点に持っていくしか無いんでしょうかね、現行の金融系のシステムってどうしてるんでしょうね。 

 

 

DPD(Densely packed decimal )、BID(Binary Integer Decimal)とは?

誤差の問題に関して、極力影響を少なくしようという動きは進んでいたらしく、

デ=ジュレ標準による標準化の要請が根強く存在していることもあって、浮動小数点表現の標準であるIEEE 754に2008年の改訂で十進浮動小数点が追加された。これには、より効率の良い Densely packed decimal(DPD)方式が採用された。

二進化十進表現 - Wikipedia

⇧  十進浮動小数点 という表現形式を実現する方式として採用されているのが、DPD(Densely packed decimal)というものらしい。

 

十進法の1桁を二進法4ビットで表現する伝統的な方法は、4ビットで表現可能な16個の状態の内10個のみしか使っておらず、無駄が多い。DPDは3桁(1000状態)を10ビット(1024状態の表現が可能)に押し込めるためより効率的であり、またこの圧縮にかかるハードウェアのコストはわずか2、3ゲートの遅延のみである

Densely packed decimal - Wikipedia

⇧  二進化十進数をパワーアップしたもの、それが、「DPD(Densely packed decimal)」というものらしい。 

 

ちなみに、浮動小数点数の計算の標準規格は、

IEEE 754(あいとりぷるいー754、IEEE Standard for Floating-Point Arithmetic: 直訳すると「浮動小数点数算術標準」)は、浮動小数点数の計算で最も広く採用されている標準規格であり、多くのプロセッサなどのハードウェア、またソフトウェア(コンピュータ・プログラム)に実装されている。多くのコンピュータ・プログラミング言語ないしその処理系でも、浮動小数点数処理の一部または全部が IEEE 754 になっている。

IEEE 754 - Wikipedia

⇧  「IEEE 754」というものらしく、

IEEE 754 が制定される前に成立したC言語などは、仕様上はIEEE 754 が必須となっていないものの、IEEE 754対応の演算命令を使える環境下では、それをそのまま利用して浮動小数点数演算を実装することが多い。一方で、JavaC#など、言語仕様として IEEE 754 を必須としているものもある。

IEEE 754 - Wikipedia

⇧  C言語に関しては、IEEE 754 が制定される前に成立していたらしい...

21世紀に入った後に改定され、2008年8月に制定された IEEE 754-2008 がある。これには、1985年の IEEE 754 制定当初の規格であるIEEE 754-1985、ならびに基数非依存の浮動小数点演算の標準規格 IEEE 854-1987 の両者がほぼすべて吸収されている。IEEE 754-2008 は正式に制定されるまでは、IEEE 754rと呼ばれた。

IEEE 754 - Wikipedia

⇧ 最新は、IEEE 754-2008 ってことなのかしら。

さらに、IEEE 754-2008 では、新たに二進形式1つ、十進形式2つも加わって、計5つの基本形式が存在する。IEEE 754-2008 に従う実装では、これらのうち少なくとも1つの基本形式を算術演算と情報交換のために実装しなければならないとされている。

IEEE 754 - Wikipedia

基本形式は、

  形式名
一般名
binary32 binary64 binary128 decimal64 decimal128
単精度 倍精度 四倍精度 十進倍精度 十進四倍精度
基数 (b) 2 2 2 10 10
桁・ビット数 (p) 23+1 52+1 112+1 16 34
指数最小値 (emin) −126 −1022 −16382 −383 −6143
指数最大値 (emax) +127 +1023 +16383 +384 +6144
十進換算 桁数 7.22 15.95 34.02 16 34
十進換算 emax 38.23 307.95 4931.77 384 6144

の5つになるようです。 

 

十進浮動小数点数はというと、 

十進浮動小数点数に対しては、32の倍数のビット数での交換形式が定義されている。

二進の場合と同様、符号、指数、仮数と符号化していくが、仮数部は十進の各桁をより詰め込めるよう、BCDなどではなく Densely Packed Decimal および Binary Integer Decimal英語版 を採用し、ビットの扱いが二進と比べ複雑になっている。

IEEE 754 - Wikipedia

BCDではなく、DPD(Densely packed decimal )、BID(Binary Integer Decimal)のどちらかで実装されるらしいですね。

 

BCD(Binary-coded decimal )形式への変換を試してみる

そんなこんなで、BCD形式への変換を試みてみますか。

Java Card Platform用のAPI というもので、BCDUtilってのが用意されているらしいんですが、

hexadecimal data からしBCDに変換できないらしい...

convertToBCD(byte[] hexArray, short bOff, short bLen, byte[] bcdArray, short outOff)
Converts the input hexadecimal data into BCD format.The output data is right justified. If the number of output BCD nibbles is odd, the first BCD nibble written is 0.

Java Card API, Classic Edition

⇧  hexadecimal data は、byte[] 配列のことらしい。16進数のbyte配列ってことなのかしら?

 

その前に、Java Card って何ぞ?

Wikipediaさんによりますと、

Java Card refers to a software technology that allows Java-based applications (applets) to be run securely on smart cards and similar small memory footprint devices.

Java Card is the tiniest of Java platforms targeted for embedded devices. Java Card gives the user the ability to program the devices and make them application specific.

It is widely used in SIM cards (used in GSM mobile phones) and ATM cards.

The first Java Card was introduced in 1996 by Schlumberger's card division which later merged with Gemplus to form Gemalto.

Java Card products are based on the Java Card Platform specifications developed by Sun Microsystems (later a subsidiary of Oracle Corporation).

Many Java card products also rely on the GlobalPlatform specifications for the secure management of applications on the card (download, installation, personalization, deletion).

The main design goals of the Java Card technology are portability and security.

Java Card - Wikipedia

カードに特化した内容 ですかね。

At the language level, Java Card is a precise subset of Java: all language constructs of Java Card exist in Java and behave identically. This goes to the point that as part of a standard build cycle, a Java Card program is compiled into a Java class file by a Java compiler; the class file is post-processed by tools specific to the Java Card platform.

However, many Java language features are not supported by Java Card (in particular types char, double, float and long; the transient qualifier; enums; arrays of more than one dimension; finalization; object cloning; threads). Further, some common features of Java are not provided at runtime by many actual smart cards (in particular type int, which is the default type of a Java expression; and garbage collection of objects).

Java Card - Wikipedia

⇧  Java Cardでは、Java の標準APIで使用できないものが出てきてしまうらしい。 

 

Oracle の説明によりますと、

Java Card technology is the leading open, interoperable platform for smart cards and secure tokens. Providing the basis for cross-platform and cross-vendor applet interoperability, the Java Card Platform Specification includes three documents:

  • The Java Card Virtual Machine Specification Provide the instruction set of the Java Card Virtual Machine (VM), the supported subset of the Java language, and the file formats used to install applets and libraries into Java Card technology-enabled devices.
  • The Java Card Runtime Environment Specification defines the necessary behavior of the runtime environment (RE) in any implementation of the Java Card technology. The RE includes the implementation of the Java Card Virtual Machine, the Java Card API classes, and runtime support services such as the selection and deselection of applets.
  • APIs for the Java Card Platform complements the Java Card RE Specification, and describes the application programming interface of the Java Card technology. It contains the class definitions required to support the Java Card VM and the Java Card RE.

Java Card Platform Specification 2.2.2

www.oracle.com

⇧  Wikipediaさんでも説明がありましたが、Java Card Virtual Machine(VM)、Java Card Runtime Environment(RM)などなど、仮想マシンやランタイム環境なんかを追加しないといけなさそうですかね...

一応、オープンって言ってくれているので、無料で利用できるということですかね。

 

IPA(Information-technology Promotion Agency, Japan[独立行政法人情報処理推進機構])の説明によると、

JavaCard Forumとは,スマートカード製造メーカである Schlumberger社とGemplus社が共同で結成したJavaCardのフォーラムである.

JavaCardはJavaCard APIによって具体化できるJavaベースの スマートカードであり,JavaCard 1.0が1996年に発行された. 実用レベルにバージョンアップされたJavaCard 2.0はSun Microsystems社が 1997年に発行した [IC97,JC97,JC].

JavaCard APIJava言語でかかれたアプリケーションを,スマートカードで 利用するためのAPIである. スマートカード上のプログラムはカードOS(COS)上で動作するが,COSに 互換性がないと同じプログラムを導入しても異なる機種上では 動作しなくなる.これがスマートカードの多目的利用を妨げる原因であった. そこで,Javaが動作するチップを使ってどの環境でも動作するように したカードがJavaCardである.

JavaCard API仕様に準拠したJavaCardアプレットはプラットフォームに 依存しないため,別のベンダーのカードでも動作させることが可能である. また,複数のアプリケーションを搭載することもできる.これらの アプリケーションは,カード発行後にもインストールすることができる.

JavaCardはISO 7816やEMVに準拠している.

II.2.2.2 カード用OS

www.ipa.go.jp

 となっていますね。

まぁ、今回は、Java Card は使わない感じで。そもそも、一般的なプロジェクトで利用されているのか謎ですしね...

それにしても、「Java SE」「Java EE」しか知らなかったけど、「Java ME」「Java Embedded」「Java Card」「Java TV」などなど、いろいろありますね。

 

だいぶ脱線してしまいましたが、問題は、1byteにどうやって2文字の数字(通常、数字の1文字が1byteであるため)を格納するかなんですが、

oshiete.goo.ne.jp

⇧  上記サイト様が詳しく解説してくれていました。 

 

で、一応、bitは格納できたっぽいんだけど、符号が、マイナスとか出てきてしまった。

package controller;

public class TestToBcd {
  private static final int BCD_BIT_SIZE = 4; 
  private static final String ZERO = "0";
  private static final int INPUT_MUST_SIZE_10 = 10;

  public static void main(String[] args) {

    String normalNumberStr = "0019830720"; // 10進数の数値の文字列
    // 10桁に満たない場合
    if(normalNumberStr.length() < INPUT_MUST_SIZE_10) {
      // 先頭を、"0"埋め
      for (int i = normalNumberStr.length(); i < INPUT_MUST_SIZE_10; i++) {
        normalNumberStr = ZERO + normalNumberStr;
      }
    }
    // 1桁の数値の文字配列に変換する
    char[] charNumberArray = normalNumberStr.toCharArray();
    byte[] bcd = getBcd(charNumberArray);
    for (byte b: bcd) {
      System.out.println(Integer.toBinaryString(b).toUpperCase()); // 2進数表記
            System.out.println(b);  // 10進数表記
    }
  }

  /**
   * 10進数の数値の文字を、BCDの文字列へ変換
   * @param charNumberArray 10進数の数値の文字配列
   * @return BCD(Binary-code decimal)の文字列
   */
  private static byte[] getBcd(char[] charNumberArray) {

    // BCDは、1/2に圧縮されるので、元の数値(10進数の数値の文字)の半分のbyte
    byte[] bcd = new byte[charNumberArray.length /2];

    String binaryNumber = null;
    int highBit = 0;  // 上位4bit
    int lowBit = 0;   // 下位4bit
    for (int i = 0; i < charNumberArray.length; i++) {
      // toStringの仕様で、0が削られてしまうので、
      if((binaryNumber = Integer.toString((charNumberArray[i] - '0'), 2)).length() < BCD_BIT_SIZE) {
        // 先頭を、"0"埋め
        for (int j = binaryNumber.length(); j < BCD_BIT_SIZE; j++) {
          binaryNumber = ZERO + binaryNumber;
        }
      }

      // 8bit(1byte)ずつ、処理
      // 上位、下位、上位、下位...の順番で、下位のときにだけ処理
      if(i % 2 != 0){
        // 下位bit
        lowBit = Integer.parseInt(("0000" + binaryNumber), 2);
        // 上位bitと下位bitの論理和
        bcd[(i -1) /2] = (byte)(highBit | lowBit);

      }

      // 上位bitを用意しておく
      highBit = Integer.parseInt((binaryNumber + "0000"), 2);
    }
    return bcd;
  }
}

f:id:ts0818:20190114180033p:plain

入力値を8bit(1byte)ずつ区切ってみると、出力結果と一致はするんだけども...

f:id:ts0818:20190114180747p:plain

 

BCDがよく分からんので、もう少し調査が必要ですかね、理解できる気がしませんが。
マイナスとか入ってきて良いのかも分からんですしね...

結局、本棚の組み立てができなかった...徒労感のみが残ったそんな1日。


山善 本棚 コミック収納ラック 4段 幅60×奥行17×高さ89cm 耐荷重50kg ホワイト CMCR-9060(WH)

 

今回はこのへんで。