「4-12」と「4 +(-12)」の違いは何ですか?[複製]

Nov 20 2020

次の式を比較してみます。

1) 
    mov al, 4
    mov bl, 12
    sub al, bl ; CF == 1

    0000 0100 (4)
   +
    1111 0100 (-12)
   = 
    1111 1000 (-8 == 248) 

2) 
    mov al, 4
    mov bl, -12
    add al, bl ; CF == 0

    0000 0100 (4)
   +
    1111 0100 (-12)
   = 
    1111 1000 (-8 == 248) 

結果は同じですが、キャリーフラグは同じではありません。どうして?2の補数の値を加算することによって実現される減算。

回答

4 fuz Nov 20 2020 at 22:56

減算は、x86での2の補数の加算と同じではありません。キャリーフラグが想定する値を理解するには、代わりに長い減算を実行する必要があります。

    0000 0100
-   0000 1100
-------------
  1 1111 1000

最後に借りが残っているのがわかりますか?この借用は、キャリーフラグを設定するものです(つまり、キャリーはボローに等しい)。

ARMのような他のいくつかのアーキテクチャは、実際に加算として減算を実装しますが、2の補数の加算としてではなく、1の補数の加算と追加のキャリーインとして実装します。これは、0を減算するときに重要です。

たとえば、あなたのメソッドは12 −0の結果を出します。

    0000 1100
+   0000 0000 (- 0000 0000 => + 0000 0000)
-------------
  0 0000 1100

明確なキャリー付き。しかし、実際に起こることは

    0000 1100
+   1111 1111 (- 0000 0000 => +1111 1111 + 1)
+           1
-------------
  1 0000 1100

キャリー付き。0との比較は正しく機能しないため、この詳細は重要です。このスキームでは、借用がない場合は常にキャリーが示されます(つまり、キャリーは借用を補完します)。

Intelの方法とARMの方法では、キャリーフラグが逆であることを除いて、実際には常に同じ結果が得られます。したがって、ARMがキャリーを設定するときはいつでも、Intelはそれをクリアし、その逆も同様です。

減算セマンティクスへの両方のアプローチはかなり一般的です。ARMアプローチは、キャ​​リーにまったく触れることなく減算に加算器を直接使用できるため、実装が少し簡単です。Intelのアプローチでは、減算を実行するときにキャリーインとキャリーアウトを補完する必要がありますが、そうするための追加のゲートは、物事の壮大なスキームでは実際には重要ではありません。一方、Intelのアプローチは、実行されている操作を長い減算として視覚化すると、キャリーフラグを借用も示すものとして考える方が理にかなっているため、プログラマーにとってより直感的です。