10進表示
目次
ひたすら引き算
2014.9.1 追記
こちらも投稿。重い割り算よりも「各桁ごとに引き算最大10回」の方が軽いだろう、と言うプログラムです。
LD DE,8086 ; 10 (11)
LD HL,-10000 ; 10 (11)
ADD HL, DE ; 11 (12)
JR C, L10000 ; 12 / 7 (13 / 8)
LD HL, -1000 ; 10 (11)
ADD HL, DE ; 11 (12)
EX DE, HL ; 4 (5)
LD DE, DECIMAL ; 10 (11)
JR C, L1000 ; 12 / 7 (13 / 8)
INC H ; 4 (5)
DEC H ; 4 (5)
JR NZ, L100 ; 12 / 7 (13 / 8)
LD A, L ; 4 (5)
CP 100 ; 7 (8)
JR NC, L100 ; 12 / 7 (13 / 8)
CP 10 ; 7 (8)
JR NC, L10 ; 12 / 7 (13 / 8)
ADD A, 30h ; 7 (8)
JP LAST ; 10 (11)
SUB16:
LD A, 30h-1 ; 7 (8)
SLOOP:
INC A ; 4 (5)
ADD HL, BC ; 11 (12)
JR C, SLOOP ; 12 / 7 (13 / 8)
SBC HL, BC ; 15 (17)
LD (DE), A ; 7 (8)
INC DE ; 6 (7)
RET ; 10 (11)
L10000:
EX DE, HL ; 4 (5)
LD DE, DECIMAL ; 10 (11)
LD BC, -10000 ; 10 (11)
CALL SUB16 ; 17 (18)
L1000:
LD BC, -1000 ; 10 (11)
CALL SUB16 ; 17 (18)
L100:
LD BC, -100 ; 10 (11)
CALL SUB16 ; 17 (18)
LD A, L ; 4 (5)
L10:
EX DE, HL ; 4 (5)
LD BC, (30h-1)*256 + 10 ; 10 (11)
LOOP:
INC B ; 4 (5)
SUB C ; 4 (5)
JR NC, LOOP ; 12 / 7 (13 / 8)
ADD A, 10 + 30h ; 7 (8)
LD (HL), B ; 7 (8)
INC HL ; 6 (7)
LAST:
LD (HL), A ; 7 (8)
INC HL ; 6 (7)
LD (HL), 00h ; 10 (11)
プログラムは大きく2つの部分に別れています。
あらかじめ、10進数で何桁の数字になるかを見積もる部分と、実際の10進化処理の部分です。
見積もりが終わったら、10進化処理の途中から始めることで、無駄を省くとともに左詰め処理を行っています。
10進数の各桁ごとに減算を行うため、16bit で減算を行い、引けた回数をメモリに文字で残すルーチンがあります。
SUB16 以下、RET までがそれです。
ただ、常に 16bit で計算を行っていると遅いため、8bit 演算で十分な桁(10の位のみ)は、LOOP 部分で処理を行っています。
まず、この重要ルーチンである SUB16 のクロック数を見積もりましょう。
SUB16 の前処理は 8 クロック、SLOOP のループ部分は 30 クロックです。
「引きすぎた」時に処理が終わりますが、この時はジャンプしないため 5クロック速くなります。
その後、引きすぎた数値を戻す処理と、引けた回数を結果としてメモリに書き込む処理、元のルーチンに復帰する処理が入ります。
これらの後処理が 43 クロック。
SUB16 では、その桁の数値を n とすると、
8 + 30*(n+1)-5 + 43 = 30*n + 76 クロックかかることになります。
では、全体の処理ですが…条件分岐だらけなので、ひたすら数えるしかないです。
条件は「10進での桁数」に依存します。
前処理は、以下のクロック数が必要です。
5桁 | 47クロック |
4桁 | 94クロック |
3桁 | 112 / 133クロック |
2桁 | 149クロック |
1桁 | 163クロック |
3桁の際に2つ書かれているのは、256以上か未満かで異なるためです。
本処理は、最低以下のクロック数が必要です。
5桁 | 191クロック |
4桁 | 146クロック |
3桁 | 117クロック |
2桁 | 83クロック |
1桁 | 26クロック |
最低、と言うのは、10の桁のループは最低回数(10の位が 0 となるとき)で、SUB16 内の時間は考慮していないためです。
10の桁のループは、数値が 1 増えるたびに、23クロック増加します。
さて、全体のクロック数を見積もりましょう。
例題では 8086 で4桁です。
上2桁は SUB 16 で処理されますが、その内部の時間は 8 と 0 なので、(30*8+76) + (30*0+76) = 392 クロック。
2の位は、8 なので、8*23 = 184 クロック増加します。
これに、前処理で 94 クロック、本処理で 146 を足します。
94 + 146 + 392 + 184 = 816
総計は、816 クロックです。
うわ、速い (^^;
いろいろ技巧を凝らしたよりも、シンプルに減算するだけの方が速かったか…