LoginSignup
2
1

x87 による浮動小数点数の比較

Posted at

この記事のねらい

  • x87 で浮動小数点数の大小を比較する命令がわかる
  • 比較結果を x86 で取得・解釈する方法がわかる

浮動小数点数を比較する命令

x87 では、「ST(0) (スタックトップ) と〇〇を比較する」命令がいくつかある。

FCOM 命令および FCOMP 命令は、比較対象としてメモリ上または x87 のレジスタスタック上の浮動小数点数を用いる。
FICOM 命令および FICOMP 命令は、比較対象としてメモリ上の整数を用いる。

FCOMPP 命令は、比較対象として x87 のレジスタスタック上のトップの次の値 ST(1) を用いる。
FTST 命令は、比較対象として固定値のゼロ (0.0) を用いる。

FCOM 命令・FICOM 命令・FTST 命令は、比較後もレジスタスタック上の値を変更しない。
FCOMP 命令・FICOMP 命令は、比較後、レジスタスタックから値1個をポップする。(ST(0) を除去する)
FCOMPP 命令は、比較後、レジスタスタックから値2個をポップする。(ST(0) および ST(1) を除去する)

命令 比較対象 スタックからのポップ
FCOM メモリ上の 32bit 浮動小数点数
メモリ上の 64bit 浮動小数点数
スタック上の値 ST(i)
しない
FCOMP メモリ上の 32bit 浮動小数点数
メモリ上の 64bit 浮動小数点数
スタック上の値 ST(i)
1個する
FCOMPP スタック上の次の値 ST(1) 2個する
FICOM メモリ上の 16bit 整数
メモリ上の 32bit 整数
しない
FICOMP メモリ上の 16bit 整数
メモリ上の 32bit 整数
1個する
FTST ゼロ (0.0) しない

これらの命令は、比較結果に応じて、x87 のステータスワードのうち C0、C2、C3 を以下のように設定する。

結果 C0 C2 C3
ST(0) > 比較対象 0 0 0
ST(0) = 比較対象 0 0 1
ST(0) < 比較対象 1 0 0
比較不能 1 1 1

「比較不能」は、ST(0) または比較対象のいずれか、または両方が NaN または未対応のフォーマットの場合である。
このとき、IE (invalid operation) 例外が発生し、この例外がマスクされていない場合は割り込み要求が行われる。

C1 は、8087 のデータシートでは「変化なし」となっているが、最近のCPUでは「0にする」となっているようである。

比較結果の取得・解釈

FNSTSW 命令により、2バイトのステータスワードをメモリに読み込むことができる。
また、80286 以降では、ステータスワードを直接 AX レジスタに読み込むこともできる。

FSTSW 命令は、FNSTSW 命令の直前に FWAIT 命令を実行する。

ステータスワードの値を AX レジスタに格納し、さらに SAHF 命令を用いると、以下のように x86 のフラグレジスタが x87 の C0、C2、C3 に従って設定される。

x87 ステータスワード x86 フラグレジスタ
C0 CF (キャリーフラグ)
C2 PF (パリティフラグ)
C3 ZF (ゼロフラグ)

C0、C2、C3 はステータスワードの上位に配置されているため、フラグレジスタの下位を AH レジスタ (AX レジスタの上位) に従って設定する SAHF 命令によりフラグレジスタに反映できる。
ステータスワード全体を AX レジスタに格納せず、上位だけを AH レジスタにロードして SAHF 命令を用いてもよさそうである。

C1 もステータスワードの上位に配置されているが、予約されているビットに対応するため、フラグレジスタには反映されない。

POPF 命令によりフラグレジスタ全体の値を設定するには、ステータスワードの上位と下位を入れ替える、IF (割り込みフラグ) などの重要だが計算と関係ないフラグを適切に設定する、といった手間がかかる。
SAHF 命令により計算結果を表すフラグレジスタの下位のみを設定したほうが簡単だろう。

これを先ほどの比較結果とステータスワードの対応関係と比較すると、Jcc 命令 を用いて以下のように判定することができることがわかる。

命令 判定 ジャンプする条件 比較不能時ジャンプ
JP PF=1 (比較不能) する
JNP PF=0 (比較不能でない) しない
JB / JNAE CF=1 ST(0) < 比較対象 する
JBE / JNA CF=1 or ZF=1 ST(0) ≦ 比較対象 する
JE / JZ ZF=1 ST(0) = 比較対象 する
JNE / JNZ ZF=0 ST(0) ≠ 比較対象 しない
JAE / JNB CF=0 ST(0) ≧ 比較対象 しない
JA / JNBE CF=0 and ZF=0 ST(0) > 比較対象 しない

また、TEST 命令 (ビット AND 演算の結果に基づいてフラグを設定する) などを用い、取得したステータスワードの上位の値を直接チェックすることでも、判定が可能である。
上記の表と同様の判定は、TEST 命令と JZ/JNZ 命令を用いて以下の方法で可能である。

ジャンプする条件 判定 AND を取る値 分岐命令
比較不能 PF=1 0x04 JNZ
比較不能でない PF=0 0x04 JZ
ST(0) < 比較対象 or 比較不能 CF=1 0x01 JNZ
ST(0) ≦ 比較対象 or 比較不能 CF=1 or ZF=1 0x41 JNZ
ST(0) = 比較対象 or 比較不能 ZF=1 0x40 JNZ
ST(0) ≠ 比較対象 ZF=0 0x40 JZ
ST(0) ≧ 比較対象 CF=0 0x01 JZ
ST(0) > 比較対象 CF=0 and ZF=0 0x41 JZ

まとめ

  • x87 では、スタックトップの値 ST(0) と比較対象の大小関係を比較する命令がある
  • 比較結果は x87 のステータスワードに反映される
  • 比較結果が入ったステータスワードの上位を SAHF 命令でフラグレジスタに反映すると、JA 命令などの条件分岐命令で比較結果の解釈ができる
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1