2014.11.22

前へ
次へ
ホームページトップへ戻る

MYCPU80でCP/Mを!
超巨大基板の8080互換HCMOS・CPUでCP/Mを走らせてしまおうという、なんとも狂気なプロジェクトです!


[第69回]


●倍精度実数演算プログラムの組込み(2)

前にも書きましたように現在MYCPU80にZB3BASICを移植する作業を行なっております。
倍精度演算プログラムを除いては大体のところは出来上がったのですが、最後の倍精度演算プログラムのところで足踏みしております。
着手前から予想はしていたのですが、予想を上回る複雑さにこのところ作業が難航しています。
遅々としてはかどりません。
その間に急ぎの注文などがあったりしてなかなか続けて作業することもままなりません。
気にはしているのですけれどついHPの更新が後回しになってしまいます。
今回の記事もなんとか時間をみつけてもうこれで2日ほど書き足しながら時間切れでUPできずに来てしまいました。
ですので以下に書きました内容も2日ほど前の組込み状況についての説明になっています。
現在はもう少し進んでいるのですがそれについてはまた時間をみつけて整理しながら書くことにいたします。

最良近似式についても最後の詰めの部分の肝心の説明ができておりません。
そちらのほうも時間をみつけて書きたいと思っております。

昨日と今日と2日を費やしてやっと少し進展いたしました(上に書きましたように11月20日頃の状況です)。
まだ倍精度演算のほんの入口のところが出来ただけです。
倍精度変数に倍精度定数を代入する部分です。
たったそれだけのところが実に難物だったのです。
下は2日間の成果です。

>list
    10 A#= 123.45#
    20 B#= 123.45
    30 PRINT A#,B#
>run
 123.45       123.4499969482422

何をやっておるのかよくわからんぞお、と思われるかも知れません。
見ての通りの簡単なプログラムです。
倍精度変数A#には倍精度定数の123.45#を代入します。
倍精度変数や倍精度定数は末尾に#をつけて倍精度であることを示します。
倍精度変数B#には単精度定数の123.45を代入します。
十進数では倍精度でも単精度でも同じ123.45という定数なのですが、それを2進数に置き換えると、変換しきれない誤差が発生してしまいます。
このプログラムではその差が出ています。
A#を表示するときちんと123.45になりますが、B#のほうはご覧のように気持ちの悪い表示になってしまいます。
でもこれはバグではありません。
こうなるのが正しいのです。

下はプロクラムが格納されているメモリエリアをメモリダンプコマンドDMで16進数表示したものです。

>help
TEXT 8004-8062
ヘンスウ DFEB-DFFF
>dm 8000,806f
8000  4C F3 0B 3F 28 32 ED 4A-9A 32 4C F3 0B 3F 28 32  L..?(2.J.2L..?(2
8010  FC DF 41 00 00 0B 3F 28-0A 00 04 00 F4 DF 41 23  .゚A...?(.....゚A#
8020  00 0B 3F 28 0A 00 08 00-EC DF 42 23 00 0B 3F 28  ..?(.....゚B#..?(
8030  14 00 08 00 0A 00 0F F1-18 00 9A F9 33 33 33 33  ............3333
8040  33 73 7B 07 23 0D 12 14-00 0A F1 24 00 9A F8 33  3s{.#......$...3
8050  73 7B 07 0D 0D 1E 00 09-81 F1 18 00 2C F1 24 00  s{..........,.$.
8060  0D 0C 81 22 2A 2A 2A 22-0D 0A 2A 2A 22 0D 0A 0A  ..."***"..**"...
>

ZB3BASICはプログラムを入力する段階で中間コードに変換する作業が行なわれます。
そのときに実数や整数の定数も2進数に変換されてメモリに格納されます。
ですからただメモリを見ただけでは何が書いてあるのかわかりません。
でも私はZB3BASICを作った本人ですから、もちろん何が書いてあるか解読できます。

123.45#はアドレス803C〜8043 の 33 33 33 33 33 73 7B 07 です。
123.45はアドレス804F〜8052 の 33 73 7B 07 です。
[第67回]で説明しましたようにプログラムの都合で数の並びが逆順になっています。
これを普通の並び順で表示しますと下のようになります。

123.45#は指数が07で仮数は7B733333333333です。
123.45は指数が07で仮数は7B7333です。

単精度実数は2進数では23ビットの数として扱いますから倍精度実数に比べてうんと短くなります。
倍精度実数は2進数では55ビットの数として扱います。
どちらもZB3BASICでの場合です。
そういうビット長でなければならないというきまりや約束事があるわけではありません。
その長さの違いがもとの十進数にもどしたときどのように影響してくるのかということを、[第67回]と同じようにWindowsの電卓で計算して確かめてみることにします。

まず最初は123.45#のほうの計算です。

[表示]で[プログラマ]を選択し「16進」を指定します。
ここのところをうっかりして[第67回]では[関数電卓]と書いてしまいました(現在は訂正済みです)。

仮数部の7B733333333333を入力します。

「10進」に切り換えて、[M+]を押します。
これはWindows7の場合です。
Windows7ではこうしないと後の計算ができません。


[表示]で[普通の電卓]を指定したあと[MR]を押して、メモリした数値を表示させます。

/256/256/256/256/256/256=と入力します。
仮数部が55ビットなので本当はこのあと/128を入力するところなのですが、指数部に07があるので、それと相殺できますから、上の入力になります。

計算の結果もとの十進数123.45が表示されました。


なぜ256で繰り返し割るのでしょうか。
以下はその説明です。

最初に仮数部を16進(2進)→10進に変換した段階で10進数が求まっています。
しかしそれは仮数部の55ビットの数が整数(55ビットの下位に小数点がある)として換算した結果です。
実際には55ビツトの上位に小数点が置かれています。
ですのでその位置まで小数点を移動しないと正しい結果は求まりません。
2進数ですから2で割ることでnビット分上位に小数点を移動できます。
=256です。
/256/256/256/256/256/256/128=/2/2/2/2/2/2/2=/255
という計算のあと指数部の2を掛けることでもとの10進数が求まります。

それでは次は単精度の123.45のほうの計算をしてみます。

[表示]で[プログラマ]を選択し「16進」を指定します。
さきほどの「メモリ」がまだ残っていますから[MC](メモリクリア)を押してメモリをクリアしておきます。

仮数部の7B7333を入力します。

「10進」に切り換えて、[M+]を押します。


[表示]で[普通の電卓]を指定したあと[MR]を押して、メモリした数値を表示させます。

/256/256=と入力します。
仮数部が23ビットなので本当はこのあと/128を入力するところなのですが、指数部に07があるので、それと相殺できますから、上の入力になります。

計算の結果は?



誤差を含む数値が表示されました。
55ビットでも23ビットでも正しい数値ではなくて10進数から2進数に変換したときの誤差はあるのですが、それをもとの10進数に直して表示する場合には有効数字(倍精度実数では15〜16桁)の範囲内に収めるために下位桁を四捨五入しますから、結果として55ビットの場合にはもとの数と同じ123.45として表示されるのに対して、23ビットの場合には誤差が大きいため上のように表示されてしまいます。
なお23ビットの値でも倍精度実数ではなくて単精度の実数として扱う場合(たとえば単精度の変数に代入するような場合)には有効数字が6〜7桁のため、そこで四捨五入すると123.45と表示されます。

MYCPU80でCP/Mを![第69回]
2014.11.22upload

前へ
次へ
ホームページトップへ戻る