
前回はメモリオペランドを使った整数演算でした。今回は「剰余算」です。フツーのプログラミング言語の剰余演算子は整数に対するものが多いですが、8087系FPUの剰余の命令FPREMは浮動小数演算です。そのうえ、partial で exact だと。とってもメンドクセー雰囲気が漂ってくるんだが、どうなんだ?
※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら
※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。
FPREM
剰余算というと、「5÷2の商は2、余り1」なので「1」ね、と整数計算するのがフツーです。しかし、8087FPUのもつFPREM命令では、「5.1 ÷ 2.1の商は2、余り0.9」という塩梅で割る数も割られる数も、そして結果の剰余も皆、浮動小数デス(実際には2進で0.1とか0.9とか表現できないので例えっす。)そのうえこの命令 partial remainder の略だそうな。partialって何?
今回実験のプログラム
今回は以下の2つの数をFPREM命令で処理してみます。
-
- だいたい 6.28 くらいの割る数。泣く子も黙る 2π ね。
- だいたい63.355くらいの割られる数。10*2π + π/6ね。10周まわって6分のπっと。
まあ、スタックトップに置かれた割られる数(一般角)から360°以下のフツーの角度を求める感じ。
なお以下は「強力なx86用アセンブラNASM」用のソースです(MSのMASMともインテルASM86とも微妙に異なるけど、まあ分かるっしょ。)
%use fp segment code ..start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, stacktop test: mov bx, src1 mov si, src2 fld dword [bx] fldpi fmulp fld dword [si] loopFPREM: fprem fstsw ax sahf jp loopFPREM nop fin: mov ax, 0x4c00 int 0x21 resb 2048 segment data align=16 resb 1024 * 63 src1: dd 2.0 src2: dd 63.355 segment stack class=STACK align=16 resb 2048 stacktop: dw 1024 dup (0) stackend:
アセンブルして実行
MS-DOS互換で機能強化されているフリーなFreeDOS上、以下のステップで上記のアセンブラソース fprem.asm から実行可能なオブジェクトファイルを生成して実行することができます(nasmとwatcom Cがインストール済であること。)
なお、FreeDOS付属の「debugx」デバッガは、8087のレジスタ内容を浮動小数で見せてくれます
nasm -f obj -l fprem.lst fprem.asm wlink name fprem.exe format dos file fprem.obj debugx fprem.exe
さて、上の緑色の部分の前後でレジスタスタックがどうなっているのか眺めてみます。こんな感じ。
黄色枠のところの一般角 10*2π + π/6相当を、赤枠の2π相当で割った余りをもとめたら、緑枠の π/6 相当の数がもとまったみたい。余りっちゃ余りだけれども、メンドクセーな、おい。