我看到平等可以通过比较位模式来实现,但是如何编写自己的小于和大于运算符?将价值机械地相互比较的实际过程是什么?
答案 0 :(得分:4)
我假设你想知道逻辑是怎么做的?模仿那个?那么这就是:
首先,你必须谈论无符号大于或小于vs签名大于vs小于因为它们重要。只需要三位数就可以让生活更轻松,它可以扩展到N位宽。
由于处理器文档通常会声明比较指令将减去两个操作数以生成标志,因此它是一个减法,不会保存答案只是修改标志。然后可以使用稍后在某些标志图案上跳转或分支。有些处理器不使用标志但有类似的解决方案,它们仍然使用等效的标志,但只是不保存它们。如果大于指令的种类,则比较和分支,而不是单独的比较和分支,如果大于指令。
什么是逻辑减法?在小学里,我们学到了
a - b = a + (-b).
我们也从介绍编程类中知道二进制补码中的负数意味着反转并添加一个
a - b = a + (~b) + 1.
注意补充意味着在C中反转〜b意味着反转所有的位,它也被称为取补码。
所以7 - 5是
1
111
+010
=====
非常酷我们可以使用随身携带作为"加上一个"。
1111
111
+010
=====
010
因此,执行集的答案是2。执行集合是一件好事,意味着我们没有借用。并非所有的处理器都做同样的事情,但到目前为止我们使用加法器但是反转第二个操作数并反转进位。如果我们反转执行,我们可以称之为借位,7 - 5不借用。同样,一些处理器体系结构不会反转并称之为借用,它们只是称之为执行。如果它们有标记,它仍会进入进位标志。
为什么这有关系?坚持下去。
让我们看看6-5 5-5和4-5,看看旗帜告诉我们的是什么。
1101
110
+010
=====
001
1111
101
+010
=====
000
0001
100
+010
=====
111
所以这意味着执行告诉我们(无符号)小于0.如果是1然后大于或等于。那是使用a - b,其中b是我们所比较的。因此,如果我们那么做b - a意味着我们可以得到(无符号)大于进位位。 5 - 4,5 - 5,5 - 6.我们已经知道5 - 5在执行集合中看起来像是零
1111
101
011
====
001
0011
101
001
====
111
是的,我们可以使用进位标志确定(无符号)大于或等于或小于或等于(无符号)。不小于大于或等于相同,反之亦然。您只需要在正确的位置获取要比较的操作数。我可能从每个比较指令向后做了这个,因为我认为它们减去了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;
然后你去,使用等于比较,将c与零进行比较。并且根据您的操作数顺序,它会告诉您(无符号)小于或大于。如果你想要超过8位,那么继续无限期地添加进位的级联。
签名号码......
添加(和减法)逻辑不知道签名和未签名操作之间的差异。重要的是要知道。这是两个补充的美。自己尝试编写一个程序,将位模式添加到一起并打印出位模式。将这些位模式输入和输出解释为全部无符号或全部已签名,并且您看到它有效(注意某些组合溢出并且结果被剪切)。
现在说减法比较的标志确实有所不同。我们从小学数学中知道我们在二进制中看到的那个或者其他什么。执行是无符号的无符号溢出。如果设置为溢出,我们有一个1我们不能适合我们的寄存器,所以结果太大我们失败。有符号溢出虽然是V位,它告诉我们msbit的进位IN和进位OUT是否相同。
现在让我们使用四位,因为我想。我们可以做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
现在负数-5 - -6,-5 - -5,-5 - -4
10111
1011
1010
=====
0110
c = 0, v = 1, n = 1
你知道吗,有一种更简单的方法。
#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);
}
和结果的子集
-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
我只会告诉你答案......你正在寻找n == v或者不是n == v。所以如果你计算n和v,那么x =(n + v)&amp; 1。然后,如果它是零,则它们是相等的,如果它是1,则它们不是。您可以使用等于比较。当它们不相等时,b大于a。反转你的操作数,你可以检查b小于a。
如果n和v相等,您可以将上面的代码更改为仅打印输出。因此,如果您使用的处理器只有相等的比较,您仍然可以使用真正的编程语言和比较。
某些处理器手册可能会为您提供此图表。他们可能会说n == v对于一件事情或者z和n!= v对另一件事(LT对GT)。但它可以简化,从小学开始鳄鱼吃大一个&gt; b当你翻转它时b&lt;一个。因此,以一种方式为运营商提供服务,您将得到一个&gt; b,以另一种方式喂他们b&lt;一个。
等于只是一个直接比较,通过一个单独的逻辑路径,而不是添加的东西。 N从结果的msbit中获取。 C和V脱离了添加。
答案 1 :(得分:0)
对于给定域中的所有数字(保持位数不变),O(1)的一种方法是减去数字并检查符号位。即,假设您有A
和B
,那么
C = A - B
如果C
的符号位为1,则B
&gt; A
。否则,A
&gt; = B
。