小于和大于在二进制逻辑级别上如何工作?

cra*_*fox 1 machine-code

我看到仅通过比较位模式如何实现平等,但是如何写一个小于或大于运算符的自有数据呢?机械地相互比较值的实际过程是什么?

old*_*mer 6

我假设您只是想知道它的逻辑性?模仿吗?好吧:

首先,您必须谈论无符号大于或小于vs有符号大于大于小于,因为它们很重要。只需做三个位数字即可使生活更轻松,所有数字都可扩展到N位宽。

由于处理器文档通常指出,比较指令将对两个操作数进行减法以生成标志,因此,减法运算符不会保存答案,只会修改标志。然后可以使用以后在某些标志模式上跳转或分支。一些处理器不使用标志,但是有类似的解决方案,它们仍然使用等效的标志,只是不将它们保存在任何地方。如果大于指令种类,则进行比较和分支;如果大于指令种类,则进行单独的比较和分支。

逻辑减法是什么?在小学时,我们了解到

a - b = a + (-b).  
Run Code Online (Sandbox Code Playgroud)

从介绍性编程类我们还知道,负的二进制补码意味着求反并加一个

a - b = a + (~b) + 1.
Run Code Online (Sandbox Code Playgroud)

注意,补码表示将C中的〜b取反意味着将所有位取反,这也称为取1补码。

所以7-5是

   1
 111
+010
=====
Run Code Online (Sandbox Code Playgroud)

很酷,我们可以将随身携带作为“加一”。

1111
 111
+010
=====
 010
Run Code Online (Sandbox Code Playgroud)

因此答案是2与进位集。进行安排是一件好事,这意味着我们没有借钱。并非所有处理器都执行相同的操作,但到目前为止,我们使用加法器进行减法运算,但将第二个操作数取反,然后将进位取反。如果我们将进位取反,可以称其为借位,则7-5不借位。再次,一些处理器体系结构不求反而是称其为借位,而只是称其为执行。如果它们有标志,它仍然进入进位标志。

为什么这有关系?等一下

让我们看一下6-5 5-5和4-5,看看标志告诉我们什么。

 1101
  110
 +010
=====
  001

 1111
  101
 +010
=====
  000

 0001
  100
 +010
=====
  111
Run Code Online (Sandbox Code Playgroud)

因此,这意味着进位告诉我们(无符号)小于0。如果1大于或等于。那是使用a-b,其中b是我们要比较的对象。因此,如果我们随后进行b-a运算,则意味着我们可以得到(无符号的)大于带进位的数字。5-4、5-5、5-6。我们已经知道5-5随进位集看起来像零一样

1111
 101
 011
====
 001

0011
 101
 001
==== 
 111
Run Code Online (Sandbox Code Playgroud)

是的,我们可以使用进位标志确定(无符号)大于或等于或(无符号)小于或等于。不小于等于等于或大于等于,反之亦然。您只需要在正确的位置获取要比较的操作数即可。我可能会从每个比较指令中向后进行此操作,因为我认为它们减去a-b,其中a是要与之比较的内容。

既然您已经看到了这一点,那么您可以在几秒钟内轻松地在纸上草拟上述数学知识,以了解您需要的顺序和要使用的标记。或使用您正在使用的处理器进行类似这样的简单实验,并查看标志以找出从中减去哪个和/或它们是否将进位进行反转并将其称为借位。

从小学时用纸和笔做起,我们可以看到加法一次降到一列,您有一个进位加两个操作数,就得到一个结果和一个进位。您可以将进位进行级联到下一列的进位中,并在可以承受的任何位数上重复此操作。

一些/许多指令集使用标志(进位,零,有符号溢出和负数是您进行大多数比较所需的标志)。您可以看到我希望您不需要汇编语言或带有标志的指令集,您可以自己使用具有基本布尔和数学运算的编程语言来完成此操作。

未经测试的代码我刚刚在此编辑窗口中遇到了麻烦。

unsigned char a;
unsigned char b;
unsigned char aa;
unsigned char bb;
unsigned char c;

aa = a&0xF;
bb = (~b)&0xF;
c = aa + bb + 1;
c >>=4;
a >>=4;
b >>=4;
aa = a&0xF;
bb = (~b)&0xF;
c = c + aa + bb;
c >>=4;
Run Code Online (Sandbox Code Playgroud)

然后,使用等于比较将c与零进行比较。并且根据您的操作数顺序,它告诉您(无符号)小于或大于。如果要执行8位以上的操作,请继续进行级联,并无限期地加上进位。

签名号码...

