小于和大于如何在二进制逻辑级别上工作?
How does less than and greater than work on a logical level in binary?
我只通过比较位模式就明白了相等性是如何起作用的,但是如何编写自己的小于和大于运算符呢?机械地相互比较值的实际过程是什么?
给定域中所有数字的 O(1) 时间复杂度(保持位数不变)的一种方法是减去数字并检查符号位。即,假设您有 A
和 B
,那么
C = A - B
如果C
的符号位为1,则B
> A
。否则,A
>= B
.
我假设你只想知道逻辑是如何做的?并模仿那个?好吧:
首先,您必须讨论无符号大于或小于与有符号大于或小于,因为它们很重要。只需做三位数字就可以让生活更轻松,它都可以扩展到 N 位宽。
由于处理器文档通常指出比较指令将对两个操作数进行减法以生成标志,因此减法不保存答案只是修改标志。然后可以使用某些标志模式的跳转或分支。一些处理器不使用标志但有类似的解决方案,它们仍然使用标志的等价物但不将它们保存在任何地方。如果大于某种指令则比较和分支,而不是如果大于指令则单独比较和分支。
什么是逻辑减法?嗯,在小学时我们了解到
a - b = a + (-b).
我们还从入门编程中了解到 类 二进制补码中的负数表示取反并加一
a - b = a + (~b) + 1.
注意取反是指取反 ~b 在 C 中是指取反所有的位,也称为取反。
所以 7 - 5 是
1
111
+010
=====
很酷,我们可以使用进位作为 "plus one"。
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
所以这意味着进位告诉我们(无符号)小于 if 0。如果 if 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 是被比较的对象。
既然你已经看到了这一点,你可以在几秒钟内轻松地在一张纸上划掉上面的数学,以了解你需要的东西的顺序和使用的标志。或者用您正在使用的处理器做一个像这样的简单实验,然后查看标志以确定从哪个中减去哪个 and/or 他们是否反转进位并称之为借位。
我们可以从小学时用纸和铅笔做的事情中看出,加法归结为一次一列,你有一个进位加上两个操作数,你得到一个结果和一个进位。您可以将进位级联到下一列的进位,并对您可以存储的任意数量的位重复此操作。
Some/many 指令集使用标志(进位、零、有符号溢出和负数是进行大多数比较所需的集合)。您可以看到我希望您不需要汇编语言或带标志的指令集,您可以使用具有基本布尔和数学运算的编程语言自己完成此操作。
我刚刚在此编辑中敲出的未经测试的代码 window。
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)&1。然后,如果那是零,则它们相等,如果那是 1,则它们不相等。您可以使用等于比较。当它们不相等时,b 大于 a。反转你的操作数,你可以检查 b 小于 a.
您可以将上面的代码更改为仅在 n 和 v 相等时才打印出来。因此,如果您使用的是仅具有相等比较的处理器,您仍然可以使用真正的编程语言和比较来生存。
一些处理器手册可能会为您列出这一点。他们可能会说 n==v 表示一件事或不是 z 而 n!=v 表示另一件事(LT 与 GT)。但它可以简化,从小学开始,当你翻转 b < a 时,鳄鱼会吃掉更大的 a > b。因此,以一种方式喂养运算符,你会得到 a > b,以另一种方式喂养它们,你会得到 b < a.
Equals 只是一个直接的位比较,它通过一个单独的逻辑路径,而不是加法之外的东西。 N 从结果的 msbit 中获取。 C 和 V 不相加。
我只通过比较位模式就明白了相等性是如何起作用的,但是如何编写自己的小于和大于运算符呢?机械地相互比较值的实际过程是什么?
给定域中所有数字的 O(1) 时间复杂度(保持位数不变)的一种方法是减去数字并检查符号位。即,假设您有 A
和 B
,那么
C = A - B
如果C
的符号位为1,则B
> A
。否则,A
>= B
.
我假设你只想知道逻辑是如何做的?并模仿那个?好吧:
首先,您必须讨论无符号大于或小于与有符号大于或小于,因为它们很重要。只需做三位数字就可以让生活更轻松,它都可以扩展到 N 位宽。
由于处理器文档通常指出比较指令将对两个操作数进行减法以生成标志,因此减法不保存答案只是修改标志。然后可以使用某些标志模式的跳转或分支。一些处理器不使用标志但有类似的解决方案,它们仍然使用标志的等价物但不将它们保存在任何地方。如果大于某种指令则比较和分支,而不是如果大于指令则单独比较和分支。
什么是逻辑减法?嗯,在小学时我们了解到
a - b = a + (-b).
我们还从入门编程中了解到 类 二进制补码中的负数表示取反并加一
a - b = a + (~b) + 1.
注意取反是指取反 ~b 在 C 中是指取反所有的位,也称为取反。
所以 7 - 5 是
1
111
+010
=====
很酷,我们可以使用进位作为 "plus one"。
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
所以这意味着进位告诉我们(无符号)小于 if 0。如果 if 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 是被比较的对象。
既然你已经看到了这一点,你可以在几秒钟内轻松地在一张纸上划掉上面的数学,以了解你需要的东西的顺序和使用的标志。或者用您正在使用的处理器做一个像这样的简单实验,然后查看标志以确定从哪个中减去哪个 and/or 他们是否反转进位并称之为借位。
我们可以从小学时用纸和铅笔做的事情中看出,加法归结为一次一列,你有一个进位加上两个操作数,你得到一个结果和一个进位。您可以将进位级联到下一列的进位,并对您可以存储的任意数量的位重复此操作。
Some/many 指令集使用标志(进位、零、有符号溢出和负数是进行大多数比较所需的集合)。您可以看到我希望您不需要汇编语言或带标志的指令集,您可以使用具有基本布尔和数学运算的编程语言自己完成此操作。
我刚刚在此编辑中敲出的未经测试的代码 window。
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)&1。然后,如果那是零,则它们相等,如果那是 1,则它们不相等。您可以使用等于比较。当它们不相等时,b 大于 a。反转你的操作数,你可以检查 b 小于 a.
您可以将上面的代码更改为仅在 n 和 v 相等时才打印出来。因此,如果您使用的是仅具有相等比较的处理器,您仍然可以使用真正的编程语言和比较来生存。
一些处理器手册可能会为您列出这一点。他们可能会说 n==v 表示一件事或不是 z 而 n!=v 表示另一件事(LT 与 GT)。但它可以简化,从小学开始,当你翻转 b < a 时,鳄鱼会吃掉更大的 a > b。因此,以一种方式喂养运算符,你会得到 a > b,以另一种方式喂养它们,你会得到 b < a.
Equals 只是一个直接的位比较,它通过一个单独的逻辑路径,而不是加法之外的东西。 N 从结果的 msbit 中获取。 C 和 V 不相加。