加(减)逻辑不知道有符号和无符号操作之间的差异。重要提示。这是二进制补全的美。自己尝试编写一个将位模式加在一起并打印出位模式的程序。将这些输入和输出的位模式解释为全部无符号或全部带符号,您会看到此方法有效(请注意某些组合溢出并且结果被裁剪)。

现在说这些标志的确会因减法比较而有所不同。我们从小学数学知道,在二进制中我们也可以携带一个或任何一个。进位是unsigned的unsigned溢出。如果设置为溢出,则我们的寄存器不能为1,因此结果太大,我们将失败。但是,有符号溢出是V位,它告诉我们msbit的进位和进位是否相同。

现在让我们使用四个位,因为我想要。我们可以执行5-4、5-5和5-6。这些是正数,因此我们已经看到了,但是我们没有看过V标志或N标志(也没有z标志)。N标志是结果的msbit,使用二进制补码表示为负,尽管有副作用,但不要与符号位混淆,它不是从数字中删除的单独符号位。

11111
 0101  
 1011  
=====
 0001
c = 1, v = 0, n = 0
11111
 0101
 1010
=====
 0000
c = 1, v = 0, n = 0
00011
 0101
 1001
=====
 1111
c = 0, v = 0, n = 1
Run Code Online (Sandbox Code Playgroud)

现在为负数-5--6,-5--5,-5--4

10111
 1011
 1010
=====
 0110
c = 0, v = 1, n = 1
Run Code Online (Sandbox Code Playgroud)

您知道吗,有一种更简单的方法。

#include <stdio.h>
int main ( void )
{
    unsigned int ra;
    unsigned int rb;
    unsigned int rc;
    unsigned int rd;
    unsigned int re;
    int a;
    int b;

    for(a=-5;a<=5;a++)
    {
        for(b=-5;b<=5;b++)
        {
            ra = a&0xF;
            rb = (-b)&0xF;
            rc = ra+rb;
            re = rc&8;
            re >>=3;
            rc >>=4;
            ra = a&0x7;
            rb = (-b)&0x7;
            rd = ra+rb;
            rd >>=3;
            rd += rc;
            rd &=1;
            printf("%+d vs %+d: c = %u, n = %u, v = %u\n",a,b,rc,re,rd);
        }
    }
    return(0);
}
Run Code Online (Sandbox Code Playgroud)

和部分结果

-5 vs -5: c = 1, n = 0, v = 0 
-5 vs -4: c = 0, n = 1, v = 0 

-4 vs -5: c = 1, n = 0, v = 0 
-4 vs -4: c = 1, n = 0, v = 0 
-4 vs -3: c = 0, n = 1, v = 0 

-3 vs -4: c = 1, n = 0, v = 0 
-3 vs -3: c = 1, n = 0, v = 0 
-3 vs -2: c = 0, n = 1, v = 0 

-2 vs -3: c = 1, n = 0, v = 0 
-2 vs -2: c = 1, n = 0, v = 0 
-2 vs -1: c = 0, n = 1, v = 0 

-1 vs -2: c = 1, n = 0, v = 0 
-1 vs -1: c = 1, n = 0, v = 0 
-1 vs +0: c = 0, n = 1, v = 0 

+0 vs -1: c = 0, n = 0, v = 0 
+0 vs +0: c = 0, n = 0, v = 0 
+0 vs +1: c = 0, n = 1, v = 0 

+1 vs +0: c = 0, n = 0, v = 0 
+1 vs +1: c = 1, n = 0, v = 0 
+1 vs +2: c = 0, n = 1, v = 0 

+3 vs +2: c = 1, n = 0, v = 0 
+3 vs +3: c = 1, n = 0, v = 0 
+3 vs +4: c = 0, n = 1, v = 0 
Run Code Online (Sandbox Code Playgroud)

我只想告诉你答案...您正在寻找n == v或不是n == v。因此,如果您计算n和v,则x =(n + v)&1。然后,如果该值为零,则它们相等;如果为1,则它们不相等。您可以使用等于比较。当它们不相等时,b大于a。反转您的操作数,您可以将b小于a。

您可以将上面的代码更改为仅在n和v相等时打印出来。因此,如果您使用的处理器仅包含等值比较,则仍然可以使用真实的编程语言和比较生存。

一些处理器手册可能为您列出了这一点。他们可能对某件事说n == v,对另一件事说不,而对另一件事说n!= v(LT与GT)。但是可以简化一下,从小学时起,当您将鳄鱼翻转为b <a时,它就会吃掉更大的a> b。因此,以一种方式喂食运算符,您会得到a> b,而以另一种方式喂食它们,则会得到b <a。

等于只是通过单独的逻辑路径进行的直接比较,而不是从加法中得出的结果。N从结果的msbit中获取。C和V不属于加法项。